Suivre des pointeurs à la main, prévoir des sizeof, trouver des bogues classiques, puis écrire avec des adresses - minmax, chaînes, matrices. Chapitre 2.
Sauf mention contraire, on se place sur un PC 64 bits sous Linux : un int fait 4 octets, un pointeur 8. Les programmes se compilent avec gcc -std=c11 -Wall -Wextra -Werror.
Exercice · Suivre les flèches
Qu'affiche ce programme ? Dessiner les variables et les pointeurs après chaque ligne.
#include <stdio.h>
int main(void )
{
int a = 1 , b = 2 ;
int *p = &a, *q = &b;
*p = *q + 1 ;
p = q;
*p = 10 ;
*q = *q + a;
printf("a = %d, b = %d, *p = %d\n" , a, b, *p);
return 0 ;
}
Exercice · Combien d'octets ?
Qu'affiche ce programme ?
#include <stdio.h>
#include <string.h>
int main(void )
{
char s[] = "abc" ;
char *p = s;
int t[5 ];
char m[10 ] = "abc" ;
printf("%zu %zu %zu %zu %zu %zu %zu\n" , sizeof s, sizeof p, strlen(s),
sizeof t, sizeof t / sizeof t[0 ], sizeof m, strlen(m));
return 0 ;
}
On ajoute ensuite cette fonction, appelée par f(t) :
void f(int u[])
{
printf("%zu\n" , sizeof u / sizeof u[0 ]);
}
Qu'afficherait-elle ? Pourquoi gcc -Wall -Werror refuse-t-il de la compiler ?
Exercice · Trois bogues
Chacun de ces programmes est faux. Dire pourquoi, ce que gcc -Wall -Wextra en dit, et le corriger.
Premier programme :
#include <stdio.h>
int main(void )
{
int n;
if (scanf("%d" , n) != 1 )
return 1 ;
printf("%d\n" , n);
return 0 ;
}
Deuxième programme :
int main(void )
{
int *p;
*p = 3 ;
return 0 ;
}
Troisième programme :
#include <stdio.h>
int somme(int t[])
{
int s = 0 ;
for (size_t i = 0 ; i < sizeof t / sizeof t[0 ]; i++)
s += t[i];
return s;
}
int main(void )
{
int t[4 ] = {1 , 2 , 3 , 4 };
printf("%d\n" , somme(t));
return 0 ;
}
Exercice · Deux résultats
Une fonction C ne rend qu'une valeur. Écrire
void minmax(const int t[], size_t n, int *min, int *max);
qui range dans *min et *max le plus petit et le plus grand élément du tableau t de n éléments (n ≥ 1). L'appeler depuis main sur {3, -1, 4, 1, -5, 9, 2, 6}.
Exercice · Des chaînes sans indices
Écrire, sans utiliser de crochets (seulement des pointeurs, * et ++) :
Une fonction size_t longueur(const char *s), qui rend le nombre de caractères de s. Une fonction void inverser(char *s), qui renverse s sur place : "bonjour" devient "ruojnob". Pourquoi inverser("bonjour") compile-t-il, et que se passe-t-il à l'exécution ? Comment l'appeler correctement ?
Exercice · Transposer
Une matrice de h lignes et w colonnes est rangée ligne par ligne dans un tableau à une dimension : la case (colonne x, ligne y) est a[x + y * w].
Écrire void transposer(const int a[], int b[], size_t w, size_t h), qui range dans b la transposée de a (w lignes, h colonnes). Pourquoi ne pas écrire void transposer(int a[][w], …) ? Qu'est-ce qui serait possible si w était une constante ?