W języku C, przekazując strukturę do funkcji przez wartość, tworzona jest pełna kopia struktury w tymczasowej przestrzeni pamięci (zwykle na stosie funkcji). Oznacza to, że jakiekolwiek zmiany w funkcji nie wpływają na oryginalny egzemplarz struktury poza funkcją.
Przekazując duże struktury przez wartość, napotykasz koszty czasowe i pamięciowe z powodu konieczności kopiowania wszystkich członów struktury. Dlatego standardową praktyką jest przekazywanie wskaźnika do struktury:
#include <stdio.h> struct Data { int arr[1000]; int flag; }; void modify_by_value(struct Data d) { d.flag = 10; // Zmienia tylko lokalną kopię } void modify_by_pointer(struct Data *d) { d->flag = 20; // Zmienia oryginał } int main() { struct Data data = { {0}, 0 }; modify_by_value(data); // data.flag == 0 modify_by_pointer(&data); // data.flag == 20 return 0; }
Zalety przekazywania przez wskaźnik:
Wady przekazywania przez wartość:
Co się stanie, jeśli funkcja zwraca strukturę przez wartość? Jakie są ryzyka?
Odpowiedź:
W C można zwracać strukturę przez wartość z funkcji, na przykład:
struct Point { int x, y; }; struct Point make_point(int x, int y) { struct Point p = {x, y}; return p; // zwracana jest kopia }
Główne ryzyko — wydajność: tworzona i zwracana jest kopia struktury. Ponadto, przy błędnym zwróceniu adresu lokalnej zmiennej struktura może wskazywać na niedopuszczalną pamięć:
struct Point* bad() { struct Point p = {1, 2}; return &p; // błąd: zwrócenie adresu lokalnej zmiennej }
Historia
Na urządzeniach wbudowanych z małym stosem programista przekazał dużą strukturę (1 KB) przez wartość, co spowodowało przepełnienie stosu i sporadyczne awarie systemu. Dochodzenie wykazało, że kopiowanie każdej struktury prowadziło do niedoboru pamięci stosu przy głębokim zagnieżdżeniu wywołania.
Historia
W systemie serwerowym dla przedsiębiorstw programista zwrócił wskaźnik do lokalnej struktury, a w kodzie wystąpił dostęp do "wąskich" wskaźników po wyjściu z funkcji. Objawiło się to krytycznym błędem segfault w środowisku produkcyjnym z rzadką powtarzalnością.
Historia
W projekcie Open Source wydajność gwałtownie spadła po przejściu na funkcję zwracającą przez wartość złożoną strukturę z wewnętrznymi tablicami. Profilator zidentyfikował koszty czasowe procesora wynikające z niepotrzebnego wielokrotnego kopiowania struktur.