Langage C/C++

Les Pointeurs en C : Exercices Corrigés

Les pointeurs sont une caractéristique puissante du langage C, offrant un contrôle de bas niveau sur la mémoire. Ils permettent la manipulation directe des adresses mémoire, ce qui peut être extrêmement utile pour l’optimisation des performances et la gestion dynamique de la mémoire. Cet article présente des exercices pratiques sur les pointeurs en C, avec des solutions détaillées pour aider à comprendre leur utilisation et leur importance.

Exercice 1 : Comprendre les bases des pointeurs

Énoncé :

Écrire un programme en C qui :

  1. Déclare un entier a et un pointeur vers un entier p.
  2. Assigne l’adresse de a à p.
  3. Modifie la valeur de a en utilisant le pointeur p.
  4. Affiche l’adresse de a, la valeur de a et la valeur pointée par p.

Solution :

#include <stdio.h>

int main() {
    int a = 10;
    int *p;

    p = &a; // p pointe vers a

    // Afficher les valeurs initiales
    printf("Adresse de a : %p\n", (void*)&a);
    printf("Valeur de a : %d\n", a);
    printf("Valeur pointée par p : %d\n", *p);

    *p = 20; // Modifier la valeur de a en utilisant p

    // Afficher les valeurs après modification
    printf("Valeur de a après modification : %d\n", a);
    printf("Valeur pointée par p après modification : %d\n", *p);

    return 0;
}

Explication :

Cet exercice permet de comprendre les bases des pointeurs : comment déclarer un pointeur, lui assigner une adresse, et utiliser le pointeur pour modifier la valeur de la variable à laquelle il pointe.

Exercice 2 : Manipulation de tableaux avec des pointeurs

Énoncé :

Écrire un programme en C qui :

  1. Déclare un tableau d’entiers de taille 5.
  2. Utilise un pointeur pour accéder et modifier les éléments du tableau.
  3. Affiche les éléments du tableau avant et après modification.

Solution :

#include <stdio.h>

int main() {
    int arr[5] = {1, 2, 3, 4, 5};
    int *p = arr; // p pointe vers le premier élément de arr

    // Afficher les éléments du tableau avant modification
    printf("Tableau avant modification : ");
    for(int i = 0; i < 5; i++) {
        printf("%d ", arr[i]);
    }
    printf("\n");

    // Modifier les éléments du tableau en utilisant le pointeur
    for(int i = 0; i < 5; i++) {
        *(p + i) = *(p + i) * 2;
    }

    // Afficher les éléments du tableau après modification
    printf("Tableau après modification : ");
    for(int i = 0; i < 5; i++) {
        printf("%d ", arr[i]);
    }
    printf("\n");

    return 0;
}

Explication :

Cet exercice illustre l’utilisation des pointeurs pour manipuler les éléments d’un tableau. En utilisant un pointeur pour accéder et modifier les éléments du tableau, on peut constater la puissance et la flexibilité des pointeurs.

Exercice 3 : Utilisation de pointeurs pour l’allocation dynamique de mémoire

Énoncé :

Écrire un programme en C qui :

  1. Utilise malloc pour allouer dynamiquement un tableau d’entiers de taille spécifiée par l’utilisateur.
  2. Remplit le tableau avec des valeurs données par l’utilisateur.
  3. Affiche les éléments du tableau.
  4. Libère la mémoire allouée dynamiquement.

Solution :

#include <stdio.h>
#include <stdlib.h>

int main() {
    int n;
    printf("Entrez la taille du tableau : ");
    scanf("%d", &n);

    // Allocation dynamique de mémoire
    int *arr = (int*)malloc(n * sizeof(int));
    if(arr == NULL) {
        printf("Échec de l'allocation de mémoire.\n");
        return 1;
    }

    // Remplir le tableau
    printf("Entrez %d entiers :\n", n);
    for(int i = 0; i < n; i++) {
        scanf("%d", &arr[i]);
    }

    // Afficher les éléments du tableau
    printf("Éléments du tableau : ");
    for(int i = 0; i < n; i++) {
        printf("%d ", arr[i]);
    }
    printf("\n");

    // Libérer la mémoire allouée
    free(arr);

    return 0;
}

Explication :

Cet exercice montre comment utiliser les pointeurs pour allouer et gérer dynamiquement la mémoire. malloc permet de réserver un espace mémoire pendant l’exécution du programme, ce qui est essentiel pour des structures de données dynamiques.

Exercice 4 : Pointeurs et fonctions

Énoncé :

Écrire un programme en C qui :

  1. Déclare une fonction qui prend un pointeur vers un entier et double la valeur de cet entier.
  2. Utilise cette fonction pour doubler la valeur d’un entier donné.

Solution :

#include <stdio.h>

// Fonction qui double la valeur d'un entier
void doubleValue(int *p) {
    *p = *p * 2;
}

int main() {
    int a = 5;
    printf("Valeur de a avant : %d\n", a);

    doubleValue(&a); // Passer l'adresse de a

    printf("Valeur de a après : %d\n", a);

    return 0;
}

Explication :

Cet exercice montre comment les pointeurs peuvent être utilisés pour passer des arguments par référence aux fonctions. En passant l’adresse d’une variable à une fonction, la fonction peut modifier directement la valeur de la variable

Exercice 5 : Manipulation de chaînes de caractères avec des pointeurs

Énoncé :

Écrire un programme en C qui :

  1. Déclare une chaîne de caractères et un pointeur vers un caractère.
  2. Utilise le pointeur pour inverser la chaîne de caractères.
  3. Affiche la chaîne de caractères avant et après l’inversion.

Solution :

#include <stdio.h>
#include <string.h>

void reverseString(char *str) {
    int length = strlen(str);
    char *start = str;
    char *end = str + length - 1;
    char temp;

    while (start < end) {
        temp = *start;
        *start = *end;
        *end = temp;
        start++;
        end--;
    }
}

int main() {
    char str[] = "Hello, world!";
    printf("Chaîne avant inversion : %s\n", str);

    reverseString(str);

    printf("Chaîne après inversion : %s\n", str);

    return 0;
}

Explication :

Cet exercice montre comment utiliser les pointeurs pour manipuler les chaînes de caractères. La fonction reverseString utilise des pointeurs pour échanger les caractères aux extrémités de la chaîne, progressant vers le centre jusqu’à ce que la chaîne soit complètement inversée.

Exercice 6 : Utilisation de pointeurs pour des matrices

Énoncé :

Écrire un programme en C qui :

  1. Utilise malloc pour allouer dynamiquement une matrice de taille m x n spécifiée par l’utilisateur.
  2. Remplit la matrice avec des valeurs données par l’utilisateur.
  3. Affiche les éléments de la matrice.
  4. Libère la mémoire allouée dynamiquement.

Solution :

#include <stdio.h>
#include <stdlib.h>

int main() {
    int m, n;
    printf("Entrez le nombre de lignes : ");
    scanf("%d", &m);
    printf("Entrez le nombre de colonnes : ");
    scanf("%d", &n);

    // Allocation dynamique de la matrice
    int **matrix = (int **)malloc(m * sizeof(int *));
    for(int i = 0; i < m; i++) {
        matrix[i] = (int *)malloc(n * sizeof(int));
    }

    // Remplir la matrice
    printf("Entrez les éléments de la matrice (%d x %d) :\n", m, n);
    for(int i = 0; i < m; i++) {
        for(int j = 0; j < n; j++) {
            scanf("%d", &matrix[i][j]);
        }
    }

    // Afficher la matrice
    printf("Éléments de la matrice :\n");
    for(int i = 0; i < m; i++) {
        for(int j = 0; j < n; j++) {
            printf("%d ", matrix[i][j]);
        }
        printf("\n");
    }

    // Libérer la mémoire allouée
    for(int i = 0; i < m; i++) {
        free(matrix[i]);
    }
    free(matrix);

    return 0;
}

Explication :

Cet exercice introduit la gestion des matrices à l’aide de pointeurs et d’allocation dynamique de mémoire. La matrice est représentée par un tableau de pointeurs, chaque pointeur pointant vers une ligne de la matrice.

Exercice 7 : Manipulation de structures avec des pointeurs

Énoncé :

Écrire un programme en C qui :

  1. Déclare une structure Personne avec des champs pour le nom, l’âge et l’adresse.
  2. Utilise un pointeur pour initialiser et afficher les informations d’une personne.

Solution :

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct {
    char nom[50];
    int age;
    char adresse[100];
} Personne;

void afficherPersonne(Personne *p) {
    printf("Nom : %s\n", p->nom);
    printf("Âge : %d\n", p->age);
    printf("Adresse : %s\n", p->adresse);
}

int main() {
    Personne *p = (Personne *)malloc(sizeof(Personne));

    strcpy(p->nom, "Alice Dupont");
    p->age = 30;
    strcpy(p->adresse, "123 Rue Principale, Paris");

    afficherPersonne(p);

    free(p);

    return 0;
}

Explication :

Cet exercice montre comment utiliser des pointeurs pour manipuler des structures. En allouant dynamiquement une structure Personne, on peut initialiser ses champs et les afficher en utilisant un pointeur.

Exercice 8 : Pointeurs et récursivité

Énoncé :

Écrire un programme en C qui :

  1. Utilise une fonction récursive pour calculer la somme des éléments d’un tableau d’entiers.
  2. Utilise des pointeurs pour passer le tableau et sa taille à la fonction récursive.

Solution :

#include <stdio.h>

int sommeTableau(int *arr, int taille) {
    if (taille == 0) {
        return 0;
    } else {
        return arr[0] + sommeTableau(arr + 1, taille - 1);
    }
}

int main() {
    int arr[] = {1, 2, 3, 4, 5};
    int taille = sizeof(arr) / sizeof(arr[0]);

    int somme = sommeTableau(arr, taille);

    printf("Somme des éléments du tableau : %d\n", somme);

    return 0;
}

Explication :

Cet exercice combine l’utilisation des pointeurs et la récursivité pour résoudre un problème. La fonction sommeTableau calcule la somme des éléments d’un tableau en utilisant un pointeur pour accéder aux éléments et réduire la taille du tableau de manière récursive.

Exercice 9 : Gestion des pointeurs de fonctions

Énoncé :

Écrire un programme en C qui :

  1. Déclare deux fonctions, addition et multiplication, qui prennent deux entiers en paramètres et renvoient leur somme et leur produit respectivement.
  2. Déclare un pointeur de fonction.
  3. Utilise le pointeur de fonction pour appeler dynamiquement addition et multiplication en fonction de l’entrée de l’utilisateur.

Solution :

#include <stdio.h>

int addition(int a, int b) {
    return a + b;
}

int multiplication(int a, int b) {
    return a * b;
}

int main() {
    int (*operation)(int, int); // Déclaration du pointeur de fonction
    int choix, x, y;

    printf("Choisissez l'opération : 1 pour addition, 2 pour multiplication : ");
    scanf("%d", &choix);
    printf("Entrez deux entiers : ");
    scanf("%d %d", &x, &y);

    if (choix == 1) {
        operation = addition;
    } else if (choix == 2) {
        operation = multiplication;
    } else {
        printf("Choix invalide.\n");
        return 1;
    }

    int resultat = operation(x, y);
    printf("Le résultat est : %d\n", resultat);

    return 0;
}

Explication :

Cet exercice montre comment utiliser des pointeurs de fonctions pour appeler dynamiquement des fonctions en fonction de l’entrée de l’utilisateur. Cela permet de rendre le code plus flexible et modulaire.

Exercice 10 : Manipulation de listes chaînées avec des pointeurs

Énoncé :

Écrire un programme en C qui :

  1. Déclare une structure pour représenter un nœud dans une liste chaînée (contenant un entier et un pointeur vers le nœud suivant).
  2. Implémente des fonctions pour ajouter un nœud en tête, ajouter un nœud en queue, et afficher tous les nœuds de la liste.
  3. Utilise ces fonctions pour créer une liste chaînée et afficher son contenu.

Solution :

#include <stdio.h>
#include <stdlib.h>

typedef struct Node {
    int data;
    struct Node *next;
} Node;

void ajouterEnTete(Node **head, int newData) {
    Node *newNode = (Node *)malloc(sizeof(Node));
    newNode->data = newData;
    newNode->next = *head;
    *head = newNode;
}

void ajouterEnQueue(Node **head, int newData) {
    Node *newNode = (Node *)malloc(sizeof(Node));
    newNode->data = newData;
    newNode->next = NULL;
    if (*head == NULL) {
        *head = newNode;
        return;
    }
    Node *temp = *head;
    while (temp->next != NULL) {
        temp = temp->next;
    }
    temp->next = newNode;
}

void afficherListe(Node *node) {
    while (node != NULL) {
        printf("%d -> ", node->data);
        node = node->next;
    }
    printf("NULL\n");
}

int main() {
    Node *head = NULL;

    ajouterEnTete(&head, 10);
    ajouterEnTete(&head, 20);
    ajouterEnQueue(&head, 30);
    ajouterEnQueue(&head, 40);

    printf("Contenu de la liste : ");
    afficherListe(head);

    return 0;
}

Explication :

Cet exercice introduit la manipulation de listes chaînées en utilisant des pointeurs. Les fonctions permettent d’ajouter des nœuds en tête ou en queue de la liste et d’afficher son contenu, illustrant ainsi la gestion dynamique des structures de données.

Exercice 11 : Pointeurs et tableaux multidimensionnels

Énoncé :

Écrire un programme en C qui :

  1. Déclare et initialise une matrice 3×3.
  2. Utilise des pointeurs pour transposer la matrice.
  3. Affiche la matrice originale et la matrice transposée.

Solution :

#include <stdio.h>

void afficherMatrice(int mat[3][3], int taille) {
    for (int i = 0; i < taille; i++) {
        for (int j = 0; j < taille; j++) {
            printf("%d ", mat[i][j]);
        }
        printf("\n");
    }
}

void transpose(int (*mat)[3], int taille) {
    for (int i = 0; i < taille; i++) {
        for (int j = i; j < taille; j++) {
            int temp = mat[i][j];
            mat[i][j] = mat[j][i];
            mat[j][i] = temp;
        }
    }
}

int main() {
    int mat[3][3] = {
        {1, 2, 3},
        {4, 5, 6},
        {7, 8, 9}
    };

    printf("Matrice originale :\n");
    afficherMatrice(mat, 3);

    transpose(mat, 3);

    printf("Matrice transposée :\n");
    afficherMatrice(mat, 3);

    return 0;
}

Explication :

Cet exercice démontre comment utiliser des pointeurs pour manipuler des tableaux multidimensionnels. La fonction transpose utilise des pointeurs pour échanger les éléments de la matrice afin de la transposer.

Exercice 12 : Gestion de la mémoire avec calloc et realloc

Énoncé :

Écrire un programme en C qui :

  1. Utilise calloc pour allouer dynamiquement un tableau d’entiers initialisé à zéro.
  2. Utilise realloc pour redimensionner le tableau.
  3. Remplit le tableau avec des valeurs données par l’utilisateur et affiche les éléments du tableau après chaque redimensionnement.
  4. Libère la mémoire allouée dynamiquement.

Solution :

#include <stdio.h>
#include <stdlib.h>

void afficherTableau(int *arr, int taille) {
    for (int i = 0; i < taille; i++) {
        printf("%d ", arr[i]);
    }
    printf("\n");
}

int main() {
    int tailleInitiale, nouvelleTaille;

    printf("Entrez la taille initiale du tableau : ");
    scanf("%d", &tailleInitiale);

    int *arr = (int *)calloc(tailleInitiale, sizeof(int));
    if (arr == NULL) {
        printf("Échec de l'allocation de mémoire.\n");
        return 1;
    }

    printf("Entrez les valeurs pour le tableau initial :\n");
    for (int i = 0; i < tailleInitiale; i++) {
        scanf("%d", &arr[i]);
    }

    printf("Tableau initial : ");
    afficherTableau(arr, tailleInitiale);

    printf("Entrez la nouvelle taille du tableau : ");
    scanf("%d", &nouvelleTaille);

    arr = (int *)realloc(arr, nouvelleTaille * sizeof(int));
    if (arr == NULL) {
        printf("Échec de l'allocation de mémoire.\n");
        return 1;
    }

    printf("Entrez les valeurs supplémentaires pour le tableau :\n");
    for (int i = tailleInitiale; i < nouvelleTaille; i++) {
        scanf("%d", &arr[i]);
    }

    printf("Tableau redimensionné : ");
    afficherTableau(arr, nouvelleTaille);

    free(arr);

    return 0;
}

Explication :

Cet exercice montre comment utiliser calloc pour allouer dynamiquement de la mémoire initialisée à zéro, et realloc pour redimensionner dynamiquement cette mémoire. Il illustre également l’importance de libérer la mémoire allouée pour éviter les fuites de mémoire.

Autres articles

Guide : Comment créer un QCM en...
Le QCM en langage C peut être simulé dans un...
Read more
Tableaux en Langage C : Exercices Corrigés
Voici une série d'exercices corrigés sur les tableaux en langage...
Read more
Comment fonctionne la récursion terminale en C...
La récursion terminale en CLa récursion terminale est une forme...
Read more

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *