Pointers in Memory |
||
To get a better understanding of what pointers are and what they do let's take a look at pointers on a very basic level. Let's look at pointers and other types of variables as they appear in memory. Memory consists of a sequential array of bytes. Each consisting of 8 bits. Each bit is like an on-off switch. Each byte therefore can have 256 different combinations of bits turned either on or off (see the page on Decimal-Hexadecimal-Binary Numbering Systems for more information.) These bytes of memory are numbered from zero and up using the hexadecimal numbering system. In figure 1 we see a portion of memory diagrammed. Lower address are at the top of the diagram. |
![]() Figure 1. Somewhere in Memory |
Now suppose you declare the following variables in main(): int ivar; double d_var; char c_var; char c_array[5]; Memory will now appear as in figure 2. Since no values have been stored yet the contents of these variables is garbage. Note: some compilers produce code that automatically sets all numerical variables to zero and clears all bytes in a character array to null terminators, i.e. byte value zero. |
![]() Figure 2. After declaring variables. |
If you execute the following code to store some values in these
variables then memory will appear as in figure 3. ivar = 16; d_var = 3.14159; c_var = 'a'; strcpy(c_array, "test"); |
![]() Figure 3. After storing values in the variables. |
Now let's see what memory looks like as we declare the same
set of variables and some pointers in main(): int ivar; double d_var; char c_var; char c_array[5]; int *i_ptr; double *d_ptr; char *c_ptr; Memory will now appear as in figure 4. |
![]() Figure 4. After declaring variables and pointers. |
Now when we execute the following code to store some values in these
variables and in the pointers memory will appear as in figure 5. ivar = 16; d_var = 3.14159; c_var = 'a'; strcpy(c_array, "test"); i_ptr = &i_var; d_ptr = &d_var; c_ptr = &c_var;
Notice that we are storing the starting memory address of the integer
variable i_var in the integer pointer variable i_ptr and the same
goes for the other pointers. We use the ampersand & as the
address operator to indicate the address of a variable in memory,
instead of the value stored in the variable. |
![]() Figure 5. After storing values in the variables and pointers. |
|
When we want to access the value stored in a variable using a pointer which stores the address of that variable we use the asterisk, '*'. This is referred to as dereferencing the pointer. printf("%d", *i_ptr); /* Print the value stored in i_var */ printf("%f", *d_ptr); /* Print the value stored in d_var */ printf("%c", *c_ptr); /* Print the value stored in c_var */ |
Using Pointers In Function Calls |
||
When you call a function you pass arguments to that function. If we consider the technical aspects of computer programming separate from the C language we find that there are two ways in which those arguments can be passed to the function. The first way of passing arguments to a function is Pass By Value. In this approach the values stores in the variables, which are arguments to the function, are copied and the copies passed to the function. The function therefore only has the values. It does not have any way of accessing or changing the variables, in the calling function, from which the values are copied. The second way of passing arguments to a function is Pass By Reference. In this approach the arguments passed to the function are "references" to the variables that are arguments. The called function can now make changes in the variables themselves. These "references" are actually the memory addresses of the variables. In C we can only Call By Value, but we can simulate the Call By Reference by passing the values stored in pointers, i.e. memory addresses of variables, into a function. |
||
If you execute the following code in main() and then call a function named ValFunc() memory accessed by main() will look like that illustrated in figure 6 int i_var;double d_var; char c_var; i_var = 16; d_var = 3.14159; c_var = 'a'; ValFunc(i_var, d_var, c_var); |
![]() Figure 6. Somewhere in Memory |
|
The declaration of the function looks like this: void ValFunc(int arg1, double arg2, char arg3){ // Just print the values cout << arg1 << endl; // print i_var cout << arg2 << endl; // print d_var cout << arg3 << endl; // print c_var } When you call the function, somewhere else in memory another set of variables (the arguments to the function) will be created and the values which were passed into the function copied into those variables. This is illustrated in figure 7. |
![]() Figure 7. Somewhere else in Memory |
To Call By Reference in C we need to pass the addresses of variables as arguments to a function. If you execute the following code in main() then call the function RefFunc() you will be "calling by reference." The arrangement of memory accessed by main() is illustrated in figure 8 int i_var;double d_var; char c_var; int *i_ptr; double *d_ptr; char *c_ptr; i_var = 16; d_var = 3.14159; c_var = 'a'; i_ptr = &i_var; d_ptr = &d_var; c_ptr = &c_var; Now you can call the function RefFunc() in either of two ways. Both, calls pass the addresses of the variables i_var, d_var, and c_var to the function. In the first call the actual addresses of the variables are passed. In the second call the addresses stored in the pointers are passed. RefFunc(&i_var, &d_var, &c_var); RefFunc(i_ptr, d_ptr, c_ptr); |
![]() Figure 8. Somewhere in Memory |
|
The declaration of the function looks like this: void RefFunc(int *arg1, double *arg2, char *arg3){ // Just print the values in the variables pointed to cout << *arg1 << endl; // print i_var cout << *arg2 << endl; // print d_var cout << *arg3 << endl; // print c_var } When you call the function, somewhere else in memory another set of variables (the arguments to the function) will be created and the values which were passed into the function copied into those variables. In this case the "values" being stored are addresses and they are being stored in pointer variables. This is illustrated in figure 9. |
![]() Figure 9. Somewhere else in Memory |
|
While you have to "fake" the Call by Reference in C by passing
in to the functions pointers to variables, in C++ you can create an actual
Call by Reference function. The declaration of the function looks
like this: Using the variables declared above this function can be called with this statement: RefFuncCPP(i_var, d_var, c_var);When you call the function the arguments arg1, arg2, and arg3 actually become "aliases" for the variable names so values can be placed directly into the function arguments like this: arg1 = 32; // store 32 in i_vararg2 = 2.5; // store 2.5 in d_var arg3 = 'z'; // store 'z' in c_var |
  |   |
You can also perform some arithmetic manipulation of pointers. Consider the following code:
int *ptr; /* Declare a pointer to an integer */ int tab[5] = {50, 25, 10, 5, 1}; /* Declare and initialize an array of 5 ints */ ptr = tab; /* Set the pointer pointing to the first int in the array */ printf("%d", *ptr); /* Print the value stored in the first integer of the array.*/ printf("%d", *(ptr+1)); /* Print the value stored in the second integer of the array.*/ /* Print all integers in the array */ for(i=0; i<5; i++) printf("%d", *(ptr+i)); ptr++; /* Increment ptr to point to the next integer in the tab array */