[C] Incrementation de pointeur

Published 11-28-2018

Prenons en exemple ce main:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <stdio.h>
#include <stdlib.h>

int	main()
{
	// Allocation de 100 octets
	char *alloc = (char *)malloc(sizeof(char) * 100);
	if (alloc == NULL) {
		dprintf(2, "Memory allocation failure !\n");
		return (EXIT_FAILURE);
	}

	alloc[0] = 'a';

	printf("Adress alloc (before incrementation) = %p\n", alloc);

	alloc++;
	alloc[0] = 'b';

	printf("Adress alloc (after incrementation)  = %p\n", alloc);

	printf("Value of alloc[0]   = %c\n", alloc[0]);
	printf("Value of alloc[-1] = %c\n", alloc[-1]);
}

Output :

/tmp » ./a.out
Adress alloc (before incrementation) = 0x55f8c66ed260
Adress alloc (after incrementation)  = 0x55f8c66ed261
Value of alloc[0]   = b
Value og alloc[-1] = a

J’ai alloué 100 octets avec malloc.

À l’offset 0 j’ai assigner la valeur ‘a’ puis j’ai incrémenté mon pointeur de 1, et j’ai assigné la valeur ‘b’.

Pour incrémenter notre pointeur, nous avons juste a l’incrémenter comme si nous incrémentons un index.

À la ligne 13, alloc pointe sur l’adresse : 0x55f8c66ed260

J’assigne la valeur ‘a’ a cette adresse. (ligne 13)

J’incrémente ensuite alloc de 1(ligne 17).

Alloc pointe maintenant 1 octets plus loin : 0x55f8c66ed261

J’assigne la valeur ‘b’ a l’offset 0 (qui est en réalité l’offset 1 devenue l’offset 0 du a notre incrémentation)

On voit clairement que le pointeur a été incrémente de sizeof(char) * 1 octets.

Rien de spécial, j’ai incrémenté mon pointeur de 1 octets, normal que je suis 1 octet plus loin.

Voyons maintenant le pourquoi de cet article.

Que ce passe t’il si je fais la même chose avec un type multi octets (uint64_t, uint32_t, struct, …)?

 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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#include <stdio.h>
#include <stdlib.h>

typedef struct	s_struct
{
	size_t		var_a;
	size_t		var_b;
	int			var_c;
	int			var_d;
	char		var_e;
}				t_struct;

void	print_value(t_struct *alloc)
{
	printf("address alloc = %p\n", alloc);
	printf("alloc->var_a = %zu\n", alloc->var_a);
	printf("alloc->var_b = %zu\n", alloc->var_b);

	puts("");
}

int	main()
{
	// Allocation de 100 structures
	t_struct	*alloc = (t_struct *)calloc(sizeof(t_struct), 100);
	if (alloc == NULL) {
		dprintf(2, "Memory allocation failure !\n");
		return (EXIT_FAILURE);
	}

	// Print sizeof struct
	printf("sizeof t_struct = %zu\n", sizeof(t_struct));

	alloc->var_a = 1;
	alloc->var_b = 2;

	// Affiche l'adresse de alloc et le contenue de variable
	print_value(alloc);

	alloc++;

	alloc->var_a = 3;
	alloc->var_b = 4;

	print_value(alloc);

	alloc--;

	print_value(alloc);
}

Dans ce code, on a une structure qui fait combien d’octet a votre avis ?

Je vais faire un article sur le padding pour ceux qui ont répondu 25.

La bonne réponse est 32.

Donc on a une structure de 32 octets, une allocation de la taille de notre struct * 100.

Une assignation de deux éléments de notre structure, une incrémentation et une autre assignation.

Output de ce main :

/tmp » ./a.out                                             segfault42@segfault42-pc
sizeof t_struct = 32

address alloc = 0x55f4a3e46260
alloc->var_a = 1
alloc->var_b = 2

address alloc = 0x55f4a3e46280
alloc->var_a = 3
alloc->var_b = 4

address alloc = 0x55f4a3e46260
alloc->var_a = 1
alloc->var_b = 2

À votre avis, après le alloc++ mon pointeur sera incrémenté de combien d’octet ?

On voit ici qu’en incrémentent de 1 (alloc++), notre pointeur ne s’incrémente pas de 1 octet, mais de sizeof(son type).

Je passe de l’adresse 0x55f4a3e46260 a 0x55f4a3e46280.

J’ai bien les bonnes valeurs dans mes deux variables quand j’affiche leur contenue avec la fonction print_value.

Si je décrémente, je me retrouve bien a -sizeof(mon type) et le contenue de mes 2 variables et toujours le même.

Donc pour résumer, contrairement à ce qu’on pourrait penser, quand on incrémente un pointeur, en faisant notre_variable++ ou notre_variable += 1 ou même notre_variable = notre_variable + 1, on n’incrémente pas de 1 octet, mais de sizeof(le type de notre variable).

Une incrémentation de pointeur revient à faire notre_variable += sizeof(notre_variable) + 1.