Search code examples
cpass-by-referencepointer-to-pointer

Pointers of pointer and pass by reference


I'm struggling to understand how pointers work. The way I got it is that, when I declare a pointer to, say, int, I create both a variable that'll contain an address (that must be initialized to even operate on the int) and an int variable. Visually, I'd represent this this way (address;int). For example, if I declared

int* number;

I'd have "number" being the address variable and "*number" being the int variable.

Likewise, declaring something such as int** d should mean to create a pointer to (address;int). That'd be [address;(address;int)].

With this in mind, I was trying to modify the int value of **d by using an external function, incrementer_3, and this so called pass by reference, but I get an error on runtime. So, I was wondering what I'm missing.

#include <stdio.h>

void incrementer(int* a) {
    (*a)++;
}

void incrementer_2(int** a) {
    (**a)++;
}

void incrementer_3(int*** a) {
    (***a)++;
}

int main() {
    int b = 7;
    incrementer(&b);
    printf("%d\n", b);

    int* c = (int*)malloc(sizeof(int));
    *c = 4;
    incrementer_2(&c);
    printf("%d\n", *c);

    int** d = (int**)malloc(sizeof(int*));
    **d = 6;
    incrementer_3(&d);
    printf("%d\n", **d);

    system("pause");
}

FYI the part when I increase b and c works fine. On a side note, I was also wondering if it's possible to modify the value of *c by using the function "incrementer" and not "incrementer_2". In fact I was just thinking that I could have simply written from main

incrementer(&(*c));

or, in a simpler way

incrementer(c);

but none of them work on runtime.


Solution

  • You need to keep in mind that a pointer need not actually refer to anything, and even if it does refer to something that something need not be valid. Keeping track of those things is your job as a programmer.

    By convention an invalid pointer will be given the value 0 (which is what NULL eventually comes to) but that is only convention, other values might be used in some circumstances.

    So, with "int* number;" you have declared a pointer-to-int but because it is not initialized you have absolutely no idea what value it contains, dereferencing it at this point is undefined behavior - meaning that most anything could happen if you tried doing so, though in reality it will likely simply crash your program.

    The problem with:

    int** d = (int**)malloc(sizeof(int*));
        **d = 6;
    

    is that while d is initialized *d is not. You could do:

    *d = malloc(sizeof(int));
    

    or

     *d = c;
    

    but *d needs to be pointed at something before you can use **d.