When we create and declare a variable, for example:
int i = 77;
The compiler assigns an address to that variable. i will be stored at one specific address in computer’s memory system. The computer memory is normally Random Access memory (RAM). Which part of the RAM will be used to store the variable and other things declared and used in programs determined by the compiler and depending on the addressing mode used by processor. You can get the detail story for C/C++ compiler in Module W andModule Buffer overflow and see how the C/C.++ program elements stored in different part of the memory area. To understand the addressing used, you need to learn about the microprocessor and it is not in our scope of discussion.
It doesn’t matter whether it is variable or other C/C++ element, the most important thing here when you declare a variable, memory storage with address is reserved for it. The memory address is fixed and also depends on the installed size but the data place in the variable can be changed from time to time during the execution. For the above C/C++ statement, data is placed in i temporarily and may be used later, during the program execution.
Here, it can be concluded that the name of the variable and itsaddress is fixed once the program starts executing, but its contents may change. In programming or computer system the memory address normally represented by hexadecimal number. For example you already used the& (address-of operator) to display variable’s address and to store data in the specified variable (such as in scanf()/scanf_s()).
|
For 32 bits system the 0012FF60 hexadecimal will be converted to 32 bits binary (onehex character represented by 4 binary digits).
Just as we can create variables that store integers, characters and floats, we can also create variables that store the memory addresses of other variables. Variables that store memory addresses instead of the actual data or values are called pointers. An example of the pointer variable is shown below.
int i, *p;
Here we have created two variables i and p. The similarity between them is that they both have something to do with integers. The difference between them, seen by the asterisk, is that i stores integer values, whereas p stores addresses of integers’ locations. You can store a 60 in i, but not in p. Similarly, you can store the address of i in p, but not the address of an integer in i.Integer variables store integer values and integer pointers store the addresses of integers. Both of the following statements are legal:
i = 60; // storing an integer value
p = &i // storing an address of an integer variable
Let depict the previous statements in graphical manner.
In the Figures, (a) shows that when the variables are created, i is stored at location AD1A04 and p is stored at location AD1A05. In (b) 60 is assigned to i, and in (c) the address of i, which is AD1A04 is assigned to p.
We can also define pointer variables that store addresses to other data types, such as the following:
char a[1], *pa;
float x, *px;
Here pa, can store addresses to character data types and px can store addresses to floats. Other combinations are not allowed. Here, both are correct.
pa = &a[0]; // storing a character address in a character pointer.
px = &x; // storing a float address in a float pointer
However the following statements are not legal.
pa = &x; // pa is not a pointer variable for floats.
px = 3.40; // px cannot store floating point values!
Pointer Arithmetic
int i, *p;
Arrays And Pointers Relation
int *p, j[ ] = {2, 6, 3, 7, 4};
|
However pointer constant cannot be changed.
The integer array is initialized with each slot and the initialization requires two bytes. When we execute this statement:
p = &j[2];
The value of p becomes 1A06, the address of j[2]. We can change the value of p because it is a pointer variable, but we can’t change the value of j, a pointer constant. Notice that the value of p is an address, whereas the value of j[0] is an integer. If we do this:
p = p + 1;
Then the value of p will become 1A08 and if we do this:
p = j + 1;
Then the value of p will become 1A04 because j is fixed at 1A02. However, we can’t change j like:
j = j + 1; // not legal
Because j is an array and arrays are pointer constants.
Create an empty Win32 console application project named mypointer. Add a C++ source file named mypointersrc. Set your project compiled as a C code. Build and run the following code.
#include<stdio.h>
// function prototype void ReadArr(int *x, int y);
void main(void) { // p used to store addresses for array j[ ]. int i, j[5], *p; // q used to store addresses for array x[ ] float x[5], *q = &x[0]; // printing out the addresses of the two arrays. p = &j[0]; // line 1 for(i = 0; i <= 4; ++i) printf("Addresses of j[%d] = %p\tAddresses of x[%d] = %p \n", i, p + i, i, &q[i]); // reading numbers into the integer array. printf("\nEnter 5 integers\n"); // for older compiler may use scanf("%d", &j[4]); etc // notice there is no & scanf_s("%d", &j[4], 4); scanf_s("%d", j, 1); scanf_s("%d", j + 1, 1); // j can't change and it hasn't p = &j[1]; // same as p = j + 1; p = p + 1; // notice there is no & scanf_s("%d", p, sizeof(int)); ReadArr(j, 3); // print the array printf("The array is: \n"); for(i = 0; i <= 4; ++i) printf("j[%d] = %d ", i, j[i]); printf("\n"); }
// function definition, to read a number into x[y] // receive a pointer integer and integer arguments // return nothing... void ReadArr(int *x, int y) { x = x + y; scanf_s("%d", x, 1); } |
The loop varies i from 0 to 4. In each iteration, it prints the address of the next slot in each of the two arrays. It does this by printing the value of p, which has the address of j[ ] and adding i to it each time. The addresses of the q[ ] array are printed by printing &q[i]. This gives the address of each slot. Notice that in the output, the addresses of the integer array go up by two and that of the float array go up by 4. On your computer the storage unit of each data type and the actual addresses may be different for example if you use and compile on 64 bits machine.
Next, the program uses different ways of specifying the address of each slot in the j[ ] array. The addresses are passed to the scanf_s() function to read in values in the array slots. First, we read 4 intoj[4] by passing &j[4]. Then a 2 is read into j[0] because j is passed to scanf_s().j is the same as &j[0]. Similarly, j + 1 is passed to scanf_s() which is really&j[ ]. This reads in j[1]. Notice that you can add 1 to j, which will evaluate the expression to 1A04 as in the previous Figure. However, you can’t change j to that.
Now, the address of j[1] is stored in p, which is changed to p + 1 because p is a pointer, unlike j, which is a pointer constant. Since p contains the address of j[1], 3 is read into that slot. Last, j and 3 are passed to the function ReadArr(). The address given by j is now assigned to the pointer variable x. We could not change j in main(), but here, x is a variable and so it can be changed. y is 3, so storage units are added to 1A02 and x becomes 1A08. Reading a 7 at this address places the 7 inj[3]. Finally the program prints the array to show its contents.
More Pointers Practice
#include<stdio.h>
void main(void) { int i = 7, j = 11; printf("i = %d, j = %d\n", i, j); printf("&i = %p, &j = %p\n", &i, &j); }
As you may recall, each variable has a data type, name, value and address associated with it. In the following Figure, inside the boxes, under the label of “value”, show the values ofi and j. Likewise, on the lines under the label marked “Address”, show the addresses of i and j in RAM from your output.
|
------------------------------------------------------
|
|
|
#include<stdio.h>
void main(void) { int i = 7, j = 11; printf("i = %d, j = %d\n", i, j); printf("&i = %p, &j = %p\n", &i, &j); // reassign new values... i = 4; j = 5; // reprint... printf("\ni = %d, j = %d\n", i, j); printf("&i = %p, &j = %p\n", &i, &j); }
|
|
|
|
#include<stdio.h>
void main(void) { int i = 7; // Statement 1 int *pOne; // Statement 2 float x = 0.00; printf("&i = %p \n", &i); pOne = &i; // Statement 3 printf("pOne = %p\n", pOne); }
pOne = 4;
pOne = &x;
printf("&pOne = %p\n", &pOne); |
We can assign addresses or an integer to pOne.
However assigning an integer to pOne has no valuable purpose in programming because we don't know what is stored at the address and programming wise it is illegal.
|
|
|
| |
#include<stdio.h>
void main(void) { char a ='Q', *pa; // the F modifier force the value to float // else by default it is a double float x = 7.3F, *px; int i = 2, *m; pa = &a; px = &x; m = &i; printf("pa = %p\npx = %p\n m = %p\n", pa, px, m); }
pa = &x; pa = &i;
pa = 'Q';
&a = 4440;
px = &a; px = &i;
m = &a; m = &x;
|
|
#include<stdio.h>
void main(void) { char a ='Q', b = 'X', *pa, *pb; pa = &a; // Statement 1 pb = pa; // Statement 2 printf("pa = %p, pb = %p\n", pa, pb); // Statement 3 pa = &b; printf("pa = %p, pb = %p\n", pa, pb); }
|
|