C/malloc
Deklaracja
[edytuj]#include <stdlib.h> void *calloc(size_t nmeb, size_t size); void *malloc(size_t size); void free(void *ptr); void *realloc(void *ptr, size_t size);
Argumenty
[edytuj]- nmeb
- Liczba elementów, dla których ma być przydzielona pamięć
- size
- Rozmiar (w bajtach) pamięci do zarezerwowania bądź rozmiar pojedynczego elementu
- ptr
- Wskaźnik zwrócony przez poprzednie wywołanie jednej z funkcji lub NULL
Opis
[edytuj]Funkcja calloc przydziela pamięć dla nmeb elementów o rozmiarze size każdy i zeruje przydzieloną pamięć.
Funkcja malloc przydziela pamięć o wielkości size bajtów.
Funkcja free zwalnia blok pamięci wskazywany przez ptr wcześniej przydzielony przez jedną z funkcji malloc, calloc lub realloc. Jeżeli ptr ma wartość NULL funkcja nie robi nic.
Funkcja realloc zmienia rozmiar przydzielonego wcześniej bloku pamięci wskazywanego przez ptr do size bajtów. Pierwsze n bajtów bloku nie ulegnie zmianie gdzie n jest minimum z rozmiaru starego bloku i size. Jeżeli ptr jest równy zero (tj. NULL), funkcja zachowuje się tak samo jako malloc.
Wartość zwracana
[edytuj]Jeżeli przydzielanie pamięci się powiodło, funkcje calloc, malloc i realloc zwracają wskaźnik do nowo przydzielonego bloku pamięci. W przypadku funkcji realloc może to być wartość inna niż ptr.
Jeśli jako size, nmeb podano zero, zwracany jest albo wskaźnik NULL albo prawidłowy wskaźnik, który można podać do funkcji free (zauważmy, że NULL jest też prawidłowym argumentem free).
Jeśli działanie funkcji nie powiedzie się, zwracany jest NULL i odpowiedni kod błędu jest wpisywany do zmiennej errno. Dzieje się tak zazwyczaj, gdy nie ma wystarczająco dużo miejsca w pamięci.
Przykład
[edytuj]/*UWAGA! Ten kod jest zle napisany, bardzo źle*/
#include <stdio.h>
#include <stdlib.h>
int main()
{
size_t size = 64;
float tmp, *tab;
// Przydzielenie początkowego bloku pamięci
tab = malloc(sizeof *tab * (size + 1));
if (!tab)
{
perror("malloc");
return EXIT_FAILURE;
}
// odwołanie do elementu poza tablicą
tab[size + 1] = 0;
puts("Podaj liczbe. Wpisanie nie-liczby zakonczy.");
// Odczyt liczb
while (scanf("%f", &tmp) == 1)
{
// Jeżeli zapełniono całą tablicę, trzeba ją zwiększyć
// błędny warunek - prawdziwy tylko gdy size jest równe 0
if (tab == tab + size)
{
size *= 2;
float *ptr = realloc(tab, (size + 1) * sizeof *ptr);
if (!ptr)
{
free(tab);
perror("realloc");
return EXIT_FAILURE;
}
// znowu odwołanie się do elementu poza tablicą
ptr[size + 1] = 0;
tab = ptr;
}
*tab = tmp;
++tab;
printf("Podaj liczbe: ");
}
// Wypisanie w odwrotnej kolejnosci
while (*tab)
{
--tab;
printf("%f\n", *tab);
}
// Zwolnienie pamieci i zakonczenie programu
free(tab);
return EXIT_SUCCESS;
}
Podaj liczbe. Wpisanie nie-liczby zakonczy. 10 Podaj liczbe: 15 Podaj liczbe: 30 Podaj liczbe: 35 Podaj liczbe: 70 Podaj liczbe: 75 Podaj liczbe: 75.000000 70.000000 35.000000 30.000000 15.000000 10.000000
Uwagi
[edytuj]Użycie rzutowania przy wywołaniach funkcji malloc, realloc oraz calloc w języku C jest zbędne i szkodliwe. W przypadku braku deklaracji tych funkcji (np. gdy programista zapomni dodać plik nagłówkowy stdlib.h) kompilator przyjmuje domyślną deklaracje, w której funkcja zwraca int. Przy braku rzutowania spowoduje to błąd kompilacji (z powodu niemożności skonwertowania liczby na wskaźnik) co pozwoli na szybkie wychwycenie błędu w programie. Rzutowanie powoduje, że kompilator zostaje zmuszony do przeprowadzenia konwersji typów i nie wyświetla żadnych błędów. W przypadku języka C++ rzutowanie jest konieczne.
Zastosowanie operatora sizeof z wyrażeniem (np. sizeof *tablica), a nie typem (np. sizeof float) ułatwia późniejszą modyfikację programów. Gdyby w pewnym momencie programista zdecydował się zmienić tablicę z tablicy floatów na tablice doubli, musiałby wyszukiwać wszystkie wywołania funkcji malloc, realloc i calloc, co nie jest konieczne przy użyciu operatora sizeof z wyrażeniem.
Ponieważ dla parametru size równego zero funkcja może zwrócić albo wskaźnik różny od wartości NULL albo jej równy, zwykłe sprawdzanie poprawności wywołania poprzez przyrównanie zwróconej wartości do zera może nie dać prawidłowego wyniku.
Zobacz też
[edytuj]- C/Wskaźniki (dokładne omówienie zastosowania)