moonraccoon
moonraccoon

Reputation: 93

Why has the structure pointer have the wrong values

So I started looking into Datastructures in C and wanted to code a Singly Linked List.

this is a small piece of it:

struct nodes {
    int val;
    struct nodes *next;
};

void insert(struct nodes *list, int val) {
    struct nodes *tmp = (struct nodes*) malloc(sizeof(struct nodes));
    tmp->val = val;
    tmp->next = list;
    list = tmp;
}

int main() {
    struct nodes *test;
    insert(test, 5);
    insert(test, 10);

    printf("test %d\n", test->next->val);
}

Here I get totally wrong output. When I try writing a function where I don't have to pass in the structure pointer, it works like expected.

OUTPUT:

test 90053

P.S I'm still starting with C so don't judge too hard :D

Upvotes: 0

Views: 856

Answers (2)

arfneto
arfneto

Reputation: 1765

You can go on this way:

    struct nodes {
    int val;
    struct nodes* next;
};

nodes* insert(struct nodes* list, int val) {
    struct nodes* tmp = (struct nodes*)malloc(sizeof(struct nodes));
    tmp->val = val;
    tmp->next = list;
    return tmp;
}

When experimenting with structures like that the 1st function you write --- I believe --- is list() not insert().

In every function that can change the start address of the list you must return the address or it would be lost. And since you only insert at the beginning you lost everything, as the start address is always changed.. In general do not use void. At a minimum is a waste, often an error. Return something, like a completion status. See an implementation of list() that returns... the size

int         list(struct nodes* list)
{
    struct nodes* p = list;
    int N = 0;
    while (p != NULL)
    {
        printf("#%d  %d\n", N, p->val);
        p = p->next; N += 1;
    };
    printf("\n");
    return N;
}

and a version of main() using the 2 functions

int main() {
    struct nodes* test = NULL;
    int n = 0;
    for(n = 800; n>0; n-= 100) test = insert(test, n);
    n = list(test);
    printf("At the end list() returned %d\n", n);
}

this way you have more info since the beginning.

#0  100
#1  200
#2  300
#3  400
#4  500
#5  600
#6  700
#7  800

At the end list() returned 8

a test program

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

struct no
{
    void*       item;
    struct no*  next;
    struct no*  prev;
};  // no
typedef struct no Node;

typedef struct
{
    char* name;
    unsigned  size;
    unsigned  limit;
    Node* start;
    Node* end;
}   List;

struct nodes {
    int val;
    struct nodes* next;
};

struct nodes*   insert(struct nodes*, int);
int             list(struct nodes* L);

int main() {
    struct nodes* test = NULL;
    int n = 0;
    for(n = 800; n>0; n-= 100) test = insert(test, n);
    n = list(test);
    printf("At the end list() returned %d\n", n);
}

struct nodes*   insert(struct nodes* list, int val) {
    struct nodes* tmp = (struct nodes*)malloc(sizeof(struct nodes));
    tmp->val = val;
    tmp->next = list;
    return tmp;
}

int         list(struct nodes* list)
{
    struct nodes* p = list;
    int N = 0;
    while (p != NULL)
    {
        printf("#%d  %d\n", N, p->val);
        p = p->next; N += 1;
    };
    printf("\n");
    return N;
}

As pointed in the comments, note that a list is not a node. A list if a collection of nodes, and the nodes have a data payload. If the payload is a (void*) then you have a really abstract data structure since it can load anything, from a single char to a 100-fields structure.

Think about the way you wrote it and the case you have 5 lists in your program: a mess it will turn into very fast. And compare with something like the code below

a linked list structure

struct no
{
    void*       item;
    struct no*  next;
    struct no*  prev;
};  // no
typedef struct no Node;

typedef struct
{
    char* name;
    unsigned  size;
    unsigned  limit;
    Node* start;
    Node* end;
}   List;

Note that as you put more info into the List things get easier: you have always a size, a limit, pointers to start and end, and so on

Upvotes: 0

tadman
tadman

Reputation: 211540

You're altering a local variable so there's no effect on the caller. What you might mean is to use a pointer to a pointer so that can be changed:

int main() {
    struct nodes *test = NULL; // Don't forget to initialize
    insert(&test, 5);
    insert(&test, 10);

    printf("test %d\n", test->next->val);
}

Where your function now looks like:

void insert(struct nodes **list, int val) {
    struct nodes *tmp = malloc(sizeof(struct nodes)); // No need to cast malloc() in C
    tmp->val = val;
    tmp->next = *list;
    *list = tmp;
}

Since list is de-referenced (*list) it actually alters the original value (that is pointed to) meaning your list head changes.

In your original code you never initialized list, it's just some random garbage value, and because insert can never change it, it stays as junk data. Accessing any data through that is undefined behaviour so you'll get junk data or a crash.

Upvotes: 3

Related Questions