UC3M

Telematic/Audiovisual Syst./Communication Syst. Engineering

Systems Architecture

September 2017 - January 2018

5.5.  Indirections through pointers

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.

5.5.1.  Indirect access to the fields of a structure

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;
}

Suggestion

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.