W języku C argumenty w funkcjach zawsze są przekazywane przez wartość. Oznacza to, że funkcja otrzymuje kopię wartości argumentu. Dla podstawowych typów (int, float) jest to oczywiste: zmiany wewnątrz funkcji nie wpływają na oryginalną zmienną. Dla tablic i struktur są pewne niuanse:
Przykład: obróbka tablicy i struktury
#include <stdio.h> typedef struct { int a; int b; } Pair; void modifyArray(int arr[], int size) { arr[0] = 42; // modyfikuje oryginalną tablicę } void modifyStruct(Pair s) { s.a = 100; // zmienia tylko lokalną kopię } void modifyStructPtr(Pair *s) { s->a = 200; // zmienia oryginał przez wskaźnik } int main() { int nums[2] = {1, 2}; Pair p = {10, 20}; modifyArray(nums, 2); modifyStruct(p); modifyStructPtr(&p); printf("nums[0]=%d, p.a=%d ", nums[0], p.a); // nums[0]=42, p.a=200 return 0; }
Pytanie: Jeśli funkcja jest zadeklarowana jako void func(int arr[10]), czy ta tablica wewnątrz funkcji zawsze będzie miała 10 elementów?
Odpowiedź: Nie. Zapis int arr[10] w argumentach tak naprawdę jest równoważny int *arr — rozmiar tablicy gubi się podczas przekazywania. Funkcja nie zna rzeczywistej długości tablicy, dlatego zawsze przyjmuj dodatkowy parametr z jej długością. W przeciwnym razie mogą wystąpić nadmiarowe odwołania do pamięci i UB.
Przykład:
void foo(int arr[10]) { printf("%d ", arr[9]); // arr niekoniecznie zawiera 10 elementów! }
Historia
W projekcie do przetwarzania sygnałów przekazano tablicę przez funkcję, zakładając, że jej długość zawsze jest taka sama, ale w jednym przypadku przekazano mniejszą tablicę. Wynik — odwołanie poza zakres pamięci, awaria aplikacji oraz nieprzewidywalne zachowanie na kontrolerze.
Historia
W oprogramowaniu bankowym próbowano modyfikować strukturę, przekazując ją przez wartość, a nie przez wskaźnik. Zmiany nie były zapisywane, przez co moduł przetwarzający nie aktualizował stanu kont, co prowadziło do błędów w obliczeniach.
Historia
W systemie telemetrycznym student dodał funkcję czyszczenia tablicy, ale zapomniał przekazać długość, a tablice miały różne rozmiary. Błąd został odkryty dopiero po zebraniu dużej ilości niepoprawnych danych i długim czasie poszukiwania błędów.