【问题标题】:Pointer moving inside string [closed]指针在字符串内移动[关闭]
【发布时间】:2018-04-18 15:08:56
【问题描述】:

我正在研究这段代码,但我不明白指针是如何在 buffer 内部移动的

...

  while(fgets(buffer,buf_size,fp) != NULL){  
    read_line_p = malloc((strlen(buffer)+1)*sizeof(char));   
    strcpy(read_line_p,buffer);   
    char *string_field_in_read_line_p = strtok(read_line_p,",");
    char *integer_field_in_read_line_p = strtok(NULL,",");  

    char *string_field_1 = malloc((strlen(string_field_in_read_line_p)+1)*sizeof(char));
    char *string_field_2 = malloc((strlen(string_field_in_read_line_p)+1)*sizeof(char));  

    strcpy(string_field_1,string_field_in_read_line_p);
    strcpy(string_field_2,string_field_in_read_line_p);    
    int integer_field = atoi(integer_field_in_read_line_p);  

    struct record *record_p = malloc(sizeof(struct record));   
    record_p->string_field = string_field_1;
    record_p->integer_field = integer_field;

    ordered_array_add(array, (void*)record_p);

    free(read_line_p);
  }

...

源代码是这样做的:

.csv 文件中读取数百万条由字符串和整数组成的记录,这些记录由, 分隔,并且每条记录都放在不同的行上;每条记录都作为一个单独的元素添加到我们必须订购的通用数组中。泛型数组由

表示
typedef struct {
  void** array; 
  unsigned long el_num; //index
  unsigned long array_capacity; //length
  int (*precedes)(void*,void*); //precedence relation (name of a function in main which denota which one field we're comparing)
}OrderedArray;

在这个结构体内部,我们有一个前置函数,它告诉我们是否必须按字符串字段或整数字段对数组进行排序。

我们的 csv 文件中的记录示例

第一个单词,10

第二个字,9

第三个字,8 ecc..

所以在每次执行ordered_array_add 时,我们都会在数组中插入一个新元素。

关注ordered_array_add

void ordered_array_add(OrderedArray *ordered_array, void* element){
  if(element == NULL){
    fprintf(stderr,"add_ordered_array_element: element parameter cannot be NULL");
    exit(EXIT_FAILURE);
  }

  if(ordered_array->el_num >= ordered_array->array_capacity){
    ordered_array->array = realloc(ordered_array->array,2*(ordered_array->array_capacity)*sizeof(void*));
    if(ordered_array->array == NULL){
      fprintf(stderr,"ordered_array_add: unable to reallocate memory to host the new element");
      exit(EXIT_FAILURE);
    }
    ordered_array->array_capacity = 2*ordered_array->array_capacity;
  }

  unsigned long index = get_index_to_insert(ordered_array, element);

  insert_element(ordered_array,element,index);

  (ordered_array->el_num)++;

}

我不明白第一个循环如何扫描字符串 buffer,因为我在提到的循环中看不到任何索引。

我写了一个与我发布的第一个循环类似的代码,问题是它在从buffer 读取第一个单词后停止,而我正在研究的代码成功读取整个字符串

while(fgets(buffer,buf_size,fp) != NULL) {
char *word = strtok(buffer, " ,.:");

    add(words_to_correct, word);
    words_to_correct->el_num = words_to_correct->el_num+1;
    printf("%s\n", word);

}

【问题讨论】:

  • 我正在研究这段代码,但我不明白指针是如何在缓冲区内移动的 嗯,首先这是非常糟糕的代码。 sizeof(char) 根据定义是一个,因此可以删除它的每次使用。除了一个strcpy() 调用之外,其他所有调用都是不需要的。编写该代码的人需要介绍strdup()。最后,你的问题到底是什么?你指的是什么“指针”?
  • 我正在学习的代码是由我的 UNI 教授完成的......无论如何我会编辑问题以便更好地理解

标签: c string strtok


【解决方案1】:

您的整个第一个循环可以重写为:

while(fgets(buffer,buf_size,fp) != NULL){  
    // note how sizeof() is used - that way if the type of
    // record_p changes, no changes to this code are needed
    struct record *record_p = malloc(sizeof(*record_p));   

    // no need at all for temporary copies of the strings
    record_p->string_field = strdup(strtok(buffer,","));
    record_p->integer_field = atoi(strtok(NULL,","));

    ordered_array_add(array, (void*)record_p);
  }

没有必要多次调用malloc()strcpy() - 可以用strdup() 替换这对 - 这是POSIX-standardsupported on Windows,所以它非常广泛可用。

当然,该代码需要错误检查和it shouldn't be using atoi() at all,但正如此处发布的那样,它将复制您的原始功能。

还有一个额外的好处,就是您可以真正了解正在发生的事情。

你的代码

while(fgets(buffer,buf_size,fp) != NULL) {
char *word = strtok(buffer, " ,.:");

    add(words_to_correct, word);
    words_to_correct->el_num = words_to_correct->el_num+1;
    printf("%s\n", word);

}

只会处理每行中的第一个单词——你需要一直调用strtok()直到它返回NULL,因为strtok() only returns one token

while(fgets(buffer,buf_size,fp) != NULL) {
    // trick to keep loop simple - start by using
    // buffer on the first loop iteration, then
    // set tmp to NULL so later iterations works too
    char *tmp = buffer;
    // loop until strtok() returns null
    for ( ;; )
    {
        // note use of tmp here
        char *word = strtok(tmp, " ,.:");

        // line is fully parsed - break this loop
        // and get the next line to parse
        if (word == NULL)
        {
            break;
        }

        // now set tmp to NULL so next strtok()
        // gets a NULL first parameter
        tmp = NULL;

        add(words_to_correct, word);
        words_to_correct->el_num = words_to_correct->el_num+1;
        printf("%s\n", word);
    }

}

还请注意,我是在分散内容,而不是试图在每一行中填充尽可能多的代码。这通常更容易阅读。

【讨论】:

  • 因此,如果我尝试扫描的字符串都在一行上(我的意思是没有'\n'),每次我进入循环时,我只会扫描第一个字?
  • @ZenoRaiser 是的。在您的原始代码中,您只会得到每行的第一个单词。
猜你喜欢
  • 2018-06-11
  • 2017-05-03
  • 2014-02-16
  • 1970-01-01
  • 2014-06-19
  • 2013-04-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多