Pointers have two uses. The first is to store a memory address (see Section 5.4). The second is to use the stored memory address to access that points using an indirection (see Section 5.2).
An indirection in C is denoted by the operand *
followed by the name of a pointer variable. Its meaning is “access the
content the pointer points to”. Unfortunately, this operator is the
same as the one to denote pointer data types when declaring pointer
variables. It is very important to have a clear distinction between these
two uses of the operator. When translating a program, the compiler does not
check neither that the memory address contained in a pointer is correct, nor
that the pointed data is correct. This feature makes the design of programs
using pointer a complex task.
The following program shows the use of the indirection operator (file pointer_example_2.c):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | #include <stdio.h> int main(int argc, char** argv) { int num1, num2; int *ptr1, *ptr2; ptr1 = &num1; ptr2 = &num2; num1 = 10; num2 = 20; *ptr1 = 30; *ptr2 = 40; *ptr2 = *ptr1; return 0; } |
Line 13 assigns the value 30 to the memory location stored
in ptr1
through an indirection. The pointer has the address of
num1
, thus it is equivalent to assign the value 30 directly to
num1
. Analogously, line 14 assigns the value 40 to the address
pointed by ptr2
. This assignment is equivalent to assign the
value 40 to num2
. Line 16 contains two indirections. The right
hand side of the assignment obtains the data from the memory address stored
in ptr1
(the address of num1
), and this data is
assigned to the memory address stored in ptr2
(the address of
num2
). Upon program termination, variable num2
contains the value 30 although it has not been directly assigned.
The following figure shows the evolution of these four variables throughout the program execution. Again, the memory addresses where they are stored are arbitrary.
The coincidence between the indirection operator and the
definition of the pointer type “*
” may pose a
difficulty when understanding code. For example, the following line
int *r = *p;
contains two “*
” operands. The
first defines the type “pointer to integer” and is followed by
a declaration of variable “r
”. The second is an
indirection and is applied to the address stored in pointer
“p
”.
Let us suppose that a data structure with name
“struct s
” has been defined. Applying the rule
to define the pointer types, a pointer to this structure has type
“struct s *
”. In the following code fragment a
structure is defined and declared, and a pointer is then declared
containing its address.
1 2 3 4 5 6 7 8 9 10 | struct s { int x; char c; } struct s element; struct s *pointer; pointer = &element; |
An indirection with pointer
is used only to
access the structure fields. This operation require two operators, the
indirection (operator “*
”) and the access to the
structure fields (operator “.
”). The syntax is
then:
(*pointer).x = 10; (*pointer).c = 'l';
These two operations in C are grouped by the operator
“->
” that is placed between the pointer and
the name of the field structure. The equivalent notation is then:
pointer->x = 10; pointer->c = 'l';
The operator “->
” is always
written next to a pointer pointing to a structure, and precedes the name
of one of the fields of that structure. The following program shows the
use of this operator to copy the content from one structure to
another.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | /* Definition of the structure */ struct coordinates { float x; float y; float z; }; int main() { /* Declaring two structures */ struct coordinates location1, location2; /* Declaring two pointers */ struct coordinates *ptr1, *ptr2; /* Assigning the addresses to the pointers */ ptr1 = &location1; ptr2 = &location2; /* Assigning values to the first structure */ ptr1->x = 3.5; ptr1->y = 5.5; ptr1->z = 10.5; /* Copy the values to the second structure */ ptr2->x = ptr1->x; ptr2->y = ptr1->y; ptr2->z = ptr1->z; return 0; } |
Copy and paste the content of the previous program in a
text file in your development environment. Compile and execute. Define a
second structure and include a pointer to it as a field in the
“coordinate
” structure. Write code to
manipulate this new structure.