-2

Why cant I assign a pointer to a double pointer's pointer? I get segmentation fault every time.

#include <stdio.h>

int main() {
    int **pointer1, *pointer2, *pointer3, var;

    var = 10;
    pointer3 = &var; 
    pointer1 = &pointer3;
    pointer2 = *pointer1;   //correcting my mistake, so this is now correct?

    return 0;
}

The code I was actually working on, practicing linked list:

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

typedef struct node_t {
    int num;
    struct node_t *next;
} node_t;

void insert(int, node_t**);

int main(void) {
    int list;
    node_t **head, *temp;

    *head = NULL;

    while (scanf("%d", &list) != EOF) {
        insert(list, head);
    }
    temp = *head;
    /*while (temp != NULL) {      //here is the problem, if I remove this 
                                  //I get segmentation fault but it runs 
        printf("%d ", temp->num); //runs fine when I include it
        temp = temp->next;

    }*/
    return 0;
}

void insert(int list, node_t **head) {
    node_t *temp = malloc(sizeof(node_t));
    temp->next = (*head);
    temp->num = list;
    (*head) = temp;
}

Just like what I put in the code comment, the above version of my code gets segmentation fault when I compile it without the while loop. But weirdly enough, it works fine once I include the while loop. After fiddling around, I suspect the culprit to be the double pointer in which I tried to assign the secondary address into a regular pointer. But this version actually runs fine:

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

typedef struct node_t {
    int num;
    struct node_t *next;
} node_t;

void insert(int, node_t**);

int main(void) {
    int list;
    node_t *head, *temp;

    head = NULL;

    while (scanf("%d", &list) != EOF) {
        insert(list, &head);
    }
    temp = head;
    while (temp != NULL) {

        printf("%d ", temp->num);
        temp = temp->next;

    }
    return 0;
}

void insert(int list, node_t **head) {
    node_t *temp = malloc(sizeof(node_t));
    temp->next = (*head);
    temp->num = list;
    (*head) = temp;
}

Over here I passed the address into the linked list function and essentially I'm doing the same thing but without the double pointer.

On a side note, I have seen many different implementations of linked lists. Mine requires the double pointer because I'm using a void insert(int, **node_t), but there are versions which returns the address and updates the head: node_t* insert(int, *node_t) and Global linked list: void insert(int). Just wondering which versions are actually recommended, easier to debug and beginner friendly.

  • 1
    Without looking at the 2nd block of code, your first example segfaults because `*pointer1` isn't pointing to anything. Specifically the `**pointer1 = 10` statement is causing the segfault. – bool3max Sep 09 '18 at 13:09
  • For you to be able to dereference a pointer it needs to be *pointing* somewhere. All uninitialized non-static local variable really *are* uninitialized, with an *indeterminate* value. You must always initialize your local variables before using them. And dereferencing an uninitialized pointer leads to [*undefined behavior*](https://en.wikipedia.org/wiki/Undefined_behavior) and a very likely crash (if you're lucky!) – Some programmer dude Sep 09 '18 at 13:11
  • 2
    Don't confuse `Type *ptr = some address;` with sequential lines `Type *ptr; *ptr = some value;` They're two very different things. – WhozCraig Sep 09 '18 at 13:12
  • Still slightly confused, why won't the address of 10 be automatically stored in *pointer1? And automatically create and stores another pointer pointing to the address storing the address of 10? – AmateurCoder Sep 09 '18 at 13:23
  • *the address of 10* - the numeric constant value `10` isn't addressable, but that's beside the point. Your first blocks of code are dereferencing *indeterminate* pointers. That's the core problem you seem to be struggling with. Also, *"Over here I passed the address into the linked list function and essentially I'm doing the same thing but without the double pointer."* - your last code passes the `head` pointer in `main` by address to a function with a formal parameter of a pointer-to-pointer type, so I don't see how you statement "without the double pointer" holds water. – WhozCraig Sep 09 '18 at 13:27
  • So I have to initialize a double pointer by assigning it to an address of a pointer or else it would result in the segmentation fault as it is logically incorrect to do that? The double pointer part was talking about in main there is no more double pointer. Pardon my poor language. – AmateurCoder Sep 09 '18 at 13:33
  • 2
    @AmateurCoder you are trying to deliver a letter containing the number '10', but there is no address on the envelope. – Martin James Sep 09 '18 at 13:47

2 Answers2

2

Your first example segfaults because *pointer1 (and pointer1 before it) isn't pointing to anything. It's an uninitialized pointer that points to random garbage data in memory.

Trying to dereference such a pointer (**pointer1 = 10;) results in a segfault.

A solution to make your first example work would be to allocate some memory for the data you're trying to store :

int **pointer1, *pointer2;

int *data = malloc(sizeof(int));

pointer1 = &data;
**pointer1 = 10;

pointer2 = *pointer1;

free(*pointer1); //or free(data)
bool3max
  • 2,748
  • 5
  • 28
  • 57
  • Thank you! So am I right to say by allocating memory, *data now contains an address in which pointer1 can point to(by pointing at address of data which now contains a pointer)? – AmateurCoder Sep 09 '18 at 14:20
  • @AmateurCoder Yeah, exactly as you put it. One thing though, `*data` doesn't contain an address. `data` does. `*data` means: "Hey, go look what is *at* the address that `data` is holding, and fetch me whatever data is there". (in your example it's the integer `10`). – bool3max Sep 09 '18 at 14:36
1

When you do this:

 **pointer1 = 10;

What this says is "take the address stored in pointer1, dereference that address, take the address stored there, dereference again, and store the value 10 at that location".

It looks something like this:

pointer1
-------     -------    ------
|  .--|---->|  .--|--->| 10 |
-------     -------    ------

You're getting a segfault because pointer1 doesn't currently point anywhere.

This could work if you do something like this:

int **pointer1, *pointer2, value;
value = 10;
pointer2 = &value;
pointer1 = &pointer2;

In the case of the two "real" code snippets, the problem with the first piece of code is that you pass head uninitialized to insert, which then subsequently dereferences head. This is the same problem as above. The same thing happens again in main because head is still uninitialized after calling list because it was passed by value. The second piece of code works because you pass the address of head to insert, so subsequently dereferenced it is valid.

dbush
  • 205,898
  • 23
  • 218
  • 273