Les doubles pointeurs (ou pointeurs de pointeurs) en C sont des variables qui contiennent l’adresse d’un pointeur. Ils permettent de manipuler des pointeurs de manière flexible, et sont souvent utilisés dans des contextes avancés comme la gestion dynamique de mémoire ou la manipulation de tableaux 2D. Ce guide explique les concepts fondamentaux et leur utilisation, avec des exemples corrigés.
Un double pointeur est déclaré en ajoutant un second astérisque (**
) lors de la définition.
type **nom_double_pointeur;
int **doublePtr; // Déclare un double pointeur vers un int
Le type de doublePtr
est un pointeur vers un pointeur qui pointe vers un int
.
Un double pointeur est utile lorsque :
L’un des usages courants des doubles pointeurs est l’allocation dynamique d’un tableau 2D.
#include <stdio.h>
#include <stdlib.h>
int main() {
int rows = 3, cols = 4;
int **matrix = malloc(rows * sizeof(int *)); // Allocation pour les lignes
for (int i = 0; i < rows; i++) {
matrix[i] = malloc(cols * sizeof(int)); // Allocation pour les colonnes
}
// Initialisation et affichage
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
matrix[i][j] = i + j;
printf("%d ", matrix[i][j]);
}
printf("\n");
}
// Libération de la mémoire
for (int i = 0; i < rows; i++) {
free(matrix[i]); // Libère chaque ligne
}
free(matrix); // Libère les pointeurs des lignes
return 0;
}
Un double pointeur permet de modifier l’adresse d’un pointeur passé en paramètre.
#include <stdio.h>
#include <stdlib.h>
void allouerMemoire(int **ptr) {
*ptr = malloc(sizeof(int)); // Alloue un entier
if (*ptr != NULL) {
**ptr = 42; // Initialise la valeur pointée
}
}
int main() {
int *p = NULL;
allouerMemoire(&p); // Passe l'adresse du pointeur p
printf("Valeur allouée : %d\n", *p); // Affiche 42
free(p); // Libère la mémoire
return 0;
}
Un tableau 2D peut être représenté à l’aide de doubles pointeurs.
#include <stdio.h>
int main() {
int array[2][3] = {{1, 2, 3}, {4, 5, 6}};
int *ptr1 = array[0];
int **ptr2 = &ptr1;
printf("Accès via double pointeur : %d\n", **ptr2); // Affiche 1
return 0;
}
Les doubles pointeurs sont souvent utilisés pour manipuler des tableaux de chaînes de caractères.
#include <stdio.h>
int main() {
char *noms[] = {"Alice", "Bob", "Charlie"};
char **ptr = noms;
for (int i = 0; i < 3; i++) {
printf("%s\n", ptr[i]); // Affiche chaque chaîne
}
return 0;
}
Pointeur | Double Pointeur |
---|---|
Contient l’adresse d’une variable. | Contient l’adresse d’un pointeur. |
Utilisé pour manipuler directement des variables. | Utilisé pour manipuler des pointeurs. |
Accès via un astérisque (* ). | Accès via deux astérisques (** ). |
malloc
sur un pointeur, assurez-vous d’appeler free
.Les doubles pointeurs sont utiles pour manipuler une liste chaînée, notamment pour insérer un élément en tête.
#include <stdio.h>
#include <stdlib.h>
typedef struct Node {
int data;
struct Node *next;
} Node;
void insererEnTete(Node **head, int valeur) {
Node *nouveau = malloc(sizeof(Node));
nouveau->data = valeur;
nouveau->next = *head;
*head = nouveau; // Modifie le pointeur head dans la fonction
}
void afficherListe(Node *head) {
while (head != NULL) {
printf("%d -> ", head->data);
head = head->next;
}
printf("NULL\n");
}
int main() {
Node *head = NULL;
insererEnTete(&head, 3);
insererEnTete(&head, 5);
insererEnTete(&head, 7);
afficherListe(head);
return 0;
}
Voici des exemples corrigés et commentés pour illustrer l’utilisation correcte des doubles pointeurs en C. Ces exemples couvrent différents cas pratiques.
#include <stdlib.h>
void allouerMemoire(int *ptr) {
ptr = malloc(sizeof(int)); // Change une copie locale de ptr
*ptr = 42; // Cela provoque un comportement indéfini si malloc échoue
}
int main() {
int *p = NULL;
allouerMemoire(p); // p reste NULL après l'appel
printf("Valeur : %d\n", *p); // Erreur de segmentation
return 0;
}
#include <stdio.h>
#include <stdlib.h>
void allouerMemoire(int **ptr) {
*ptr = malloc(sizeof(int)); // Alloue de la mémoire à l'adresse du pointeur
if (*ptr != NULL) {
**ptr = 42; // Initialise la valeur pointée
}
}
int main() {
int *p = NULL;
allouerMemoire(&p); // Passe l'adresse de p
if (p != NULL) {
printf("Valeur : %d\n", *p); // Affiche 42
free(p); // Libère la mémoire
} else {
printf("Allocation échouée\n");
}
return 0;
}
int main() {
int **tableau = malloc(3 * sizeof(int *)); // Allocation pour les lignes
for (int i = 0; i < 3; i++) {
tableau[i] = malloc(4 * sizeof(int)); // Allocation pour les colonnes
}
tableau[3][0] = 10; // Dépassement de mémoire, 3 est hors limites
return 0;
}
#include <stdio.h>
#include <stdlib.h>
int main() {
int rows = 3, cols = 4;
int **tableau = malloc(rows * sizeof(int *)); // Allocation pour les lignes
if (tableau == NULL) {
printf("Échec de l'allocation mémoire\n");
return 1;
}
for (int i = 0; i < rows; i++) {
tableau[i] = malloc(cols * sizeof(int)); // Allocation pour les colonnes
if (tableau[i] == NULL) {
printf("Échec de l'allocation mémoire\n");
return 1;
}
}
// Initialisation et affichage
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
tableau[i][j] = i * cols + j;
printf("%d ", tableau[i][j]);
}
printf("\n");
}
// Libération de la mémoire
for (int i = 0; i < rows; i++) {
free(tableau[i]); // Libère chaque ligne
}
free(tableau); // Libère les pointeurs des lignes
return 0;
}
void remplirTableau(int *tab) {
tab[0] = 10; // Modifie une copie locale du tableau
}
int main() {
int *tableau = malloc(5 * sizeof(int));
remplirTableau(tableau); // Le tableau n'est pas initialisé correctement
printf("%d\n", tableau[0]); // Résultat indéfini
free(tableau);
return 0;
}
#include <stdio.h>
#include <stdlib.h>
void remplirTableau(int **tab, int taille) {
*tab = malloc(taille * sizeof(int)); // Alloue la mémoire
if (*tab != NULL) {
for (int i = 0; i < taille; i++) {
(*tab)[i] = i * 2; // Initialise le tableau
}
}
}
int main() {
int *tableau = NULL;
remplirTableau(&tableau, 5); // Passe l'adresse du pointeur
if (tableau != NULL) {
for (int i = 0; i < 5; i++) {
printf("%d ", tableau[i]); // Affiche : 0 2 4 6 8
}
printf("\n");
free(tableau); // Libère la mémoire
}
return 0;
}
void remplirNoms(char **noms) {
noms[0] = "Alice"; // Erreur : mémoire potentiellement non allouée
}
int main() {
char **noms = NULL;
remplirNoms(noms); // noms reste NULL
printf("%s\n", noms[0]); // Comportement indéfini
return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void remplirNoms(char ***noms, int taille) {
*noms = malloc(taille * sizeof(char *)); // Alloue pour le tableau de chaînes
if (*noms == NULL) {
printf("Échec de l'allocation mémoire\n");
return;
}
(*noms)[0] = strdup("Alice"); // Alloue et copie la chaîne
(*noms)[1] = strdup("Bob");
(*noms)[2] = strdup("Charlie");
}
int main() {
char **noms = NULL;
remplirNoms(&noms, 3);
if (noms != NULL) {
for (int i = 0; i < 3; i++) {
printf("%s\n", noms[i]); // Affiche les noms
free(noms[i]); // Libère chaque chaîne
}
free(noms); // Libère le tableau de pointeurs
}
return 0;
}
typedef struct Node {
int data;
struct Node *next;
} Node;
void ajouterEnTete(Node *head, int valeur) {
Node *nouveau = malloc(sizeof(Node));
nouveau->data = valeur;
nouveau->next = head;
head = nouveau; // Modifie uniquement une copie locale
}
int main() {
Node *head = NULL;
ajouterEnTete(head, 10); // head reste NULL
return 0;
}
#include <stdio.h>
#include <stdlib.h>
typedef struct Node {
int data;
struct Node *next;
} Node;
void ajouterEnTete(Node **head, int valeur) {
Node *nouveau = malloc(sizeof(Node));
if (nouveau == NULL) {
printf("Échec de l'allocation mémoire\n");
return;
}
nouveau->data = valeur;
nouveau->next = *head;
*head = nouveau; // Modifie le pointeur réel
}
void afficherListe(Node *head) {
while (head != NULL) {
printf("%d -> ", head->data);
head = head->next;
}
printf("NULL\n");
}
int main() {
Node *head = NULL;
ajouterEnTete(&head, 10);
ajouterEnTete(&head, 20);
ajouterEnTete(&head, 30);
afficherListe(head); // Affiche : 30 -> 20 -> 10 -> NULL
// Libération de la liste
Node *temp;
while (head != NULL) {
temp = head;
head = head->next;
free(temp);
}
return 0;
}
!= NULL
).valgrind
pour vérifier l’utilisation correcte de la mémoire.Ces exemples corrigés et optimisés montrent comment manipuler efficacement les doubles pointeurs tout en évitant les erreurs courantes en C.
La présentation d’un projet est une étape clé pour convaincre des investisseurs, des partenaires ou…
Télécharger un Canevas Word et Excel pour présenter un concept ⬇︎ Un concept novateur repose…
La présentation d’un produit commercial est une étape essentielle pour assurer son succès sur le…
Chaque année, les entreprises sont tenues de réaliser une présentation des comptes annuels, un exercice…
Le stage est une étape clé dans le parcours académique et professionnel d’un étudiant. Il…
L’expression "de par" et la tournure "de part" sont souvent confondues, mais elles ont des…
This website uses cookies.