Funkcja malloc() w bibliotece C z PRZYKŁADEM

⚡ Inteligentne podsumowanie

Funkcja malloc() w języku C rezerwuje blok pamięci na stercie w czasie wykonywania i zwraca wskaźnik typu void do jego pierwszego bajtu, umożliwiając programom żądanie pamięci, której rozmiar jest nieznany do momentu faktycznego wykonania kodu.

  • ???? Przydział czasu wykonania: malloc() rezerwuje pamięć podczas wykonywania, gdy wymagany rozmiar nie jest znany w momencie kompilacji.
  • 📦 Składnia: Wskaźnik cast_type otrzymuje funkcję malloc(byte_size), której rozmiar jest zwykle określany za pomocą funkcji sizeof w celu zapewnienia przenośności.
  • ⚠️ Sprawdzanie NULL: Nieudane żądanie zwraca wskaźnik NULL, dlatego przed odwołaniem się do niego należy sprawdzić poprawność wyniku.
  • Arytmetyka wskaźników: Blok jest ciągły, więc aby dotrzeć do elementów tablicy należy użyć znaku + zamiast ++.
  • 🧹 Zwolnij pamięć: Zwolnij każdy blok za pomocą free(), aby zapobiec wyciekom pamięci i zwisającym wskaźnikom.
  • 🤖 Pomoc AI: Asystenci AI i GitHub Copilot tworzą szkice wywołań malloc() i oznaczają brakujące polecenia free().

Funkcja malloc() w C

Co to jest malloc w C?

Funkcja malloc() oznacza alokację pamięci. Jest to funkcja służąca do dynamicznego przydzielania bloku pamięci. Rezerwuje przestrzeń pamięci o określonym rozmiarze i zwraca wskaźnik zerowy wskazujący lokalizację pamięci. Zwracany wskaźnik jest zwykle typu void. Oznacza to, że możemy przypisać funkcję malloc do dowolnego wskaźnika.

Co to jest malloc w C

Składnia

ptr = (cast_type *) malloc (byte_size);

Tutaj,

  • ptr jest wskaźnikiem typu rzutu.
  • Funkcja malloc zwraca wskaźnik do przydzielonej pamięci o rozmiarze bajtu.
Example: ptr = (int *) malloc (50)

Po pomyślnym wykonaniu tej instrukcji rezerwowana jest pamięć o wielkości 50 bajtów. Adres pierwszego bajtu zarezerwowanej przestrzeni jest przypisany do wskaźnika ptr typu int.

Rozważ inny przykład implementacji malloc:

#include <stdlib.h>
int main(){
int *ptr;
ptr = malloc(15 * sizeof(*ptr)); /* a block of 15 integers */
    if (ptr != NULL) {
      *(ptr + 5) = 480; /* assign 480 to sixth integer */
      printf("Value of the 6th integer is %d",*(ptr + 5));
    }
}

Wyjście:

Value of the 6th integer is 480

Należy zauważyć, że użyto sizeof(*ptr) zamiast sizeof(int), aby kod był bardziej odporny, gdy deklaracja *ptr zostanie później rzutowana na inny typ danych.

Alokacja może się nie powieść, jeśli pamięć nie jest wystarczająca. W tym przypadku zwraca wskaźnik NULL. Powinieneś więc dołączyć kod sprawdzający wskaźnik NULL.

Należy pamiętać, że przydzielona pamięć jest ciągła i można ją traktować jak tablicę. Możemy użyć wskaźnik arytmetyki do dostępu do elementów tablicy zamiast używania nawiasów [ ]. Zalecamy używanie znaku + do odwoływania się do elementów tablicy, ponieważ użycie inkrementacji ++ lub += zmienia adres przechowywany przez wskaźnik.

Funkcji Malloc można używać również z typami danych znakowych oraz złożonymi typami danych, takimi jak struktury.

Dlaczego warto używać malloc() w C?

Tablice statyczne i zwykłe zmienne ustalają swój rozmiar podczas kompilacji programu, co marnuje miejsce, gdy wymagania stają się mniejsze, i całkowicie kończy się niepowodzeniem, gdy stają się większe. Funkcja malloc() rozwiązuje ten problem, żądając pamięci w czasie wykonywania, dzięki czemu program może dostosować rozmiar bufora do dokładnej ilości danych, które otrzymuje. Ta elastyczność w czasie wykonywania jest sercem dynamiczna alokacja pamięci w C.

Dynamiczna alokacja z wykorzystaniem funkcji malloc() jest właściwym wyborem w kilku typowych sytuacjach:

  • Ilość danych wejściowych nie jest znana do momentu uruchomienia programu, np. odczytania pliku lub listy dostarczonej przez użytkownika.
  • Potrzebne są duże bloki, które przepełniłyby ograniczony stos, ponieważ malloc() czerpie dane ze znacznie większego stosu.
  • Dane muszą przetrwać funkcję, która je utworzyła, ponieważ pamięć sterty jest zachowywana do momentu jej jawnego zwolnienia.
  • Struktury i tablice muszą się powiększać lub zmniejszać podczas wykonywania programu.

Ponieważ zarezerwowany blok jest zwracany w postaci wskaźnika, można go tanio przekazywać między funkcjami, bez konieczności kopiowania danych bazowych.

Jak zwolnić pamięć przydzieloną przez malloc()

Pamięć zarezerwowana przez funkcję malloc() znajduje się na stercie i nigdy nie jest automatycznie zwalniana. Gdy program stale alokuje pamięć bez jej zwalniania, powoli zużywa całą dostępną pamięć – jest to defekt znany jako wyciek pamięci. Funkcja free() zwraca systemowi ukończony blok, aby przestrzeń mogła zostać ponownie wykorzystana.

Funkcja free() przyjmuje pojedynczy argument – ​​wskaźnik zwrócony przez funkcję malloc() – i natychmiast zwalnia cały blok:

int *ptr;
ptr = malloc(10 * sizeof(int));
if (ptr != NULL) {
    /* use the allocated memory here */
    free(ptr);   /* release the block */
    ptr = NULL;  /* avoid a dangling pointer */
}

Aby bezpiecznie zarządzać pamięcią dynamiczną, postępuj zgodnie z poniższymi zasadami:

  • Wywołuj free() dokładnie raz dla każdego pomyślnego zwolnienia funkcji malloc(); dwukrotne zwolnienie tego samego bloku powoduje niezdefiniowane zachowanie.
  • Po zwolnieniu ustaw wskaźnik na NULL, aby nie można było go ponownie wykorzystać jako wskaźnika wiszącego.
  • Nigdy nie zwalniaj wskaźnika, którego nie zwróciła funkcja malloc(), w tym wskaźnika przesuniętego przez arytmetykę wskaźników.
  • Dopasuj każdą alokację do pasującej wersji zanim wskaźnik wyjdzie poza zakres.

Keeping równomierne przydzielanie i zwalnianie pamięci stanowi podstawę ręcznego zarządzania pamięcią w języku C. Zapobiega to wyciekom i awariom spowodowanym przez ponowne wykorzystanie zwolnionej pamięci.

malloc() vs calloc(): kluczowe różnice

malloc() i kaloc() obie funkcje rezerwują pamięć sterty, ale różnią się argumentami i sposobem, w jaki traktują nowy blok. malloc() przyjmuje jeden argument, całkowitą liczbę bajtów, i pozostawia zawartość niezainicjowaną, więc blok przechowuje nieprzewidywalne wartości śmieci, dopóki program do niego nie zapisze. calloc() przyjmuje dwa argumenty, liczbę elementów i rozmiar każdego z nich, i czyści każdy bajt do zera przed zwróceniem wskaźnika.

Praktyczne różnice sprowadzają się do trzech punktów:

  • Inicjalizacja: calloc() zeruje pamięć, podczas gdy malloc() tego nie robi, co sprawia, że ​​malloc() działa odrobinę szybciej, gdy wartości i tak zostaną nadpisane.
  • Argumenty: piszesz malloc(n * size), ale calloc(n, size) aby zarezerwować tę samą tablicę.
  • Przypadek użycia: wybierz calloc(), gdy liczy się czysty, wyzerowany blok, a malloc(), gdy zależy Ci na szybkości, a inicjalizacja jest obsługiwana ręcznie.

Obie funkcje są zadeklarowane w stdlib.h, obie zwracają wskaźnik typu void lub wartość NULL w przypadku błędu i obie przekazują swoją pamięć za pomocą tej samej funkcji free().

FAQ

W języku C rzutowanie jest opcjonalne i często niezalecane, ponieważ void* automatycznie konwertuje się na dowolny wskaźnik do obiektu, a jawne rzutowanie może maskować brakujący element dołączony do pliku stdlib.h. C++, jednakże obsada jest wymagana.

Zwrócenie wartości NULL oznacza, że ​​żądanie nie powiodło się, zazwyczaj z powodu braku pamięci. Zawsze sprawdzaj wskaźnik przed jego użyciem, ponieważ dereferencja wartości NULL prowadzi do niezdefiniowanego zachowania i zazwyczaj powoduje awarię programu.

realloc() zmienia rozmiar bloku wcześniej zarezerwowanego przez malloc(), keeping istniejące dane do mniejszego rozmiaru. W przypadku niepowodzenia zwraca NULL i pozostawia oryginalny blok nienaruszony, dlatego najpierw należy przypisać wynik do wskaźnika tymczasowego.

Wyciek pamięci występuje, gdy pamięć sterty z funkcji malloc() nigdy nie zostaje zwolniona za pomocą funkcji free(). Program rezerwuje przestrzeń, której już nie używa, co może stopniowo wyczerpać dostępną dla niego pamięć.

Funkcja malloc() rezerwuje pamięć na stercie, a nie na stosie. Bloki sterty pozostają ważne do momentu wywołania funkcji free(), dzięki czemu mogą przetrwać funkcję, która je utworzyła, w przeciwieństwie do automatycznych zmiennych stosu, które znikają po zwróceniu.

malloc() to funkcja biblioteczna zwracająca void* i wymagająca sizeof do obliczenia bajtów. C++ new to operator zwracający wskaźnik typu i wywołujący konstruktory. Połącz malloc() z free(), a new z delete.

Tak. Asystenci kodowania AI projektują wywołania malloc(), wstawiają NULL-e i sygnalizują brakujące wywołania free() lub wycieki, a także potrafią objaśnić arytmetykę wskaźników. Zawsze kompiluj i testuj wygenerowany kod przed zatwierdzeniem go.

Drugi pilot GitHub sugeruje użycie linii malloc(), sizeof() i pasujących linii free() z komentarza opisującego Twój zamiar. RevPrzed kompilacją zapoznaj się ze wszystkimi sugestiami dotyczącymi brakujących kontroli wartości NULL i wycieków.

Podsumuj ten post następująco: