简体   繁体   中英

Linked List in C (apparently malloc doesn't want to be my friend)

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

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

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.

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

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM