C 语言中的链表(显然 malloc 不想成为我的朋友)



我很高兴自己昨晚第一次尝试时没有出现任何错误或警告!但是,当然,我换了一堆填充物,把它搞砸了。。。当我尝试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)循环永远不会在这里终止——EOFstdio.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->keycurr->def。(如果您想在出现错误时保持对象的一致性,读取临时存储是有意义的,但您需要两个临时变量,并在这两个IO命令之后更新值。由您决定。(

    curr=curr->ptr;
    curr=malloc(sizeof(struct member));
    curr->ptr=0;
}

在这篇小文章中,您用下一个节点的值重写curr指针。然后分配一个新节点,并再次重写curr指针。然后将新分配的对象中的curr->ptr指针置空。curr对象现在具有未初始化的curr->keycurr->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(...)

相关内容

  • 没有找到相关文章

最新更新