Contributor's Corner

A collection of hopefully helpful information
Functionality Clarity Elegance

Pointers


How Pointers Work

Consider the following code. When you name your variables, whether they're pointers or integers or whatever, the name is a mnemonic, an alias, for a memory address. A convict and his number are irretrievably linked, but the number is not the convict, and is cheaper to feed. Suppose you write these statements:

int iValue = 25; 
int *pIntOne; 
int *pIntTwo = iNumber; 
pIntOne = &iValue; 
int iCopy; 

The first statement will cause the compiler to set aside for you a memory location large enough to hold an integer value. It will also initialize the memory with the value, 25. Nice compiler. The memory set aside for you may live in one place or another, depending upon the context, but you know where it is in a useful way because you named it and the name is an alias for a numerical location in your memory area.

The second statement will cause the compiler to set aside enough memory to hold a pointer. It is not initialized; it contains nothing useful. There are many for whom this will be a surprise. When they declare a pointer, they expect it to automagically generate an object to point to (a mate, the other half of the pair mentioned in the beginning) as well as a value for itself that points there. These people have a predictable and recurring agenda: they write code, compile it, run it, then log on to a forum and post a question asking why they got a segmentation fault or core dump. Possibly there's a reboot before that final step. This code,

char *buffer; 
scanf ("%s", buffer); 
(or any other character-transfer mechanism you care to substitute for 'scanf') is a common, and often fatal (to the program) error. If it were fatal to the programmer, the average competency-level would be rising by the minute.

The third statement will cause a problem. iNumber has not been defined at this point. If one could actually get away with the declaration, it would constitute a likely path through a hatchet fight. Presumably your compiler will gripe and you won't actually have to walk through the fight. This statement looks okay on the surface. After all, It meets the requirements of having two things in a pointer-object relationship. The relationship is a lie. The second thing doesn't exist.

The next statement stores a value in pIntOne. The value is the address of the variable, iValue. It is not the value of iValue. It is merely a reference. The final statement sets aside additional memory for another value, but stores no meaningful value there. Assuming 32-bit integers, 32-bit pointers, and memory for our declarations beginning at hex address 0x1000, the memory will look like this:

0x1000: iValue  contents: 25 
0x1004: pIntOne contents: 0x1000 
0x1008: pIntTwo contents: unknown, junk 
0x100c: iCopy   contents: unknown, junk 
The programmer that uses pIntTwo at this point is going to be down in the ditch by himself with a pick and no date. The programmer that tries to store an int to pIntTwo is also going to be in trouble. One may force the issue by casting and place any value, say 37, there. If one then uses that as a pointer, it will be referring to the contents at address 37, which may very well not be usable memory. It may be off-limits. Possibly, it doesn’t even exist. Your program will trot off into the woods and be breakfast for a bear. You will be introduced to the segmentation fault, the core-dump, the dreaded blue screen of death.

The value of pIntOne (yes it holds a value) is 0x1000. "pIntTwo = pIntOne" will assign the value, 0x1000, to pIntTwo, not the value 25. To use the 25 pointed to by pIntOne, one must 'dereference' it. One does this with the indirection operator, '*' (and sometimes the '->' operator, which is not discussed here). pIntOne has the value, 0x1000. *pIntOne has the value, 25 (the value in memory location 0x1000). "pIntTwo = pIntOne" (notice pIntOne isn't dereferenced here) assigns the value, 0x1000, found in pIntOne, to pIntTwo. "iCopy = *pIntTwo" (notice the dereference operator) assigns the value, 25, found at the location referred to by pIntTwo, not in pIntTwo, to iCopy.

Of course, we could have written directly into the variable, so what good is a pointer, you ask? On occassion, one may need to write to a variable whose location is not known until runtime. Perhaps it has been dynamically allocated in response to changing conditions, and the only reference we have to it is a pointer. Thanks to our pointer conduit, memory now looks like this:

0x1000: iValue   contents: 25 
0x1004: pIntOne  contents: 0x1000  
0x1008: pIntTwo  contents: 0x1000  
0x100c: iCopy    contents: 25  

 What is a pointer?Confustoids