1

I've been trying to figure this out for a while.

From what I understand a pointer is declared like this:

int x =1;
int* p;

From what I understand is that p is not currently pointed to anything but whatever p is pointing at should be an int. Makes sense.

then pass the address of x into p, so that it can point to its value

p = &x

Now whatever x is equal to is also equal to *p and vice versa.

Following that train of logic, if you wanted to initialize a pointer you would do so like this:

int x = 1;
int* p = x;

But this is confusing me. Now what I understand is that the value of p (whatever it points to) is the value of x, 1, but doesn't point to x actually. So how does that work? p isn't pointing to anything but whatever it is pointed to is 1? I don't understand.

Another thing I wanted to know was how pointer = pointer works?

Let's see another example along with my train of logic:

int x = 1;
int* p;
int* p2;
p = &x;
*p2 = *p;

This translated to me as: the pointed value at p2 equals to the value pointed at p, but doesn't point to the variable that p is pointing at (which is x), just the value of x.

Can someone clarify this for me? Is my train of logic wrong? And if so how should I look at it?

Delupara
  • 359
  • 1
  • 4
  • 10
  • I guess we cannot answer such a question in a few paragraphs. Spend weeks in reading books about programming, the C language, operating system, computer architecture, instruction set, etc.. – Basile Starynkevitch Apr 22 '16 at 15:46
  • `int* p = x;` won't work. it should be `int* p = &x;` . general rule - "type" of the thing on the left should be the same as the "type" of the thing on the right. this applies to all assignments and initializations not only those which involve pointers – fukanchik Apr 22 '16 at 15:50
  • 1
    `int *p;` is a pointer to an integer. That is, `p` holds the *address* of an integer. When you do `int *p = x;` you are assigning the value of `x` as the *address* of an integer, which is likely not valid (if the value at `x` is 1, then you're saying the address of an integer is 1, which likely isn't valid). This should be `int *p = &x;` which means you are assigning the value of `p` to be the *address* of the variable `x`. – lurker Apr 22 '16 at 15:51
  • Perhaps [this](http://stackoverflow.com/questions/23963269/can-someone-explain-how-pointer-to-pointer-works/23964156#23964156) will help? – Mahonri Moriancumer Apr 22 '16 at 15:58
  • 1
    [comp.lang.c FAQ](http://www.c-faq.com/), section 4. – Keith Thompson Apr 22 '16 at 16:06
  • @lurker: "*`int *p;` is a pointer to an integer*" -- More precisely, `p` is a pointer to an integer *object*. It can't just point to `42`, for example; it has to point to some `int` object (which might contain the value `42`). – Keith Thompson Apr 22 '16 at 16:07
  • @KeithThompson indeed, I was being a little loose with my terminology. – lurker Apr 22 '16 at 16:09
  • @lurker @KeithThompson Repeating myself in the top answer: doesn't `int * p = &x;` mean that whatever p is pointing at is the address of x? Like if I printed the pointer value, wouldn't it print the adress of x and not it's value? – Delupara Apr 22 '16 at 16:10
  • @Programgenesis: What `p` is pointing at *is* `x`. What `p` *contains* (the current value of `p`) is the address of `x`. This would print the same value twice: `printf("%p\n%p\n", (void*)p, (void*)&x);`. And this: `p == &x` would evaluate to true (`1`). – Keith Thompson Apr 22 '16 at 16:13

3 Answers3

4

After

int x = 1;

to get a pointer to x you would say

int * p = &x;

and not

int * p = x;

so you were right to find the latter confusing.

In your second example, when you say

*p2 = *p;

that will take the thing p points to (which is the value 1, contained in the variable x) and try to store it wherever p2 points. Unfortunately p2 has not been initialized, and doesn't point anywhere useful, so the results are unlikely to be anything you want. So, again, if you were confused about what that would do, you were right to be confused.

Gareth McCaughan
  • 19,888
  • 1
  • 41
  • 62
  • but doesn't `int * p = &x;` mean that whatever p is pointing at is the address of x? Like if I printed the pointer value, wouldn't it print the adress of x and not it's value? – Delupara Apr 22 '16 at 16:04
  • 1
    When you write `int * p = &x`, the `int *` part is just the type of `p`; it doesn't mean that the pointer `p` is being followed at this time. (But later if you write `*p = 3;`, it does mean that. You'll get used to it...) – Gareth McCaughan Apr 22 '16 at 16:16
  • @GarethMcCaughan So the "value at address" operator "*" doesn't mean the same at initialisation? – Delupara Apr 22 '16 at 16:17
  • In `int * p = &x;`, the `*` isn't an operator at all, it's part of a *type*, and as such it doesn't mean the same as it does when it's an operator. – Gareth McCaughan Apr 22 '16 at 16:25
  • @GarethMcCaughan This was 100% my problem. Thanks a whole lot. – Delupara Apr 22 '16 at 16:36
  • You're very welcome. – Gareth McCaughan Apr 22 '16 at 16:39
2

Important to say in computer memory there are no integers or pointers - only sequence of bytes. It's your program interpreting these bytes as int or int*. Outside of your program it's just bytes

Let's look at your example step by step. Suppose for the demonstration purpose you have memory of 256 bytes and your ints are only 1 byte:

step 1: where you are declaring and assigning a variable

program:
int x = 1;
...

say your compiler decided to allocate memory cell 12 for the variable x:

memory |address:value| (value of X means unknown): 
|0:X|1:X|2:X| ... |12:1| ... |255:X|

step 2: where you are declaring the pointer

program:
int x = 1;
int *p;
...

recall step 1 ... and compiler allocated memory cell 5 for variable p (note - p is not initialized yet so the value in the cell 5 is X!):

memory |address:value| (value of X means unknown): 
|0:X|1:X|2:X| ... |5:X| .. |12:1| ... |255:X|

step 3: where you are assigning the pointer

program:
int x = 1;
int *p;
p = &x;
...

recall step 2 ... and now cell p stores pointer to x. we know cell 12 has been allocated for x, hence 12 is stored into p (cell 5):

memory |address:value| (value of X means unknown): 
|0:X|1:X|2:X| ... |5:12| .. |12:1| ... |255:X|

step 4: where you are declaring the second pointer

program:
int x = 1;
int *p;
p = &x;
int *p2;
...

recall step 3 ... and your compiler allocated memory cell 6 for the variable p2 (it's unassigned yet so the value is X):

memory |address:value| (value of X means unknown): 
|0:X|1:X|2:X| ... |5:12|6:X| .. |12:1| ... |255:X|

step 5: where you are assigning the second (still undefined!) pointee:

program:
int x = 1;
int *p;
p = &x;
int *p2;
*p2 = *p;
...

recall step 4 and then *p makes compiler recall that p is cell 5 so it generates insruction to read from cell 5 (there is value 12) and use that value as an address of an actual result: reading from cell 12 returns 1. Now compiler knows that name p2 has been given to cell #6 p2 is 6, but *p2 means you need to read the value of p2 and use it as address of the actual storage. But in our case this value is X (undefined)! However in the actual memory chips there is no undefined values and something has been store there at boot time (say value 42). Things become more complicated if virtual memory is affected but i do not want to discuss it here. So let's say electrical charges and cosmic rays at boot time initialized this cell to a random value of 42. Let's see what will happen when *p2 = *p will be executed: we've seen how *p returned us 1, now program will try to find where to store it to. it will read value of p2 which yields 42, now program will store 1 to the memory cell 42 and the result will look:

memory |address:value| (value of X means unknown): 
|0:X|1:X|2:X| ... |5:12|6:X| .. |12:1| ... |42:1| ... |255:X|

in real world however using uninitialized value would frequently lead to a crash. When virtual memory involved some areas of address space (our 256 addresses) may have no memory cells allocated for them and writing to such an address would lead to crash.

step 6: where you are assigning the second pointer and make it defined pointing again to x:

program:
int x = 1;
int *p;
p = &x;
int *p2;
p2 = p;
...

recall step 4 and ignore step 5 which caused your program crash ... now compiler knows which cells are used for both p (cell 5) and p2 (cell 6). hence assignment p2=p works this way: take value from p (which is 12), do not interpret it as pointer but just copy it to p2 instead. Now p2 becomes initialized with the pointer to x (cell 12).

memory |address:value| (value of X means unknown): 
|0:X|1:X|2:X| ... |5:12|6:12| .. |12:1| ... |42:X| ... |255:X|

step 7: where you are assigning pointer to unnamed location:

program:
int x = 1;
int *p;
p = &x;
int *p2;
p2 = (int*)100;
...

... let's focus on this line: p2 = (int*)100; this shows how to assign pointer to point to an unnamed memory cell. Recall that compiler didn't assign a name yet to cell #100. But what if you know for sure there is something interesting at this memory location, for example a computer device is communicating with us via that cell. What if the keyboard stores the next character to memory cell #100 and we would like to read it? Now you can read it as *p2:

memory |address:value| (value of X means unknown): 
|0:X|1:X|2:X| ... |5:12|6:100| .. |12:1| ... |42:X| ... |100:keyboard| ... |255:X|

step 8: where you are revealing relation of pointers to arrays:

program:
int x = 1;
int *p;
p = &x;
int a[5];
a[2]=18;
int *p2 = a;
p2[2]=3;
...

... let's focus on this line: int a[5];: this declaration line tells compiler to allocate 5 cells and use name a for them. And compiler allocated cells 7, 8, 9, 10, 11 for a:

memory |address:value| (value of X means unknown): 
|0:X|1:X|2:X| ... |5:12|6:100|7:X|8:X|9:X|10:X|11:X|12:1| ... |42:X| ... |100:keyboard| ... |255:X|

note that it didn't allocate a pointer -- a would be used literally like any other variable! This is how a[2]=18 works: first compiler knows that a starts and 7, so it uses that value as a start, then it adds 2 to get 9. So the target storage cell is found - it's the cell number 9, so it store 18 into that cell:

|0:X|1:X|2:X| ... |5:12|6:100|7:X|8:X|9:18|10:X|11:X|12:1| ... |42:X| ... |100:keyboard| ... |255:X|

so let's see how int *p2 = a; works: the compiler knows that a starts at 7. Hence 7 is stored into p2 (recall the cell #6 has been allocated to p2 at step 4)

|0:X|1:X|2:X| ... |5:12|6:7|7:X|8:X|9:18|10:X|11:X|12:1| ... |42:X| ... |100:keyboard| ... |255:X|

after initializing a pointer you can use it as an array p2[2]=3;: this is short for *(p2 + 2) = 3. value of p2 is 7, adding 2 gives 9, so we are storing 3 to cell #9:

|0:X|1:X|2:X| ... |5:12|6:7|7:X|8:X|9:3|10:X|11:X|12:1| ... |42:X| ... |100:keyboard| ... |255:X|

Sorry for such a long explanation i tried to cover relations between values, variables, pointers and arrays and most use cases for these.

fukanchik
  • 2,811
  • 24
  • 29
0

I think it helps to remember that pointers are simply integers themselves. So when you create a pointer, it's really just an offset number into memory. The type of a pointer just tells the compiler how to interpret the data when the pointer is dereferenced. So when you do something like this:

int *p = &x;

You are just assigning an integer to p that is the memory address (offset) of x. In a sense, all pointers really have the same "type", they are either 32 or 64 bit integers, depending on the architecture. Dereferencing a pointer like this:

int y = *p;

Just means "offset into memory by p bytes, and give me the value there in the form of an int (which is 4 bytes)". The type of a pointer just tells the compiler how to read the data out of memory after the offset.

  • That does help considering I've done mem manipulation in the past, thanks for this. – Delupara Apr 22 '16 at 16:19
  • One very important word of caution about this: C lets you do arithmetic involving pointers, and for that purpose if you think about them as integers representing machine addresses you will sometimes get the wrong answer. Why? Because e.g. if `p` is a pointer-to-`int` then `p+1` means "one `int` further along in memory than `p`", which on a typical machine actually means adding 4 to the address because `int`s are usually 4 bytes in size. (Though 2 bytes and 8 bytes are not un-heard-of.) – Gareth McCaughan Apr 22 '16 at 16:27
  • Similarly, if `p` and `q` are pointers-to-`int` (strictly, they'd better also be within a single array or `malloc`ed block of memory) then `q-p` is measured in units of the size of an `int`, not in bytes. So e.g. if you say `int x[10]; p=&x[1]; q=&x[3];` then `p` might be 0x23006C, `q` might be 0x230074`, and `q-p` would be 2 (and not 8). – Gareth McCaughan Apr 22 '16 at 16:29
  • I think it's actually whatever the size of the pointer is, If it's a pointer to a char, p+1 would be simply +1, since chars are a byte long. well, to be more specific it's `sizeof(type)` more whenever you change the address. – Delupara Apr 22 '16 at 16:37