0

I'm probably missing something really important regarding pointers and memory management. I'm building a doubly linked list. I have a struct Node:

struct Node {
    void* data;
    nodep prev;
    nodep next;
};

with nodep being a typedef for a pointer to such a Node:

typedef struct Node * nodep;

Now I wrote an insertAt() function, which takes a nodep lst which is basically a pointer to the first element in the list, or NULL for the empty list, an int pos, the position at which to insert the element and a void* data, which is the payload of the Node. This is the excerpt my code, where I get an error:

nodep insertAt(nodep lst, int pos, void *data){

    nodep new = malloc(sizeof(struct Node));
    [...]


    new -> data = data;
    assert(new != NULL);
    printf("memory allocated!\n");

    /* insert at last position */
    if(pos == -1) {
        [...]

    /* insert at first position */
    } else if (pos == 0) {
        if(lst == NULL) {
            new -> next = lst;
            lst = new;
        } else {
            [...]
        }

    /* insert at pos */
    } else {        
        [...]
    }

    return new;
}

This is how I call insertAt() in my main() function:

int i;
nodep lst = NULL;

insertAt(lst, 0, "test");

When I run my program with valgrind, I get an

Access not within mapped region at adress 0x10

for this line of code:

lst = new;

What I want to do is make the nodep lst point to the nodep new, which then is the first element of the list. I don't really get, why I encounter this error.

Thanks in advance for any help.

Cheers Nick

npie_
  • 53
  • 1
  • 7
  • Better create a [Minimal, **Complete**, and Verifiable Example](http://stackoverflow.com/help/mcve) to show us. – Some programmer dude Feb 09 '18 at 11:34
  • It's really not a good habit to use `new` as a variable name, it's too keyword-like in many languages. – llllllllll Feb 09 '18 at 11:34
  • 1
    It makes program unreadable if you typedef pointers. – 0___________ Feb 09 '18 at 11:36
  • Also, you do know that C passes its argument *by value*, meaning they get *copied*? That means inside your `insertAt` funciton, the variable `lst` is a *copy*, and modifying that copy (like assigning to it) will not change the original variable you passed in. You might want to do some research about *emulating pass by reference in C*. – Some programmer dude Feb 09 '18 at 11:36
  • Furthermore, The [`assert`](http://en.cppreference.com/w/c/error/assert) macro is disabled in typical release builds. Its use as a sanity-checker is greatly overstated and overused, especially since its way of solving a problem is to forcibly abort (crash) the program. Or do nothing at all in a release build. – Some programmer dude Feb 09 '18 at 11:44
  • You have to actually _use_ the value returned by the function. `nodep lst = insertAt(...` This would be where you should go and find out how to enable compiler warnings. In addition, you shouldn't hide pointers behind typedefs. – Lundin Feb 09 '18 at 12:31

1 Answers1

1

If you want to modify lst you have to use a double pointer.

I will use int for simplicity

int i;
int* ptr = &i;

func(ptr);
func(int* p){

   p = ....; //this won't change ptr!
}

func(&ptr);
func(int** p){

   *p = ....; //this will change ptr!
}

In case of a double pointer and sizeof(int) = 4 and sizeof(int*) = 4

 ---------------       ---------------        ---------------
|0x4|0x5|0x6|0x7|     |0x0|0x1|0x2|0x3|      |   |   |   |   |
 ---------------       ---------------        ---------------
 0x8 0x9 0xA 0xB      0x4 0x5 0x6 0x7         0x0 0x1 0x2 0x3
 address of p         address of ptr           address of i

*p will give you the address of i.This is the address to which ptr points.That's why with double pointer you change the "outside" pointer.

Martin Chekurov
  • 733
  • 4
  • 15