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

发布于 2024-12-11 17:11:46 字数 1638 浏览 0 评论 0原文

我很高兴自己昨晚就能让它正常工作,而且在我第一次尝试时也没有出现任何错误或警告!但是,当然,我换了一堆填充物,然后把它搞砸了...... 当我尝试使用 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);
}

I was so pleased with myself getting this to work last night without any errors or warnings on my first try too! But, of course, I changed a bunch of stuffed and screwed it up...
When I tried to gdb it, the list from this.ytxt seemed load to memory just fine. I think the problem was writing it. Now. it works again but only writes the first line of the file. I commented out whole functions and printf'd test marks and still couldn't figure it out.
the idea is to read a variable number of lines from a file and print them in pairs. (Actually
it was meant to be like study flashcards but I never got around to that part)

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

蓝海 2024-12-18 17:11:46

详细说明乍得的答案,您可以:

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 这样不必要的全局变量。 sarnold 提出的观点也是如此,即您只有一个临时缓冲区。更不用说您在列表中的最后一个条目可能无效;仅在成功将两个字符串读入两个临时缓冲区之后才分配列表中的下一个成员条目可能是一个更好的主意。

Elaborating on Chad's answer, you could have:

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

EDIT: thought I'd just add that if I was going to make slight modifications to your code this is what I'd do. If I were to do it from scratch I wouldn't structure the loop that way or have unnecessary global variables like curr. Same goes for the point made by sarnold where you only have a single temporary buffer. Not to mention that your last entry in the list could be invalid; it might be a better idea to allocate the next member entry in the list only after you successfully read the two strings into two temporary buffers.

娇纵 2024-12-18 17:11:46

一些可能的错误:

没有名为“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;
    }
}

Some possible bugs:

Do not have variables named "this". "this" is C++ reserved word. (Probably ok if you are compiling as C)

Your free_all() function looks suspicious. It took me a few glances to figure out what was going on. It looks like you are trying to free the linked list by traversing to the tail, deallocating the last node, and starting back from the top of the root again. This will have n-squared performance compared to freeing in a linear fashion. I think you want to say this:

void free_all()
{
    struct member* curr = root;
    while (curr)
    {
        struct member* next = curr->ptr;
        free(curr);
        curr = next;
    }
}
情绪失控 2024-12-18 17:11:46
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。 (如果您希望即使在出现错误时也能保持对象的一致性,那么读入临时存储是有意义的,但是您需要两个个临时变量,并在两个<之后更新值/em> IO 命令。由您决定。)

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

在这一小部分中,您用下一个节点的值覆盖 curr 指针。然后分配一个新节点并再次覆盖 curr 指针。然后将新分配的对象中的 curr->ptr 指针清空。 curr 对象现在具有未初始化的 curr->keycurr->def 字符数组。这是故意的吗? (允许半初始化的对象存在于程序中通常会导致灾难。)

int fill_list(){                //Fill each member struct with next two lines of
    curr=root;
    char this[20];              //FILE *f
    while(EOF){
        /* ... */

Your while(EOF) loop will never terminate here -- EOF is defined in stdio.h to (-1):

/* End of file character.
   Some things throughout the library rely on this being -1.  */
#ifndef EOF
# define EOF (-1)
#endif

It would be unwise to redefine EOF in your own program.

If you really want an infinite loop, please use one of while(1) or for(;;); Both of these are very obviously infinite loops, and both of these are common C idioms for infinite loops. Better would be re-writing your loop's exit condition into the while(), but sometimes that is difficult. (do { /* foo */ } while () is sometimes the perfect solution, and is probably better here.)

I'm not sure what exactly you should do to fix your while() loop condition, because I'm not entirely sure what it is supposed to be doing:

while(EOF){
    if(!fgets(this,20,f)) break;
    strcpy(curr->key,this);
    if(!fgets(this,20,f)) break;
    strcpy(curr->def,this);

You might as well be reading directly into curr->key and curr->def. (Reading into temporary storage makes sense if you want to keep your objects consistent even in the face of errors, but you'd need two temporary variables for that, and update the values after both IO commands. Up to you.)

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

In this small piece, you over-write the curr pointer with the value of the next node. Then you allocate a new node and over-write the curr pointer again. Then you null out the curr->ptr pointer in the newly allocated object. The curr object now has uninitialized curr->key and curr->def character arrays. Is this intentional? (Allowing half-initialized objects to live in your program is usually a recipe for disaster.)

满天都是小星星 2024-12-18 17:11:46

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(...)

In fill_list() you incorrectly allocating objects.

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(...)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文