简体   繁体   中英

storing an array of nodes in linked list

I have a problem with storing an array of nodes in linked list, each node contains a fixed size array of values. My program can compile without errors, but there is no output, and I do not know why. Here is my struct function for Node and list:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define SIZE 20

typedef struct NODE Node;
struct NODE
{
char *bucket[SIZE]; 
int count;       
Node *next;
};

  Node *new_node()
{
   Node *curr=malloc(sizeof( Node ));
   curr->count=0;
   curr->next=NULL;
   return curr;
}

void add_node(Node *node,char *x)
{

    node->bucket[node->count] = (char *)malloc( strlen( x ) + 1 );
    strcpy(node->bucket[node->count],x);
    node->count++;
}
typedef struct LIST List;

struct LIST 
{
    Node *top;
};

List *construct() 
{
List *list;

list = malloc( sizeof( List ) );
list->top = NULL;

return list;
}
void insert( List *list, char *new_string )
{
 Node *newNode = new_node();
 Node *curr;

 curr = list->top;
if ( NULL == curr)
{
  curr=newNode;
}
add_node(newNode,new_string);

 }


void print( List *list )
{
  Node *curr = list->top;

  while ( NULL != curr ) 
  {
   for(int i=0;i<curr->count;i++)
   {
    printf( "%s\n", curr->bucket[i]);
   }
    curr = curr->next;
  }
} 

Here is my test function:

 int main(int argc, char const *argv[])
 {

   List *list=construct();
   char *ch="a";

   insert(list,ch);
   insert(list,ch);
   insert(list,ch);
   insert(list,ch);
   insert(list,ch);
   print(list);


   return 0;
  }

Any ideas why this is not behaving as expected?

Main issue is your insert() function.

void insert(List *list, char *new_string)
{
        Node *newNode = new_node();
        Node *curr;

        curr = list->top;
        if (NULL == curr) {
                /* OK. We set curr to newNode, but what happens to curr? */
                curr = newNode; 
        }
        /* String is added to newNode, but what happens to newNode? */
        add_node(newNode, new_string);
}

If you instead say (which you might intended):

if (list->top == NULL) {
    list->top = newNode;
}

you would keep first newNode , but loose the rest.


When it comes to add_node() there is nothing directly wrong with it. Biggest issue is that you do not check if node->count is 20. Secondly it has a very bad name . Take care when you name functions else your code becomes very hard to read and maintain.

add_node does not add a node. The name should reflect what it does.

For example you could say:
insert should be named add_node , and add_node should be named something like add_string , push_string , bucket_fill or the like. At least that would be somewhat better.

It is also redundant to cast malloc :

node->bucket[node->count] = (char*)malloc(strlen(str) + 1);

Better (IMHO):

node->bucket[node->count] = malloc(strlen(str) + 1);

There is various ways to add a new node. One way is to loop until last and add:

    while (node->next != NULL) {
            node = node->next;
    }
    node->next = new_node();
    bucket_fill(node->next, str);

If you have a separate struct for list, you can keep track of head and tail:

struct list {
    struct node *head;
    struct node *tail;
};

And then something like:

void node_add(struct list *list, char *str)
{
        struct node *new_node = node_create();

        bucket_fill(new_node, str);

        if (list->head != NULL) {
                list->tail->next = new_node;
                list->tail = new_node;
        } else {
                list->head = new_node;
                list->tail = new_node;
        }
}

And so on and so forth.


Have a look at each step and try to keep track of the nodes.

Often one would not have a struct list and a struct node , but use node for both. A list is in essence the first node in a chain of nodes.


One thing that is really helpful when coding linked lists, and C in general, is to use Valgrind, (at least on Linux and the like). For this to be more useful you will first need to add free_list() functions to free up memory.

Make it a rule to always write a free function when you write a function using malloc .

Then run your program with:

$ valgrind ./my_program

If you use gcc compile with -ggdb to get line-numbers on the output from Valgrind.

The two cases that would be useful for you then is to ensure all memory are freed on exit. This makes sure you do not miss anything in your code. Secondly you will get warnings when you access uninitialized variables etc.


As a starter there is two things to look at:

1.) No leaks. "in use at exit" should be 0.

==13476== HEAP SUMMARY:
==13476==     in use at exit: 0 bytes in 0 blocks
==13476==   total heap usage: 43 allocs, 43 frees, 424 bytes allocated
==13476== 
==13476== All heap blocks were freed -- no leaks are possible

2.) Use of uninitialized values:

==12972== Conditional jump or move depends on uninitialised value(s)
==12972==    by 0x8048838: insert (foo.c:120)
==12972==    by 0x804890E: main (foo.c:151)
                                      |
                                      |
                                      +--- Shows file and line-number.

Or:

==12820== Use of uninitialised value of size 4
...

And the like.


A typical free function could be something like:

void free_bucket(struct node *node)
{
        int i;

        for (i = 0; i < node->count; ++i) {
                free(node->bucket[i]);
        }
}

void free_list(struct node *head)
{
        struct node *tmp_node;

        while (head != NULL) {
                free_bucket(head);
                tmp_node = head;
                head = head->next;
                free(tmp_node);
        }
}

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