在循环中将char指针分配给结构时遇到问题

时间:2012-02-03 02:31:41

标签: c pointers struct while-loop

考虑到我读取的每一行的内容,我正在尝试遍历流的内容以动态生成列表中的节点。我有一个我在下面定义的结构:

struct info {
     char *mystring;
     char *file;
     int line_no;
     struct info *next;
};

我使用这个循环遍历流:

while(1) {      
      char t [KMAX];
      char* file;
      char* line_no;
      char* text;
      if (fgets(t, KMAX, file_pipe) != NULL) {
           file = strtok (t, delimiter);
           line_no = strtok(NULL, delimiter);
           int line = atoi(line_no);
           text = strtok(NULL, delimiter);
           add(&head, text, line, file);
      }

我知道变量正确传递给我的add函数,因为我每次打印它们都可以验证它。但是,当我尝试打印列表时出现问题。它只打印文本和文件名的最后一行,但整数值会相应更改。我的猜测是,它与每次在同一块内存中被重新创建的数组有关,所以指针每次都会改变。

我不确定解决此问题的正确方法是什么。我是否以某种方式修改了我的while循环并以不同的方式使用了char指针,或者我应该以某种方式更改我的结构来保存变量,而不仅仅是使用指针?我将不胜感激任何反馈!

编辑:添加了更多代码

 void add(struct info **x, char * text, int line_no, char * file) {
 struct info* current = *x;
 struct info* newInfo;


 newInfo = malloc(sizeof(struct info));
 (*newInfo).next = NULL;
 (*newInfo).grepstring = text;
 (*newInfo).line_no = line_no;
 (*newInfo).file = file;

 if (current == NULL) { //indicates the head is null, special case
      *x = newInfo;
 } else {
      //get to the end of the list
      while ((*current).next != NULL) {
           current = (*current).next;
      }
      //apends node to the end of the list
      (*current).next = newInfo;
 }

}

3 个答案:

答案 0 :(得分:2)

当您说char* text时,您正在做的是在堆栈上分配char* strtok没有将它指向一些新分配的内存,它将它指向堆栈分配的t空间。

超出范围时,此内存将丢失,这发生在while循环的每次迭代的底部。对其地址的任何引用都可能指向正确的内容,或者没有任何内容,或者在该点之后指向其他一些随机值 - 它们展示的行为是未定义的。

您需要每个struct info的内容才能在循环中存活(并且可能在可预见的未来继续存在)。为此,您必须进行堆分配。在C中,这是通过malloc函数完成的。

add方法中,请说:

char* text_copy = malloc(strlen(text)+1); // +1 for trailing NUL character
strcpy(text_copy, text);

这将在堆上创建新内存,其内容与原始文本相同。

您应该对struct info的所有内容执行此操作,因为此时它们都是指向堆栈分配的t缓冲区的指针。

完成后你必须再次free内存,但它会持续到那时。

答案 1 :(得分:1)

您没有向我们展示add()的作用,但显然它只是将strtok()的结果直接分配给结构的成员。您不能这样做 - 在将strdup()分配给结构成员之前,使用malloc()(或strcpy()char *)复制每个strtok()。指针char将点返回到{{1}}缓冲区,并且每次新循环迭代它们都会变为无效。

答案 2 :(得分:1)

您创建的唯一用于保存字符串的缓冲区是t,您在while循环的顶部创建了它:

char t [KMAX];

因此,所有char *指针都将指向某个缓冲区,但这是一个问题,因为每次调用fgets时都会更改内容缓冲区。读完输入后,实际存储在RAM中的唯一文本将是上次调用fgets时的数据。

您可以更改add函数,以便分配新缓冲区并将字符串复制到它们。已经存在一个为您执行此操作的函数,它被称为strdup。这样的东西会起作用(虽然我没有测试过):

void add(struct info **x, char * text, int line_no, char * file) {
 ...
 newInfo = malloc(sizeof(struct info));
 newInfo->next = NULL;
 newInfo->grepstring = strdup(text);
 newInfo->line_no = line_no;
 newInfo->file = strdup(file);
 ...
}