我很高兴自己昨晚第一次尝试时没有出现任何错误或警告!但是,当然,我换了一堆填充物,把它搞砸了。。。当我尝试gdb时,this.ytxt中的列表似乎可以加载到内存中。我想问题出在写上。现在。它再次工作,但只写入文件的第一行。我注释了整个函数并打印了测试标记,但仍然无法弄清楚。这个想法是从文件中读取可变数量的行,并将它们成对打印。(实际上这本应该像学习抽认卡一样,但我从来没有抽出时间来学习(
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct member{ //This emulates a dictionary
char key[20]; //and links each word+definition pair to the next pair.
char def[20];
struct member *ptr;
};
struct member *root;
struct member *curr;
FILE *f;
int fill_list(){ //Fill each member struct with next two lines of
curr=root;
char this[20]; //FILE *f
while(EOF){
if(!fgets(this,20,f)) break;
strcpy(curr->key,this);
if(!fgets(this,20,f)) break;
strcpy(curr->def,this);
curr=curr->ptr;
curr=malloc(sizeof(struct member));
curr->ptr=0;
}
return 0;
}
void free_all(){
curr=NULL;
while(curr!=root){
curr=root;
while(curr->ptr)curr=curr->ptr;
free(curr);
}
}
int terminate(int i){ //The terminate function closes file and
free_all(); //frees malloc'd memory, then returns main func's
fclose(f); //return value.
return i;
}
int main(){
f=fopen("this.txt","r");
if(!f)return -1;
root=malloc(sizeof(struct member));
root->ptr=NULL;
fill_list();
curr=root;
if ( curr != 0 ) {
while ( curr != 0 ) {
printf( "%s", curr->key );
curr = curr->ptr;
}
}
free_all();
return terminate(0);
}
详细说明乍得的答案,您可以得到:
int fill_list(){ //Fill each member struct with next two lines of
struct member *new_mem;
curr=root;
char this[20]; //FILE *f
while(1){ /* relying on the breaks below to exit the loop */
if(!fgets(this,20,f)) break;
strcpy(curr->key,this);
if(!fgets(this,20,f)) break;
strcpy(curr->def,this);
/* create the new member */
new_mem=malloc(sizeof(struct member));
/* set the new member's next ptr to NULL */
new_mem->ptr = NULL;
/* set the current member's next to the new member */
curr->ptr=new_mem;
/* current is now the new member */
curr = new_mem;
}
return 0;
}
编辑:我想我应该补充一点,如果我要对你的代码进行轻微的修改,这就是我要做的。如果我从头开始做,我不会以这种方式构建循环,也不会有不必要的全局变量,比如curr。萨诺提出的观点也是如此,你只有一个临时缓冲区。更不用说你在列表中的最后一个条目可能是无效的;只有在成功地将两个字符串读取到两个临时缓冲区时,才分配列表中的下一个成员条目可能是更好的主意。
一些可能的错误:
没有名为"this"的变量。"this"是C++保留字。(如果你编译为C,可能没问题(
您的free_all((函数看起来可疑。我看了几眼才弄清楚发生了什么。看起来你正试图通过遍历到尾部,释放最后一个节点,然后从根的顶部重新开始来释放链表。与以线性方式释放相比,这将具有n平方性能。我想你应该这么说:
void free_all()
{
struct member* curr = root;
while (curr)
{
struct member* next = curr->ptr;
free(curr);
curr = next;
}
}
int fill_list(){ //Fill each member struct with next two lines of
curr=root;
char this[20]; //FILE *f
while(EOF){
/* ... */
您的while(EOF)
循环永远不会在这里终止——EOF
在stdio.h
到(-1)
:中定义
/* End of file character.
Some things throughout the library rely on this being -1. */
#ifndef EOF
# define EOF (-1)
#endif
在自己的程序中重新定义EOF
是不明智的。
如果您真的想要一个无限循环,请使用while(1)
或for(;;)
中的一个;这两个都是非常明显的无限循环,并且这两个是用于无限循环的常见C习惯用法。最好将循环的退出条件重新写入while()
,但有时这很困难。(do { /* foo */ } while ()
有时是完美的解决方案,在这里可能更好。(
我不确定你应该做什么来修复你的while()
循环条件,因为我不完全确定它应该做什么:
while(EOF){
if(!fgets(this,20,f)) break;
strcpy(curr->key,this);
if(!fgets(this,20,f)) break;
strcpy(curr->def,this);
您不妨直接阅读curr->key
和curr->def
。(如果您想在出现错误时保持对象的一致性,读取临时存储是有意义的,但您需要两个临时变量,并在这两个IO命令之后更新值。由您决定。(
curr=curr->ptr;
curr=malloc(sizeof(struct member));
curr->ptr=0;
}
在这篇小文章中,您用下一个节点的值重写curr
指针。然后分配一个新节点,并再次重写curr
指针。然后将新分配的对象中的curr->ptr
指针置空。curr
对象现在具有未初始化的curr->key
和curr->def
字符数组。这是故意的吗?(允许半初始化的对象存在于程序中通常会导致灾难。(
在fill_list()
中,您错误地分配了对象。
curr=root;
// now curr is a copy of root->ptr
curr=curr->ptr;
// curr allocated properly, but not attached to root at all!
curr = malloc(...)