2012-02-03 53 views
1

我试图通过流的内容循环来动态生成列表中的节点,给出了我读取的每一行的内容。我有如下定义的结构:无法指定字符指针循环中的结构

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); 
     } 

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

我不确定正确的方法是去解决这个问题。我是否以某种方式修改我的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; 
} 

}

+0

错误必须在添加或打印列表中的代码。你可以请他们发表。 – 2012-02-03 02:36:21

+0

为了能够确定问题的原因,我们需要查看您提及的打印电话的确切位置。 也是迂腐,我会建议在每次调用后检查strtok返回null,这将意味着字符串t null终止字符已被发现 – Lefteris 2012-02-03 02:40:14

+0

那么,它是什么? '结构信息'或'结构说'? – 2012-02-03 02:56:25

回答

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的所有内容执行此操作,因为此刻它们都是指向堆栈分配的缓冲区的指针。

当您完成该操作时,您必须再次使用free内存,但它会一直持续到此时。

+0

我认为你是正确的...修改我的代码,包括工作文本的内存分配。何时何地我应该释放 - 最后当我销毁列表? – thomascirca 2012-02-03 02:56:43

+0

@thomascirca每当你不再需要内容。每当你调用'malloc',某处必须有一个相应的'free',否则你有*内存泄漏*。就像你说的那样,在这种特殊情况下,当你“摧毁列表”时,你可能想循环和“释放”所有东西。 – Borealid 2012-02-03 02:59:39

+0

我只想补充一点,如果你的程序即将终止,你不需要担心释放,因为所有的内存将在那个时候被操作系统释放。 – 2012-02-03 03:10:56

1

你不告诉我们什么呢add(),但显然它只是分配直接调用strtok()到结构的成员的结果。您不能这样做 - 在将它们分配给结构成员之前,使用strdup()(或malloc()strcpy())复制每个char *。指针strtok()返回指向该缓冲区的那个点,并且它们在每个新的循环迭代中变得无效。

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); 
... 
}