malloc în C

Cere sistemului un bloc de memorie de mărimea dată, în timpul rulării, și returnează adresa lui sau NULL dacă nu reușește.

Sintaxă
#include <stdlib.h>
void *malloc(size_t size);
tip *p = malloc(n * sizeof *p);

Ce face malloc

malloc (memory allocation) alocă size octeți pe heap și returnează un pointer la începutul blocului. Memoria rămâne alocată până când o eliberezi cu free, chiar și după ce funcția care a cerut-o s-a terminat.

Folosești memorie dinamică atunci când nu știi dimensiunea la compilare (de exemplu câte elemente citești) sau când datele trebuie să trăiască mai mult decât funcția curentă. Conținutul blocului nu este inițializat: conține valori la întâmplare până scrii în el. Dacă vrei zerouri, folosește calloc.

Forma recomandată este p = malloc(n * sizeof *p);: dimensiunea se calculează din tipul pointerului, deci rămâne corectă dacă schimbi tipul. În C nu ai nevoie de cast la rezultat. Verifică mereu dacă rezultatul este NULL.

Parametri

Parametru Descriere
size Numărul de octeți ceruți (de tip size_t). Pentru n elemente: n * sizeof *p.

Ce returnează

Un void * spre blocul alocat, aliniat pentru orice tip, sau NULL dacă memoria nu a putut fi alocată. Pentru size == 0 poate returna NULL sau un pointer unic, care tot trebuie eliberat cu free.

Exemple

Exemplul 1: Un tablou cu dimensiunea aflată la rulare

Numărul de note este citit de la intrare, apoi se alocă exact cât trebuie. La final memoria este eliberată.

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

int main(void) {
    size_t n;
    if (scanf("%zu", &n) != 1 || n == 0) return 0;
    int *note = malloc(n * sizeof *note);
    if (note == NULL) {
        printf("Memorie insuficientă\n");
        return 0;
    }
    int suma = 0;
    for (size_t i = 0; i < n; i++) {
        if (scanf("%d", &note[i]) != 1) note[i] = 0;
        suma += note[i];
    }
    printf("%zu note, media %.2f\n", n, (double)suma / (double)n);
    free(note);
    return 0;
}

Ce scrie utilizatorul (intrare)

4
9 7 10 8

Rezultat

4 note, media 8.50

Exemplul 2: O structură care trăiește după funcție

Funcția creează un client pe heap și returnează pointerul. Cine îl primește trebuie să-l elibereze. Copierea numelui se face cu snprintf, care nu depășește tabloul.

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

typedef struct {
    char nume[40];
    double sold;
} Client;

Client *client_nou(const char *nume, double sold) {
    Client *c = malloc(sizeof *c);
    if (c == NULL) return NULL;
    snprintf(c->nume, sizeof c->nume, "%s", nume);
    c->sold = sold;
    return c;
}

int main(void) {
    Client *c = client_nou("Ana Ionescu", 820.0);
    if (c != NULL) {
        printf("%s: %.2f lei\n", c->nume, c->sold);
        free(c);
    }
    return 0;
}

Rezultat

Ana Ionescu: 820.00 lei

Exemplul 3: O copie a unui șir pe heap

Se alocă strlen + 1 octeți: unul în plus pentru '\0'. (C23 are deja funcția strdup care face asta.)

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

char *copiaza(const char *s) {
    size_t lungime = strlen(s) + 1;
    char *copie = malloc(lungime);
    if (copie != NULL) memcpy(copie, s, lungime);
    return copie;
}

int main(void) {
    char *oras = copiaza("Timișoara");
    if (oras == NULL) return 0;
    printf("%s (%zu octeți alocați)\n", oras, strlen(oras) + 1);
    free(oras);
    return 0;
}

Rezultat

Timișoara (11 octeți alocați)

Greșeli frecvente

  • Nu verifici rezultatul. Dacă malloc returnează NULL și scrii în el, programul se oprește (sau mai rău).
  • Aloci n octeți în loc de n elemente: malloc(n) pentru un tablou de int dă un sfert din cât trebuie. Scrie malloc(n * sizeof *p).
  • Uiți locul pentru '\0' când aloci un șir: malloc(strlen(s)) e cu un octet prea puțin.
  • Uiți free. Memoria rămâne ocupată până la terminarea programului (memory leak); într-un program care rulează mult timp, consumul crește continuu.
  • Citești memoria înainte să o inițializezi. malloc nu pune zerouri; valorile sunt nedeterminate.

Comenzi înrudite

  • calloc: Alocă memorie pentru un tablou de count elemente a câte size octeți și pune zero în toți octeții.
  • realloc: Schimbă dimensiunea unui bloc alocat dinamic, păstrând conținutul; poate muta blocul la altă adresă.
  • free: Eliberează un bloc alocat cu malloc, calloc sau realloc, ca memoria să poată fi refolosită.
  • void * (pointer generic): Un pointer care poate păstra adresa oricărui tip de date, dar care trebuie convertit la un tip concret înainte de folosire.
  • sizeof: Operatorul care spune câți octeți ocupă un tip sau o variabilă; calculat de compilator, rezultatul are tipul size_t.
  • strcpy, strncpy și strdup: Copiază un șir C într-un alt tablou (strcpy, strncpy) sau într-o zonă nouă alocată cu malloc (strdup).