考虑到我读取的每一行的内容,我正在尝试遍历流的内容以动态生成列表中的节点。我有一个我在下面定义的结构:
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;
}
}
答案 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);
...
}