Langage C/C++

Guide : Utilisation de malloc en C

La fonction malloc (memory allocation) en langage C est utilisée pour allouer dynamiquement de la mémoire à l’exécution. Ce guide explique en détail son utilisation, ses applications, et les bonnes pratiques.


1. Qu’est-ce que malloc ?

  • malloc est définie dans <stdlib.h>.
  • Elle permet d’allouer un bloc de mémoire contigu de taille spécifiée.
  • Retourne un pointeur vers le début du bloc de mémoire alloué.
  • En cas d’échec, elle retourne NULL.

2. Syntaxe de malloc

void *malloc(size_t size);
  • size : Taille en octets de la mémoire à allouer.
  • Retour : Un pointeur void * (générique), à convertir dans le type approprié.

3. Étapes de base pour utiliser malloc

  1. Inclure l’en-tête <stdlib.h>.
  2. Spécifier la taille à allouer avec l’opérateur sizeof.
  3. Vérifier si le pointeur retourné est non nul.
  4. Libérer la mémoire après usage avec free.

4. Exemple simple : Allocation d’un entier

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

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

    *ptr = 42; // Initialisation de l'entier
    printf("Valeur de l'entier alloué : %d\n", *ptr);

    free(ptr); // Libération de la mémoire
    return 0;
}

5. Allocation d’un tableau

Exemple : Allocation dynamique d’un tableau d’entiers

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

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

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

    // Initialisation des éléments
    for (int i = 0; i < n; i++) {
        tableau[i] = i * 2;
    }

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

    // Libération de la mémoire
    free(tableau);
    return 0;
}

6. Tableaux multidimensionnels avec malloc

Allocation en une seule dimension (tableau linéarisé)

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

int main() {
    int lignes = 3, colonnes = 4;

    // Allocation d'une matrice linéarisée
    int *matrice = (int *)malloc(lignes * colonnes * sizeof(int));
    if (matrice == NULL) {
        printf("Échec de l'allocation mémoire.\n");
        return 1;
    }

    // Initialisation et affichage
    for (int i = 0; i < lignes; i++) {
        for (int j = 0; j < colonnes; j++) {
            matrice[i * colonnes + j] = i + j;
            printf("%d ", matrice[i * colonnes + j]);
        }
        printf("\n");
    }

    free(matrice); // Libération de la mémoire
    return 0;
}

Allocation ligne par ligne

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

int main() {
    int lignes = 3, colonnes = 4;

    // Allocation d'un tableau de pointeurs
    int **matrice = (int **)malloc(lignes * sizeof(int *));
    if (matrice == NULL) {
        printf("Échec de l'allocation mémoire.\n");
        return 1;
    }

    // Allocation de chaque ligne
    for (int i = 0; i < lignes; i++) {
        matrice[i] = (int *)malloc(colonnes * sizeof(int));
        if (matrice[i] == NULL) {
            printf("Échec de l'allocation mémoire pour la ligne %d.\n", i);
            return 1;
        }
    }

    // Initialisation et affichage
    for (int i = 0; i < lignes; i++) {
        for (int j = 0; j < colonnes; j++) {
            matrice[i][j] = i * j;
            printf("%d ", matrice[i][j]);
        }
        printf("\n");
    }

    // Libération de la mémoire
    for (int i = 0; i < lignes; i++) {
        free(matrice[i]);
    }
    free(matrice);

    return 0;
}

7. Réallocation de mémoire avec realloc

La fonction realloc permet de redimensionner un bloc mémoire alloué avec malloc.

Syntaxe :

void *realloc(void *ptr, size_t size);
  • ptr : Pointeur vers le bloc initial.
  • size : Nouvelle taille souhaitée.

Exemple :

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

int main() {
    int n = 5;

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

    for (int i = 0; i < n; i++) {
        tableau[i] = i + 1;
    }

    // Redimensionnement
    printf("Redimensionnement du tableau à 10 éléments.\n");
    tableau = (int *)realloc(tableau, 10 * sizeof(int));
    if (tableau == NULL) {
        printf("Échec de la réallocation mémoire.\n");
        return 1;
    }

    // Initialisation des nouveaux éléments
    for (int i = n; i < 10; i++) {
        tableau[i] = i + 1;
    }

    // Affichage
    for (int i = 0; i < 10; i++) {
        printf("%d ", tableau[i]);
    }
    printf("\n");

    free(tableau);
    return 0;
}

8. Erreurs courantes avec malloc

  1. Ne pas vérifier le pointeur retourné :
    • Si malloc échoue, il retourne NULL. Utilisez toujours une vérification après l’allocation.
  2. Oublier de libérer la mémoire :
    • Toute mémoire allouée avec malloc doit être libérée avec free pour éviter les fuites mémoire.
  3. Utiliser un pointeur libéré :
    • Après un free, le pointeur est invalide. Il est recommandé de le réinitialiser à NULL.
  4. Accéder hors des limites :
    • Assurez-vous que les indices utilisés dans un tableau alloué dynamiquement sont valides.

9. Bonnes pratiques

  • Toujours initialiser les pointeurs pour éviter des comportements imprévisibles.
  • Vérifiez les échecs d’allocation systématiquement.
  • Utilisez sizeof pour calculer correctement la taille des types de données.
  • Libérez la mémoire dès qu’elle n’est plus nécessaire.

10. Comparaison avec calloc

  • malloc ne met pas à zéro les blocs de mémoire alloués. Les valeurs sont indéterminées.
  • Si vous avez besoin d’une mémoire initialisée à zéro, utilisez calloc.

Exemple avec calloc :

int *tableau = (int *)calloc(5, sizeof(int));

En C, malloc est l’une des méthodes les plus couramment utilisées pour l’allocation dynamique de mémoire. Cependant, il existe plusieurs alternatives à malloc, qui offrent des fonctionnalités supplémentaires ou adaptées à des besoins spécifiques. Voici un aperçu des alternatives :


1. calloc

  • Description : Alloue de la mémoire comme malloc, mais initialise les blocs à zéro.
  • Syntaxe : void *calloc(size_t nitems, size_t size);
    • nitems : Nombre d’éléments à allouer.
    • size : Taille de chaque élément.
  • Avantages :
    • Initialise les blocs à zéro, évitant des valeurs indéterminées.
    • Simplifie l’allocation de tableaux dynamiques.
  • Exemple : int *array = (int *)calloc(10, sizeof(int)); if (array == NULL) { printf("Allocation mémoire échouée.\n"); }

2. realloc

  • Description : Permet de redimensionner un bloc de mémoire alloué avec malloc ou calloc.
  • Syntaxe : void *realloc(void *ptr, size_t new_size);
    • ptr : Pointeur vers la mémoire initiale.
    • new_size : Nouvelle taille en octets.
  • Avantages :
    • Utile pour agrandir ou réduire la mémoire sans perdre les données existantes.
  • Exemple : int *array = (int *)malloc(5 * sizeof(int)); array = (int *)realloc(array, 10 * sizeof(int)); // Agrandir à 10 éléments

3. free

  • Description : Bien qu’il ne soit pas une alternative à l’allocation, free est nécessaire pour libérer la mémoire allouée dynamiquement.
  • Syntaxe : void free(void *ptr);
  • Bonnes pratiques :
    • Toujours appeler free pour éviter les fuites mémoire.
    • Réinitialiser le pointeur à NULL après un free.
  • Exemple : free(array); array = NULL;

4. alloca

  • Description : Alloue de la mémoire sur la pile au lieu du tas.
  • Syntaxe : void *alloca(size_t size);
    • Non standard, mais disponible dans certains compilateurs comme GCC.
  • Avantages :
    • Mémoire libérée automatiquement à la sortie de la fonction.
    • Pas besoin de free.
  • Inconvénients :
    • Moins flexible (limité par la taille de la pile).
    • Risque de dépassement de pile si trop de mémoire est allouée.
  • Exemple : int *array = (int *)alloca(10 * sizeof(int));

5. new (en C++)

  • Description : Opérateur utilisé pour l’allocation dynamique en C++.
  • Avantages :
    • Gère automatiquement l’appel au constructeur pour les objets.
    • Assure une meilleure compatibilité avec les objets complexes.
  • Inconvénients :
    • Pas disponible en C pur.
  • Exemple : int *array = new int[10]; delete[] array; // Libération en C++

6. VirtualAlloc et mmap (allocations spécifiques au système)

VirtualAlloc (Windows)

  • Description : Fonction Windows pour l’allocation directe de mémoire virtuelle.
  • Syntaxe : void *VirtualAlloc(LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect);
  • Avantages :
    • Plus flexible pour des allocations de grande taille ou spécifiques.
    • Contrôle précis sur la mémoire (protection, alignement).
  • Exemple : #include <windows.h> void *ptr = VirtualAlloc(NULL, 1024, MEM_COMMIT, PAGE_READWRITE);

mmap (Linux/Unix)

  • Description : Alloue de la mémoire directement en utilisant le gestionnaire de mémoire virtuelle.
  • Syntaxe : void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);
  • Avantages :
    • Contrôle précis sur la mémoire (lecture/écriture/exécution).
    • Utilisé pour le mappage de fichiers en mémoire.
  • Exemple : #include <sys/mman.h> void *ptr = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);

7. HeapAlloc (Windows)

  • Description : Fonction Windows pour allouer de la mémoire depuis un tas créé.
  • Syntaxe : LPVOID HeapAlloc(HANDLE hHeap, DWORD dwFlags, SIZE_T dwBytes);
  • Avantages :
    • Peut être utilisé pour gérer plusieurs tas dans une application.
  • Exemple : #include <windows.h> HANDLE heap = GetProcessHeap(); void *ptr = HeapAlloc(heap, 0, 1024);

8. std::vector et std::array (en C++ uniquement)

  • Description : Structures de données modernes de C++ qui encapsulent des allocations dynamiques.
  • Avantages :
    • Gestion automatique de la mémoire.
    • Sécurité accrue contre les erreurs de pointeurs.
  • Exemple avec std::vector : #include <vector> std::vector<int> vec(10); // Tableau dynamique de taille 10

9. Alternatives pour la gestion mémoire : Bibliothèques personnalisées

Certaines bibliothèques ou outils fournissent des fonctions spécifiques pour gérer la mémoire :

  • jemalloc : Allocation efficace pour les charges lourdes.
  • tcmalloc (Google) : Optimisé pour les applications multithreadées.
  • Boehm GC : Collecteur de mémoire automatique pour les langages C/C++.

Comparaison des alternatives

MéthodeType de mémoireInitialisationBesoin de freeApplications courantes
mallocTasNonOuiAllocation générale.
callocTasOui (zéro)OuiTableaux dynamiques.
reallocTasConserve données existantesOuiRedimensionnement de blocs.
allocaPileNonNonMémoire temporaire (locale).
VirtualAllocMémoire virtuelleNonOuiGrandes allocations (Windows).
mmapMémoire virtuelleNonOuiGestion avancée (Linux/Unix).
HeapAllocTas (Windows)NonOuiGestion de tas multiples.
new (C++)TasNonOui (delete)Objets dynamiques en C++.

L’alternative à malloc dépend du contexte et des besoins spécifiques :

  • Pour des tableaux : calloc ou realloc.
  • Pour des applications système : mmap ou VirtualAlloc.
  • Pour des solutions modernes : std::vector en C++.

Oui, il est possible de combiner malloc et calloc dans un programme, mais cela dépend du contexte et du besoin spécifique. Les deux fonctions sont utilisées pour allouer dynamiquement de la mémoire, mais elles ont des différences importantes :

  • malloc : Alloue un bloc de mémoire, mais ne l’initialise pas (les valeurs dans la mémoire sont indéterminées).
  • calloc : Alloue un bloc de mémoire et initialise tous les bits à zéro.

Combiner les deux signifie généralement utiliser l’une pour une partie du programme et l’autre pour une autre partie, selon le besoin. Voici quelques cas où cette combinaison peut être utile :


1. Exemple d’utilisation dans un même programme

Vous pouvez utiliser malloc pour une partie du programme où l’initialisation à zéro n’est pas nécessaire, et calloc pour une autre partie où vous avez besoin de mémoire initialisée.

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

int main() {
    int n = 5;

    // Utilisation de malloc
    int *array1 = (int *)malloc(n * sizeof(int));
    if (array1 == NULL) {
        printf("Échec de l'allocation avec malloc.\n");
        return 1;
    }

    // Initialisation manuelle des éléments
    for (int i = 0; i < n; i++) {
        array1[i] = i + 1;
    }

    printf("Tableau array1 (malloc) : ");
    for (int i = 0; i < n; i++) {
        printf("%d ", array1[i]);
    }
    printf("\n");

    // Utilisation de calloc
    int *array2 = (int *)calloc(n, sizeof(int));
    if (array2 == NULL) {
        printf("Échec de l'allocation avec calloc.\n");
        free(array1);
        return 1;
    }

    // array2 est déjà initialisé à 0
    printf("Tableau array2 (calloc) : ");
    for (int i = 0; i < n; i++) {
        printf("%d ", array2[i]);
    }
    printf("\n");

    // Libération de la mémoire
    free(array1);
    free(array2);

    return 0;
}

2. Utilisation de malloc puis d’une initialisation avec calloc

Une combinaison moins courante consiste à allouer une mémoire avec malloc et à utiliser une autre portion de mémoire allouée avec calloc pour initialiser certains éléments.

Exemple : Gestion de deux blocs avec différentes initialisations

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

int main() {
    int n = 5;

    // Allocation avec malloc
    int *array = (int *)malloc(n * sizeof(int));
    if (array == NULL) {
        printf("Échec de l'allocation avec malloc.\n");
        return 1;
    }

    // Initialisation manuelle de la première moitié
    for (int i = 0; i < n / 2; i++) {
        array[i] = i + 1;
    }

    // Allocation d'un autre bloc avec calloc et copie dans l'autre moitié
    int *temp = (int *)calloc(n / 2, sizeof(int));
    if (temp == NULL) {
        printf("Échec de l'allocation avec calloc.\n");
        free(array);
        return 1;
    }

    memcpy(&array[n / 2], temp, (n / 2) * sizeof(int)); // Copie mémoire initialisée à 0

    // Affichage du tableau combiné
    printf("Tableau combiné : ");
    for (int i = 0; i < n; i++) {
        printf("%d ", array[i]);
    }
    printf("\n");

    // Libération
    free(array);
    free(temp);

    return 0;
}

3. Allocation combinée pour des structures complexes

Si vous gérez des structures complexes avec plusieurs champs, vous pouvez allouer une partie de la structure avec malloc et une autre avec calloc, en fonction des besoins d’initialisation.

Exemple : Structures et mémoire combinée

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

typedef struct {
    int *values;  // Mémoire allouée avec malloc
    int *flags;   // Mémoire allouée avec calloc
} Data;

int main() {
    int n = 5;

    // Allocation de la structure
    Data *data = (Data *)malloc(sizeof(Data));
    if (data == NULL) {
        printf("Échec de l'allocation de la structure.\n");
        return 1;
    }

    // Allocation des champs
    data->values = (int *)malloc(n * sizeof(int));
    data->flags = (int *)calloc(n, sizeof(int));

    if (data->values == NULL || data->flags == NULL) {
        printf("Échec de l'allocation des champs.\n");
        free(data->values);
        free(data->flags);
        free(data);
        return 1;
    }

    // Initialisation des valeurs
    for (int i = 0; i < n; i++) {
        data->values[i] = i + 1;
    }

    // Affichage
    printf("Values : ");
    for (int i = 0; i < n; i++) {
        printf("%d ", data->values[i]);
    }
    printf("\nFlags : ");
    for (int i = 0; i < n; i++) {
        printf("%d ", data->flags[i]);
    }
    printf("\n");

    // Libération
    free(data->values);
    free(data->flags);
    free(data);

    return 0;
}

4. Bonnes pratiques pour combiner malloc et calloc

  • Utilisez calloc lorsque vous avez besoin d’un tableau ou d’une structure initialisée à zéro.
  • Préférez malloc si vous n’avez pas besoin d’une initialisation explicite, pour des raisons de performance.
  • Vérifiez toujours le retour de malloc et calloc pour éviter les plantages dus à un manque de mémoire.
  • N’oubliez pas de libérer chaque bloc alloué dynamiquement avec free.

Autres articles

Guide : Implémenter get_iemedans des fichiers avec...
La fonction get_iemepermet de récupérer le i-ème élément d'un fichier...
Read more
Guide : Implémenter un Fichier en Tableau...
Les fichiers en tableaux circulaires (ou files d'attente circulaires )...
Read more
Guide : Fichiers en Tableaux Circulaires en...
Les tableaux circulaires (ou buffers circulaires) sont des structures de...
Read more
AZ

Recent Posts

Exercices Corrigés sur les Écarts Budgétaires

Exercice 1 : Calcul des Écarts sur Volume et Prix Contexte :Une entreprise a prévu…

14 minutes ago

Exemples de QCM sur le Contrôle Budgétaire (Contrôle de Gestion)

1. Généralités sur le Contrôle Budgétaire Question 1 : Quel est l’objectif principal du contrôle…

36 minutes ago

Exemples de QCM Contrôle de Gestion et Pilotage de la Performance

Voici un QCM Contrôle de Gestion - Pilotage de la Performance bien conçu sur le…

1 heure ago

Modèle de Fiche d’Action Vierge dans Excel

Une fiche d’action est un outil essentiel pour planifier, suivre et gérer les tâches dans…

1 heure ago

Modèle de Fiche de Parrainage dans Word

La fiche de parrainage est bien plus qu’un simple document administratif. Elle constitue un outil…

3 heures ago

Fiche Méthode de La Tenue de Registres – Fiche Pratique

La tenue de registres est une méthode essentielle pour organiser et gérer des informations de…

16 heures ago

This website uses cookies.