C/Wskaźniki: Różnice pomiędzy wersjami

Usunięte 169 bajtów ,  7 lat temu
→‎Obsługa pamięci: czytelna poprawka (*tablica), poprawione dla pozostałych miejsc / int main jest tu całkowicie zbędny, w pozostałych fragmentach był też pominięty
(→‎Obsługa pamięci: czytelna poprawka (*tablica), poprawione dla pozostałych miejsc / int main jest tu całkowicie zbędny, w pozostałych fragmentach był też pominięty)
Załóżmy, że chcemy stworzyć tablicę liczb typu float:
<source lang="C">
#include <stdlib.h>
 
int main()
{
int rozmiar;
float *tablica;
tablica = (float*) malloc(rozmiar * sizeof(*tablica)); //pierwsza gwiazdka (*) w funkcji malloc() to operator mnozenia
tablica[0] = 0.1;
//program jest niekompletny, barkuje w nim zwolnienia pamieci, jesli chcesz go uruchomic, musisz dopisac zwalnianie pamieci
 
return 0;
}
</source>
 
Przeanalizujmy teraz po kolei, co dzieje się w powyższym fragmencie. Najpierw deklarujemy zmienne - rozmiar tablicy i wskaźnik, który będzie wskazywał obszar w pamięci, gdzie będzie trzymana tablica. Do zmiennej "rozmiar" możemy w trakcie działania programu przypisać cokolwiek - wczytać ją z pliku, z klawiatury, obliczyć, wylosować - nie jest to istotne. <tt>rozmiar * sizeof (*tablica)</tt> oblicza potrzebną wielkość tablicy. Dla każdej zmiennej float potrzebujemy tyle bajtów, ile zajmuje ten typ danych. Ponieważ może się to różnić na rozmaitych maszynach, istnieje operator '''sizeof''', zwracający dla danego wyrażenia rozmiar jego typu w bajtach.
 
W wielu książkach (również K&Rv2) i w Internecie stosuje się inny schemat użycia funkcji malloc a mianowicie: <tt>tablica = (float*)malloc(rozmiar * sizeof(float))</tt>. Takie użycie należy traktować jako błędne, gdyż nie sprzyja ono poprawnemu wykrywaniu błędów.
Rozważmy sytuację, gdy programista zapomni dodać plik nagłówkowy stdlib.h, wówczas kompilator (z braku deklaracji funkcji malloc) przyjmie, że zwraca ona typ int, zatem do zmiennej <tt>tablica</tt> (która jest wskaźnikiem) będzie przypisywana liczba całkowita, co od razu spowoduje błąd kompilacji (a przynajmniej ostrzeżenie), dzięki czemu będzie można szybko poprawić kod programu. Rzutowanie jest konieczne tylko w języku C++, gdzie konwersja z <tt>void*</tt> na inne typy wskaźnikowe nie jest domyślna, ale język ten oferuje nowe sposoby alokacji pamięci.
 
Teraz rozważmy sytuację, gdy zdecydujemy się zwiększyć dokładność obliczeń i zamiast typu float użyć typu double. Będziemy musieli wyszukać wszystkie wywołania funkcji malloc, calloc i realloc odnoszące się do naszej tablicy i zmieniać wszędzie <tt>sizeof(float)</tt> na <tt>sizeof(double)</tt>. Aby temu zapobiec lepiej od razu użyć <tt>sizeof (*tablica)</tt> (lub jeśli ktoś woli z nawiasami: <tt>sizeof(*tablica)</tt>), wówczas zmiana typu zmiennej <tt>tablica</tt> na <tt>double*</tt> zostanie od razu uwzględniona przy alokacji pamięci.
 
Dodatkowo, należy sprawdzić, czy funkcja malloc nie zwróciła wartości NULL - dzieje się tak, gdy zabrakło pamięci. Ale uwaga: może się tak stać również jeżeli jako argument funkcji podano zero.
Czasami możemy potrzebować zmienić rozmiar już przydzielonego bloku pamięci. Tu z pomocą przychodzi funkcja [[C/realloc|realloc]]:
<source lang="C">
tablica = realloc(tablica, 2*rozmiar*sizeof (*tablica));
</source>
 
rozmiar = 3;
tablica = (float*) calloc(rozmiar, sizeof (*tablica));
tablica[0] = 0.1;
</source>
8268

edycji