Question:
Creating linked list in C...?
Question M
2012-06-06 04:53:34 UTC
Let say you have text file people in which it is written like this:

John 25
Jack 30
Michelle 32
Scott 20
Max 17

And so on. Then I have a program like this:

import ...

struct person{
char name[50];
int age;
struct person *next;
};

int main(){

struct person *a;
struct person *b;
a=malloc(sizeof(struct person));
FILE *fd;
fd=fopen("people.txt", "r");
char wordwritten[100];
int c=0;
int i=1;
while (fscanf(fd, "%s", wordwritten)!=EOF){
if (c==0){
strcpy(a->name, wordwritten);
}
if (c==1){
a->age=atoi(wordwritten);
c=-1;
}
c++;
a=realloc(a, sizeof(struct person)*(i+1));
}
}


What did I do wrong that this program doesn`t work? Thank you!!! :)
Three answers:
Jonathan
2012-06-07 02:32:42 UTC
Your design is a little funky, using the variable 'c' the way you do. I'm less concerned about fixing that because the huge error I see is in your realloc() call. You are treating your linked list as an extendable array. That's not a linked list, it is an array. And if it were to just be an array there would be no need for a pointer (*next) to other list elements.



The idea of the linked list is that you malloc each list element separately, not keep them as adjacent elements in an aggregate array. Linked list items are "tied" together using the 'next' pointer.



C has at least three "obvious" ways to design a structure here. Look over these three:



typedef struct person1_s {

    struct person1_s *next;

    int age;

    char name[50];

} person1_t;



typedef struct person2_s {

    struct person2_s *next;

    int age;

    char *name;

} person2_t;



typedef struct person3_s {

    struct person3_s *next;

    int age;

    char name[1];

} person3_t;



The first one has a fixed size for name. That limits the length and always takes up the same memory. But it is simple and easy to work with. The second one allows you to allocate the space for 'name' separately, which means it can be any length. But the downside is that you have to (1) do two allocations -- one for the structure and another for the name; and (2) have to do two deallocations using free() when disposing of it. The third one has the advantages of both. It's simple to use but allows the name to be of any length. Only one malloc() call and only one free() call to create and destroy it.



At this point, I'll post some source code you can look at using the 3rd style. I'm choosing that one because it is an idiom of C that is worth knowing about and learning how to use.



You need to be aware this isn't professional code. sscanf() isn't entirely safe used the way I'm using it. The list isn't created in sorted order. In fact, it is created in reverse order to the way it is read. I chose to just keep it all very simple.



There is a function that builds the list and main() then simply illustrates how to walk the linked list, printing each item as it does. main() then frees up each linked list item and shows you how that is done, as well. Note the difference in the loops. It's an important difference when you are freeing up an item verses just using an item for printing. Good luck.



#include

#include

#include



#define getln(a)    fgets( buf, sizeof buf, (a) )



typedef struct person_s {

    struct person_s *next;

    int age;

    char name[1];

} person_t;



person_t * getpersons( FILE *fi ) {

    char buf[200], name[200], *r;

    person_t *head= NULL, *item;

    int age;

        if ( fi != NULL )

            for ( r= getln( fi ); r != NULL; r= getln( fi ) )

                if ( sscanf( buf, "%s %d", name, &age ) == 2 ) {

                    item= (person_t *) malloc( strlen(name) + sizeof(person_t) );

                    strcpy( item->name, name );

                    item->age= age;

                    item->next= head;

                    head= item;

                }

    return head;

}



int main( void ) {

    person_t *head= NULL, *item;

    FILE *fd;

        head= getpersons( (fd= fopen( "people.txt", "r" )) );

        for ( item= head; item != NULL; item= item->next )

            printf( "'%s' %d\n", item->name, item->age );

        for ( item= head; item != NULL; ) {

            person_t *next= item->next;

            free( item );

            item= next;

        }

        head= NULL;  /* just to be sure */

        fclose( fd );

    return 0;

}
anonymous
2012-06-06 05:12:28 UTC
#include



struct person {

        char name[50];

        int age;

};



static int readline(char *s, size_t size)

{

        int c;



        size--;

        while ((c = getchar()) != EOF && c != '\n')

                if (size) {

                        *s++ = c;

                        size--;

                }

        *s = '\0';

        return c == EOF;

}



static int parse(struct person *dst, const char *str)

{

        char format[64];



        sprintf(format, "%%%lus %%d", (unsigned long) sizeof dst->name - 1);

        return sscanf(str, format, dst->name, &dst->age) != 2;

}



int main(void)

{

        char line[1024];

        struct person a;



        while (!readline(line, sizeof line)) {

                if (parse(&a, line)) {

                        fprintf(stderr, "invalid format\n");

                        continue;

                }

                printf("%s: %d\n", a.name, a.age);

        }

        return 0;

}
Erika
2016-12-11 22:35:24 UTC
think of: what's suitable record? What function/approaches does it would furnish? What do you comprehend in C which could furnish the above function? once you start up writing the code AND come across issues which you would be able to no longer resolve - ask specific questions.


This content was originally posted on Y! Answers, a Q&A website that shut down in 2021.
Loading...