Pointer Expressions. McGraw-Hill The Complete Reference Fourth Edition
Reklama
Reklama
116
C + + : T h e C o m p l e t e R e f e r e n c e
Both & and * have a higher precedence than all other arithmetic operators except the unary minus, with which they are equal.
You must make sure that your pointer variables always point to the correct type of data. For example, when you declare a pointer to be of type int, the compiler assumes that any address that it holds points to an integer variable—whether it actually does or not. Because you can assign any address you want to a pointer variable, the following program compiles without error, but does not produce the desired result:
#include <stdio.h> int main(void)
{ double x = 100.1, y; int *p;
/* The next statement causes p (which is an integer pointer) to point to a double. */ p = (int *)&x;
/* The next statement does not operate as expected. */ y = *p;
} printf("%f", y); /* won't output 100.1 */ return 0;
This will not assign the value of x to y. Because p is declared as an integer pointer, only 4 bytes of information (assuming 4-byte integers) will be transferred to y, not the 8 bytes that normally make up a double.
In C++, it is illegal to convert one type of pointer into another without the use of an explicit type cast. In C, casts should be used for most pointer conversions.
Pointer Expressions
In general, expressions involving pointers conform to the same rules as other expressions. This section examines a few special aspects of pointer expressions.
C h a p t e r 5 : P o i n t e r s
117
Pointer Assignments
As with any variable, you may use a pointer on the right-hand side of an assignment statement to assign its value to another pointer. For example,
#include <stdio.h> int main(void)
{ int x; int *p1, *p2; p1 = &x; p2 = p1; printf(" %p", p2); /* print the address of x, not x's value! */
} return 0;
Both p1 and p2 now point to x. The address of x is displayed by using the %p printf( ) format specifier, which causes printf( ) to display an address in the format used by the host computer.
Pointer Arithmetic
There are only two arithmetic operations that you may use on pointers: addition and subtraction. To understand what occurs in pointer arithmetic, let p1 be an integer pointer with a current value of 2000. Also, assume integers are 2 bytes long.
After the expression p1++;
p1
contains 2002, not 2001. The reason for this is that each time p1 is incremented, it will point to the next integer. The same is true of decrements. For example, assuming that p1 has the value 2000, the expression p1--; causes p1 to have the value 1998.
Generalizing from the preceding example, the following rules govern pointer arithmetic. Each time a pointer is incremented, it points to the memory location
118
C + + : T h e C o m p l e t e R e f e r e n c e of the next element of its base type. Each time it is decremented, it points to the location of the previous element. When applied to character pointers, this will appear as "normal" arithmetic because characters are always 1 byte long. All other pointers will increase or decrease by the length of the data type they point to. This approach ensures that a pointer is always pointing to an appropriate element of its base type. Figure 5-2 illustrates this concept.
You are not limited to the increment and decrement operators. For example, you may add or subtract integers to or from pointers. The expression p1 = p1 + 12; makes p1 point to the twelfth element of p1's type beyond the one it currently points to.
Besides addition and subtraction of a pointer and an integer, only one other arithmetic operation is allowed: You may subtract one pointer from another in order to find the number of objects of their base type that separate the two. All other arithmetic operations are prohibited. Specifically, you may not multiply or divide pointers; you may not add two pointers; you may not apply the bitwise operators to them; and you may not add or subtract type float or double to or from pointers.
Figure 5-2.
All pointer arithmetic is relative to its base type (assume 2-byte integers)
C h a p t e r 5 : P o i n t e r s
119
Pointer Comparisons
You can compare two pointers in a relational expression. For instance, given two pointers p and q, the following statement is perfectly valid: if(p<q) printf("p points to lower memory than q\n");
Generally, pointer comparisons are used when two or more pointers point to a common object, such as an array. As an example, a pair of stack routines are developed that store and retrieve integer values. A stack is a list that uses first-in, last-out accessing. It is often compared to a stack of plates on a table—the first one set down is the last one to be used. Stacks are used frequently in compilers, interpreters, spreadsheets, and other system-related software. To create a stack, you need two functions: push( ) and pop( ). The push( ) function places values on the stack and pop( ) takes them off. These routines are shown here with a simple
main( )
function to drive them. The program puts the values you enter into the stack.
If you enter 0, a value is popped from the stack. To stop the program, enter 1.
#include <stdio.h>
#include <stdlib.h>
#define SIZE 50 void push(int i); int pop(void); int *tos, *p1, stack[SIZE]; int main(void)
{ int value; tos = stack; /* tos points to the top of stack */ p1 = stack; /* initialize p1 */ do { printf("Enter value: "); scanf("%d", &value); if(value!=0) push(value); else printf("value on top is %d\n", pop());
} while(value!=-1);
120
C + + : T h e C o m p l e t e R e f e r e n c e
} return 0; void push(int i)
{ p1++; if(p1==(tos+SIZE)) { printf("Stack Overflow.\n"); exit(1);
}
*p1 = i;
} int pop(void)
{ if(p1==tos) { printf("Stack Underflow.\n"); exit(1);
} p1--; return *(p1+1);
}
You can see that memory for the stack is provided by the array stack. The pointer
p1
is set to point to the first element in stack. The p1 variable accesses the stack. The variable tos holds the memory address of the top of the stack. It is used to prevent stack overflows and underflows. Once the stack has been initialized, push( ) and
pop( )
may be used. Both the push( ) and pop( ) functions perform a relational test on the pointer p1 to detect limit errors. In push( ), p1 is tested against the end of stack by adding SIZE (the size of the stack) to tos. This prevents an overflow. In
pop( )
, p1 is checked against tos to be sure that a stack underflow has not occurred.
In pop( ), the parentheses are necessary in the return statement. Without them, the statement would look like this: return *p1 +1; which would return the value at location p1 plus one, not the value of the location p1+1.
Preuzimanje
Reklama