-1

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.

Rob
  • 14,746
  • 28
  • 47
  • 65

3 Answers3

0

The problem is that you allocate memory for the int* but you don't allocate any memory for the int or set the pointer of the int. Should be:

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

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.

No, when you declare a pointer you create a variable that knows how to contain an address. When you use malloc() you allocate memory. malloc() returns an address that you may assign to your pointer.

P.S. - incrementer(c) should work just fine

Avishai Y
  • 123
  • 7
  • Thank you, it does work now. About the last point, I improperly meant that I've assumed that declaring a pointer to int means to create a variable that has two fields, one for containing an address, the other for containing an int value. Is this guess even true? – thegreatestdoge Dec 30 '17 at 21:13
  • You're welcome. No, a pointer contains only one value - an address. You may use operators like `* . ->` to handle the value in the memory address pointed by the pointer. – Avishai Y Dec 30 '17 at 21:17
0

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.

SoronelHaetir
  • 14,104
  • 1
  • 12
  • 23
0
int b

b is an int. We can refer to it by writing b.

b = 7;

Here we assign a number to b.

int* c 

c is a pointer that should point to an int. We can refer to that int by writing *c.

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

We have found a piece of memory that can hold an int, and made a pointer that points to that piece, and assigned it to c. All is well.

*c = 4;

Here we assign a number to *c. See? *c behaves just like b. But that's only because we have initialised it with a valid pointer! Without that, *c = 4; would be invalid.

int** d

d is a pointer that should point to a thing of type int*, which we can refer to by writing *d. That int* thing, in turn, should point to an int, which we can refer to by writing **d.

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

We have found a piece of memory that can hold an int*, and made a pointer that points to that piece, and assigned it to d. All is well. Now that int* we call *d, what does it point to?

Nothing. In order to point it to something, we could have found a piece of memory that can hold an int, and made a pointer that points to that piece, and assigned it to our *d, just as we have done earlier with c. See? *d behaves just like c. In order to use *c we had to initialise c with a valid pointer first. In order to use **d we need to initialise *d with a valid pointer first.

*d = (int*)malloc(sizeof(int));
n. m. could be an AI
  • 112,515
  • 14
  • 128
  • 243