Exemples Corrigés : QCM Avancé Langage C – Pointeurs
Voici une série de questions à choix multiples QCM sur les pointeurs en langage C. Chaque question est accompagnée de sa réponse et d’une explication détaillée pour clarifier les concepts.
Question 1 : Pointeur Non Initialisé
Que contiendra un pointeur non initialisé lorsqu’il est déclaré ?
- Une adresse valide de la mémoire.
- L’adresse de la variable la plus proche.
- Une valeur indéfinie (garbage value). ✅
- NULL.
Réponse : 3
Un pointeur non initialisé contient une valeur indéfinie (garbage value), qui correspond à une adresse mémoire aléatoire. Il peut provoquer un comportement indéfini si utilisé.
Question 2 : Pointeurs et Tableaux
Que retourne sizeof(arr)
si arr
est un tableau déclaré comme suit : int arr[10];
?
- La taille d’un pointeur.
- La taille totale du tableau en octets. ✅
- La taille d’un entier (
int
). - Une erreur de compilation.
Réponse : 2
Pour un tableau statique, sizeof(arr)
retourne la taille totale du tableau en octets, soit 10 * sizeof(int)
.
Question 3 : Conversion de Tableaux en Pointeurs
Que se passe-t-il lorsqu’un tableau est passé à une fonction ?
- Une copie complète du tableau est faite.
- Seul le premier élément est passé.
- L’adresse du tableau est passée (décay en pointeur). ✅
- Une erreur de compilation.
Réponse : 3
Lorsqu’un tableau est passé à une fonction, il est converti (décay) en pointeur pointant vers le premier élément du tableau.
Question 4 : Déréférencement Incorrect
Quel est le résultat du code suivant ?
int *p = NULL;
printf("%d", *p);
0
est imprimé.- Comportement indéfini (segmentation fault). ✅
- Le programme imprime l’adresse
NULL
. - Le programme ne compile pas.
Réponse : 2
Déréférencer un pointeur NULL
provoque un comportement indéfini, souvent un segmentation fault.
Question 5 : Pointeur de Fonction
Quelle est la syntaxe correcte pour déclarer un pointeur vers une fonction retournant un entier et prenant deux entiers comme arguments ?
int *func_ptr(int, int);
int *(*func_ptr)(int, int);
int (*func_ptr)(int, int);
✅int func_ptr(int, int);
Réponse : 3
int (*func_ptr)(int, int);
est la syntaxe correcte pour déclarer un pointeur vers une fonction prenant deux int
comme arguments et retournant un int
.
Question 6 : Allocation Dynamique
Que se passe-t-il si free()
est appelé deux fois sur le même pointeur ?
- Le programme libère la mémoire deux fois.
- Comportement indéfini. ✅
- Rien ne se passe, le programme continue.
- Une erreur de compilation.
Réponse : 2
Appeler free()
deux fois sur le même pointeur provoque un comportement indéfini. Cela peut entraîner des crashs ou une corruption de la mémoire.
Question 7 : Pointeur de Pointeur
Que représente **pp
si int **pp = &p;
et p
est un pointeur vers un entier ?
- L’adresse de
p
. - La valeur pointée par
p
. ✅ - L’adresse d’un entier.
- Une erreur de compilation.
Réponse : 2
**pp
donne la valeur pointée par le pointeur p
, car pp
est un pointeur vers un pointeur.
Question 8 : Pointeurs et Chaînes
Que retourne le code suivant ?
char str[] = "Hello";
char *p = str;
printf("%c", *(p + 2));
H
l
✅e
- Comportement indéfini.
Réponse : 2
*(p + 2)
donne le troisième caractère de la chaîne, soit l
.
Question 9 : Pointeurs et Structures
Que fait l’opérateur ->
?
- Accède à un membre d’une structure via un pointeur. ✅
- Accède directement à une structure.
- Donne l’adresse d’un membre d’une structure.
- Donne la taille de la structure.
Réponse : 1
L’opérateur ->
est utilisé pour accéder aux membres d’une structure via un pointeur.
Question 10 : Pointeur Constant
Que signifie int *const p = &x;
?
p
est un pointeur constant, mais la valeur pointée peut être modifiée. ✅- La valeur pointée par
p
est constante. - Ni le pointeur ni la valeur pointée ne peuvent être modifiés.
- Erreur de compilation.
Réponse : 1
int *const p = &x;
signifie que p
est un pointeur constant (son adresse ne peut pas changer), mais la valeur qu’il pointe peut être modifiée.
Question 11 : Chaîne de Caractères et malloc
Quel problème potentiel ce code pose-t-il ?
char *str = (char *)malloc(5);
strcpy(str, "Hello");
- La chaîne est copiée correctement.
- Le code provoque un dépassement de mémoire. ✅
- Une erreur de compilation.
- La mémoire allouée est insuffisante pour
malloc
.
Réponse : 2
malloc(5)
alloue uniquement 5 octets, mais "Hello"
nécessite 6 octets (5 caractères + le caractère nul \0
).
Question 12 : Matrice Dynamique
Que fait ce code ?
int **matrix = (int **)malloc(3 * sizeof(int *));
for (int i = 0; i < 3; i++) {
matrix[i] = (int *)malloc(3 * sizeof(int));
}
- Crée une matrice dynamique 3×3. ✅
- Crée un tableau dynamique 1D de taille 3.
- Crée un tableau statique.
- Crée une erreur de compilation.
Réponse : 1
Ce code alloue dynamiquement une matrice 3×3 (tableau 2D dynamique).
Suite : QCM Avancé Langage C – Pointeurs
Voici une nouvelle série de questions à choix multiples (QCM) avec des explications détaillées pour approfondir vos connaissances sur les pointeurs en C. Ces questions se concentrent sur des concepts encore plus complexes et des cas pratiques.
Question 13 : Taille des Données Pointées
Que retourne le code suivant ?
#include <stdio.h>
int main() {
int arr[5] = {1, 2, 3, 4, 5};
int *p = arr;
printf("%lu\n", sizeof(p));
return 0;
}
- La taille du tableau
arr
. - La taille d’un entier (
sizeof(int)
). - La taille d’un pointeur sur la machine. ✅
- Une erreur de compilation.
Réponse : 3
sizeof(p)
retourne la taille d’un pointeur (4 octets sur une architecture 32 bits, 8 octets sur une architecture 64 bits). Les tableaux, lorsqu’ils sont assignés à un pointeur, ne gardent aucune information sur leur taille.
Question 14 : Pointeurs et Décalages
Que donne le code suivant ?
#include <stdio.h>
int main() {
int arr[] = {10, 20, 30};
int *p = arr + 1;
printf("%d\n", *(p - 1));
return 0;
}
- 10 ✅
- 20
- 30
- Comportement indéfini.
Réponse : 1
p
pointe initialement sur arr[1]
(valeur 20). Le décalage (p - 1)
revient à pointer sur arr[0]
, donc *(p - 1)
retourne 10.
Question 15 : Pointeurs sur des Constantes
Que signifie const int *p
?
- Le pointeur
p
est constant. - La valeur pointée par
p
est constante. ✅ - Ni le pointeur ni la valeur pointée ne peuvent être modifiés.
- Une erreur de compilation.
Réponse : 2
const int *p
signifie que la valeur pointée par p
ne peut pas être modifiée, mais le pointeur p
lui-même peut changer d’adresse.
Question 16 : Pointeurs Void
Quel est le rôle d’un pointeur void
?
- Il peut pointer uniquement vers des entiers.
- Il peut pointer vers n’importe quel type de données. ✅
- Il ne peut pas être déréférencé directement. ✅
- Il provoque une erreur de compilation lorsqu’il est utilisé.
Réponses : 2 et 3
Un pointeur void
est générique et peut pointer vers n’importe quel type, mais il ne peut pas être déréférencé sans conversion explicite.
Question 17 : Fonction Modifiant un Tableau
Que donne le code suivant ?
#include <stdio.h>
void modify(int *arr, int size) {
for (int i = 0; i < size; i++) {
arr[i] += 1;
}
}
int main() {
int arr[] = {1, 2, 3};
modify(arr, 3);
printf("%d\n", arr[0]);
return 0;
}
- 1
- 2 ✅
- 3
- Une erreur de compilation.
Réponse : 2
Lorsque le tableau arr
est passé à la fonction modify
, il est converti en pointeur. Les modifications dans la fonction affectent directement le tableau original.
Question 18 : Double Pointeur
Que représente **p
dans le code suivant ?
int a = 10;
int *p1 = &a;
int **p = &p1;
- L’adresse de
p1
. - L’adresse de
a
. - La valeur de
a
. ✅ - Une erreur de compilation.
Réponse : 3
*p
pointe sur p1
, et **p
donne la valeur pointée par p1
, soit a
.
Question 19 : Sécurité Mémoire
Que se passe-t-il si vous déréférencez un pointeur libéré par free
?
- Rien ne se passe, mais la mémoire n’est pas accessible.
- Une segmentation fault est garantie.
- Comportement indéfini. ✅
- Une erreur de compilation.
Réponse : 3
Déréférencer un pointeur libéré (free
) mène à un comportement indéfini. Cela peut provoquer des erreurs aléatoires ou des crashs.
Question 20 : Tableaux 2D Dynamiques
Que donne le code suivant ?
#include <stdio.h>
#include <stdlib.h>
int main() {
int **matrix = (int **)malloc(2 * sizeof(int *));
for (int i = 0; i < 2; i++) {
matrix[i] = (int *)malloc(2 * sizeof(int));
}
matrix[0][0] = 5;
matrix[1][1] = 10;
printf("%d %d\n", matrix[0][0], matrix[1][1]);
for (int i = 0; i < 2; i++) {
free(matrix[i]);
}
free(matrix);
return 0;
}
- 5 10 ✅
- 5 5
- 10 10
- Une erreur de compilation.
Réponse : 1
Le tableau 2D est alloué dynamiquement et les valeurs assignées sont affichées correctement.
Question 21 : Erreur Courante avec malloc
Quel est le problème potentiel dans ce code ?
char *str = (char *)malloc(5);
strcpy(str, "Hello");
- La chaîne est copiée correctement.
- Comportement indéfini dû à un dépassement mémoire. ✅
- Une erreur de compilation.
malloc
n’alloue pas de mémoire.
Réponse : 2
malloc(5)
alloue uniquement 5 octets, mais "Hello"
nécessite 6 octets (5 caractères + le caractère nul \0
). Cela provoque un dépassement mémoire.
Question 22 : Pointeur et Fonction
Quelle est la sortie du code suivant ?
#include <stdio.h>
void func(int *p) {
*p = *p + 10;
}
int main() {
int a = 5;
func(&a);
printf("%d\n", a);
return 0;
}
- 5
- 15 ✅
- 10
- Une erreur de compilation.
Réponse : 2
La fonction func
modifie directement la valeur de a
via un pointeur.
Question 23 : Chaînes et Pointeurs
Que donne le code suivant ?
#include <stdio.h>
int main() {
char *str = "Hello";
printf("%c\n", *(str + 1));
return 0;
}
H
e
✅l
- Comportement indéfini.
Réponse : 2
*(str + 1)
donne le deuxième caractère de la chaîne "Hello"
, soit e
.
Conseils pour Approfondir :
- Pratiquez avec des exercices impliquant des structures, des chaînes, et des fonctions génériques.
- Utilisez des outils comme GDB, Valgrind, et AddressSanitizer pour déboguer les erreurs liées aux pointeurs.
Ces questions vous aideront à explorer les concepts avancés des pointeurs tout en renforçant vos compétences en C.