<what_I_have_tried>
- Looking at the suggestion list.
- In Google: how not to use pointers c (idea: is it an idea to summarize all ways pointer declaration, assignment and use could go wrong in a SO question? I know it would be helpful for me, since I'm trying to understand pointers by searching edge cases in order to see if I understand all the concepts)
- In Google: errors from pointers c
- In SO: int to int*
- Read a bunch of general stuff on pointers. I view
*
as a dereference operator. I used to view*
as a sort of 'second variable' and saw a pointer as a 'macro variable' (e.g.*a
and b are parts ofa
'macro variable'). This is completely wrong. Now I viewint *a
as one variable (just likeint b
), which is accessed by typinga
and*
is an operator. Interestingly, one small idea I have then is that you cannot dereference a pointer at the moment you declare it, since the*
is then part of the type declaration (e.g.int *p
is a pointer declaration. Likewise,int* *q
-- confusing syntax is on purpose -- is a pointer to pointer declaration, i.e. you cannot use the dereference operator since the*
is parsed as part of the type).
</what_I_have_tried>
Here is the question. Note, I'm using edge cases to understand a concept, not to promote bad software practices. I'm testing to see to what point I understand dereferencing/referencing and pointers in general, hence I try to let C do things it probably doesn't want to do normally. Considering the following program. It's a pure beauty ;)
#include "stdio.h"
int main(void) {
int a = 0;
int b = 5;
printf("a: %d, b: %d\n", a, b);
a = &b; //bad intentions! Lets see what happens, we can cast right?
printf("a: %d, b: %d, &b: %d\n", a, b, &b);
printf("*a: %d", (*((int *)a)));
return 0;
}
The output is:
a: 0, b: 5
a: 1508416372, b: 5, &b: 1508416372
Segmentation fault: 11
My thoughts for the first 30 minutes. "How can this happen?! They have the SAME MEMORY ADDRESS!!" Excuse my screaming, but this looks rather frustrating. Before going to SO, I opened up GDB breaking at the final printf
. Compilation settings are: gcc -g -O0 test.c -o a
. The relevant GDB output is:
(gdb) p/x a
$3 = 0x5fbffb34
(gdb) p/x &b
$4 = 0x7fff5fbffb34
Wait what? The function printf
is not showing me the full output. I did not expect this.
So... to test the concept again I added 0x7fff to a. It didn't work, because adding 0x7fff to 0x5fbffb34 is not the same as appending it.
Now that I think about it, I think I have the answer. I'm running a 64 bit machine and I've been assuming that int *
and int
get the same amount of bytes allocated but it could be that it doesn't work because int *
gets 4 bytes (32 bits) or 8 bytes (64 bits) allocated -- I'm running 64 bits on Mac OSX. Is this why it doesn't work?
I'm stopping here, else I'm breaking the Q&A format I suppose. I was writing this question while debugging, so the chronology is quite preserved. I'm now going to see if I can append 0x7fff somehow since I don't have a 32-bit machine to test on.
Edit and conclusion (warning, it might be too in-depth for the earliest beginners):
With the answer in mind, I can conclude the following. In GCC pointers store memory addresses. From a non-compiler but practical perspective pointers store references to objects and functions (and in GCC that gets translated to a memory address) -- as a programmer this is as far as I need to go. I read from this question that the C standard views this even a bit more broadly.
I can also conclude that, conceptually, you can dereference whatever you want. Dereferencing, from a conceptual perspective, always works or is at the very least attempted to be executed. In the code of my question 0x5fbffb34
was attempted to be dereferenced or was even dereferenced. However, a conceptual perspective is not a practical one. In the real world, the operating system does some checks when the dereference is attempted or when the value is returned. Hence, it interfered and kills the program since the memory address was not in the boundaries of my program (that's my guess at least).
Another conclusion is that people who draw boxes with arrows when they declare and initialize a pointer are wrong. In my opinion, the arrow should only be drawn when a pointer is dereferenced. This is because the arrow is part of dereferencing a value from a memory address. A pointer (and its related type, e.g. int *
) only helps and guides to get defined behaviour. It's kind of like when you dereference a value from a pointer variable (e.g. int b = 0; int *a = &b; int c = *a;
), then you get a 'safe(ish) arrow'. When you dereference a value from a non-pointer variable, then you get a 'deadly(ish) arrow' as can be seen in my program.