Read Sams Teach Yourself C in 24 Hours Online
Authors: Tony. Zhang
15 067231861x CH11 1/25/00 10:16 AM Page 177
Understanding Pointers
177
Then, when the variable is assigned a value, the value is stored into the reserved memory location as the content. The content is also called the
right value
of the variable.
For instance, after the integer variable x is declared and assigned to a value like this: int x;
x = 7;
the variable x now has two values:
Left value: 1000
Right value: 7
Here the left value, 1000, is the address of the memory location reserved for x. The right value, 7, is the content stored in the memory location. Note that depending on computers and operating systems, the left value of x can be different from one machine to another.
You can imagine that the variable x is the mailbox in front of your house, which has the address (normally the street number) 1000. The right value, 7, can be thought of as a letter delivered to the mailbox.
Note that when your C program is being compiled and a value is being assigned to a
11
variable, the C compiler has to check the left value of the variable. If the compiler cannot find the left value, it will issue an error message saying that the variable is undefined in your program. That’s why, in C, you have to declare a variable before you can use it.
(Imagine a letter carrier complaining that he or she cannot drop the letters addressed to you because you haven’t built a mailbox yet.)
By using a variable’s left value, the C compiler can easily locate the appropriate memory storage reserved for a variable, and then read or write the right value of the variable.
The Address-of Operator (
&
)
The C language even provides you with an operator, &, in case you want to know the left value of a variable. This operator is called the
address-of operator
because it evaluates to the address (that is, the left value) of a variable.
The following code, for example,
long int x;
long int *y;
y = &x;
assigns the address of the long integer variable x to a pointer variable, y. (More on this and the significance of *y will be discussed later in this chapter.)
15 067231861x CH11 1/25/00 10:16 AM Page 178
178
Hour 11
Listing 11.1 shows another example of obtaining addresses (that is, left values) of variables.
TYPE
LISTING 11.1
Obtaining the Left Values of Variables
1: /* 11L01.c: Obtaining addresses */
2: #include
3:
4: main()
5: {
6: char c;
7: int x;
8: float y;
9:
10: printf(“c: address=%p, content=%c\n”, &c, c);
11: printf(“x: address=%p, content=%d\n”, &x, x);
12: printf(“y: address=%p, content=%5.2f\n”, &y, y);
13: c = ‘A’;
14: x = 7;
15: y = 123.45;
16: printf(“c: address=%p, content=%c\n”, &c, c);
17: printf(“x: address=%p, content=%d\n”, &x, x);
18: printf(“y: address=%p, content=%5.2f\n”, &y, y);
19: return 0;
20: }
After the executable file (11L01.exe) of this program is created and run on my computer, the following output is displayed on the screen:
You might get different result, depending on your computer and operating system, and especially depending on the memory situation in your computer when you’re running the program.
c: address=0x1AF4, [email protected]
OUTPUT
x: address=0x1AF2, content=-32557
y: address=0x1AF6, content=0.00
c: address=0x1AF4, content=A
x: address=0x1AF2, content=7
y: address=0x1AF6, content=123.45
As you can see in Listing 11.1, there are three variables, c, x, and y, declared in
ANALYSIS
lines 6–8, respectively.
15 067231861x CH11 1/25/00 10:16 AM Page 179
Understanding Pointers
179
The statement in line 10 displays the address (that is, the left value) and the content (that is, the right value) of the character variable c on the screen. Here the &c expression produces the address of c.
Note that the format specifier %p is used in the printf() function of line 10 for displaying the address produced by &c.
Likewise, lines 11 and 12 print out the addresses of x and y, as well as the contents of x and y. From the first part of the output, you see that the addresses of c, x, and y are 0x1AF4, 0x1AF2, and 0x1AF6. My computer printed these addresses in hex format.
However, the %p format specifier does not guarantee to print the addresses in hex format, just to convert the addresses to a sequence of printable characters. You should consult the manual for your C compiler to see what format to expect. Because these three variables have not been initialized yet, the contents contained in their memory locations are left there from the last memory writing.
However, after the initializations that are carried out in lines 13–15, the memory slots reserved for the three variables have the contents of the initial values. Lines 16–18 display the addresses and contents of c, x, and y after the initialization.
You can see in the second part of the output, the contents of c, x, and y are now ‘A’, 7,
11
and 123.45, respectively, with the same memory addresses.
The format specifier %p used in the printf() function is supported by the ANSI standard. If, somehow, your compiler does not support %p, you can try to use %u or %lu in the printf() function to convert and print out a left value (that is, an address).
Also, the addresses printed out by the examples in this lesson are obtained by running the examples on my machine. The values may be different from what you can get by running the examples on your machine. This is because the address of a variable may vary from one type of computer to another.
Declaring Pointers
As mentioned at the beginning of this lesson, a pointer is a variable, which means that a pointer has a left value and a right value as well. However, both the left and right values are addresses. The left value of a pointer is used to refer to the pointer itself, whereas the right value of a pointer, which is the content of the pointer, is the address of another variable.
15 067231861x CH11 1/25/00 10:16 AM Page 180
180
Hour 11
The general form of a pointer declaration is
data-type
*pointer-name;
Here data-type specifies the type of data to which the pointer points. pointer-name is the name of the pointer variable, which can be any valid variable name in C.
Note that right before the pointer name is an asterisk *, which indicates that the variable is a pointer. When the compiler sees the asterisk in the declaration, it makes a note that the variable can be used as a pointer.
The following shows different types of pointers:
char *ptr_c; /* declare a pointer to a character */
int *ptr_int; /* declare a pointer to an integer */
float *ptr_flt; /* declare a pointer to a floating-point */
The program in Listing 11.2 demonstrates how to declare pointers and assign values to them.
TYPE
LISTING 11.2
Declaring and Assigning Values to Pointers
1: /* 11L02.c: Declaring and assign values to pointers */
2: #include
3:
4: main()
5: {
6: char c, *ptr_c;
7: int x, *ptr_x;
8: float y, *ptr_y;
9:
10: c = ‘A’;
11: x = 7;
12: y = 123.45;
13: printf(“c: address=%p, content=%c\n”, &c, c);
14: printf(“x: address=%p, content=%d\n”, &x, x);
15: printf(“y: address=%p, content=%5.2f\n”, &y, y);
16: ptr_c = &c;
17: printf(“ptr_c: address=%p, content=%p\n”, &ptr_c, ptr_c); 18: printf(“*ptr_c => %c\n”, *ptr_c);
19: ptr_x = &x;
20: printf(“ptr_x: address=%p, content=%p\n”, &ptr_x, ptr_x); 21: printf(“*ptr_x => %d\n”, *ptr_x);
22: ptr_y = &y;
23: printf(“ptr_y: address=%p, content=%p\n”, &ptr_y, ptr_y); 24: printf(“*ptr_y => %5.2f\n”, *ptr_y);
25: return 0;
26: }
15 067231861x CH11 1/25/00 10:16 AM Page 181
Understanding Pointers
181
I get the following output displayed on the screen after running the executable file 11L02.exe from on my machine:
c: address=0x1B38, content=A
OUTPUT
x: address=0x1B36, content=7
y: address=0x1B32, content=123.45
ptr_c: address=0x1B30, content=0x1B38
*ptr_c => A
ptr_x: address=0x1B2E, content=0x1B36
*ptr_x => 7
ptr_y: address=0x1B2C, content=0x1B32
*ptr_y => 123.45
In Listing 11.2, there are three variables, c, x, and y, and three pointer variables,
ANALYSIS
ptr_c, ptr_x, and ptr_y, declared in lines 6–8, respectively.
The statements in lines 10–12 initialize the three variables c, x, and y. Then, lines 13–15
print out the addresses as well as the contents of the three variables.
In line 16, the left value of the character variable c is assigned to the pointer variable ptr_c. The output made by the statement in line 17 shows that the pointer variable ptr_c contains the address of c. In other words, the content (that is, the right value) of ptr_c is the address (that is, the left value) of c.
11
Then in line 18, the value referred to by the pointer *ptr_c is printed out. The output proves that the pointer *ptr_c does point to the memory location of c.
Line 19 assigns the left value of the integer x to the integer pointer variable ptr_x. The statements in lines 20 and 21 print out the left value and right value of the pointer variable ptr_x, as well as the value referred to by the pointer *ptr_x.
Similarly, the left value of the float variable y is assigned to the float pointer variable ptr_y in line 22. To prove that ptr_y contains the address of y, and *ptr_y gives the content held by y, lines 23 and 24 print out the right values of ptr_y and *ptr_y, respectively.
The statements in lines 16, 19, and 22 show you how to assign the value of one variable to another—in an indirect way. In other words, the left value of a variable can be assigned to another variable so that the latter can be used as a pointer variable to obtain the right value of the former. In this case, the variable name and the pointer refer to the same memory location. Accordingly, if either the variable name or the pointer is used in an expression to change the contents of the memory location, the contents of the memory location have also changed for the other.
To help you understand the indirection of assigning values, Figure 11.1 demonstrates the memory image of the relationships between c and ptr_c, x and ptr_x, and y and ptr_y, based on the output obtained on my machine.
15 067231861x CH11 1/25/00 10:16 AM Page 182
182
Hour 11
FIGURE 11.1
.
.
The memory image of
.
variables and their
ptr_y
0x1B2C
pointers.
0x1B32
ptr_x
0x1B2E
0x1B36
ptr_c
*ptr_y
0x1B30
0x1B38
y
0x1B32
*ptr_x
123.45
x
0x1B36
7
*ptr_c
c
0x1B38
‘A’
.
.
.
The Dereference Operator (
*
)
You’ve seen the asterisk (*) in the declaration of a pointer. In C, the asterisk is called the
dereference operator
when it is used as a unary operator. (Sometimes, it’s also called the
indirection operator
.) The value of a variable can be referenced by the combination of the * operator and its operand, which contains the address of the variable.
For instance, in the program shown in Listing 11.2, after the address of the character variable c is assigned to the pointer variable ptr_c, the expression *ptr_c refers to the value contained by c. Therefore, you can use the *ptr_c expression, instead of using the variable c directly, to obtain the value of c.
Likewise, given an integer variable x and x = 1234, you can declare an integer pointer variable, ptr_x, for instance, and assign the left value (address) of x to ptr_x—that is, ptr_x = &x. Then, the expression *ptr_x produces 1234, which is the right value (content) of x.
Don’t confuse the dereference operator with the multiplication operator, although they share the same symbol, *.
The
dereference operator
is a unary operator, which takes only one operand. The operand contains the address (that is, left value) of a variable.
On the other hand, the
multiplication operator
is a binary operator that requires two operands to perform the operation of multiplication.
The meaning of the * symbol is determined by the context in which you use it.
15 067231861x CH11 1/25/00 10:16 AM Page 183
Understanding Pointers
183
Null Pointers
A pointer is said to be a
null pointer
when its right value is 0. Remember, a null pointer can never point to valid data. For this reason, you can test a pointer to see if it’s assigned to 0; if it is, you know that it is a null pointer and isn’t valid.
To set a null pointer, simply assign 0 to the pointer variable. For example: char *ptr_c;
int *ptr_int;
ptr_c = ptr_int = 0;
Here ptr_c and ptr_int become null pointers after the integer value of 0 is assigned to them.
You’ll see applications of null pointers used in control-flow statements and arrays later in this book.
Updating Variables via Pointers
As you learned in the previous section, as long as you link up a variable to a pointer vari-11
able, you can obtain the value of the variable by using the pointer variable. In other words, you can read the value by pointing to the memory location of the variable and using the dereferencing operator.