В языке C аргументы в функции всегда передаются по значению. Это означает, что функция получает копию значения аргумента. Для простых типов (int, float) это очевидно: изменения внутри функции не влияют на оригинальную переменную. Для массивов и структур есть нюансы:
Пример: обработка массива и структуры
#include <stdio.h> typedef struct { int a; int b; } Pair; void modifyArray(int arr[], int size) { arr[0] = 42; // модифицирует исходный массив } void modifyStruct(Pair s) { s.a = 100; // изменяет только локальную копию } void modifyStructPtr(Pair *s) { s->a = 200; // меняет оригинал через указатель } 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; }
Вопрос: Если функция объявлена как void func(int arr[10]), всегда ли этот массив внутри функции будет иметь 10 элементов?
Ответ: Нет. Запись int arr[10] в аргументах на самом деле равнозначна int *arr — размер массива теряется при передаче. Функция не знает реальной длины массива, поэтому всегда принимайте дополнительный параметр с его длиной. Иначе возможны выходы за границы массива и UB.
Пример:
void foo(int arr[10]) { printf("%d ", arr[9]); // arr не обязательно содержит 10 элементов! }
История
В проекте на обработку сигналов передавали массив через функцию, рассчитывая, что его длина всегда одинакова, но в одном случае передали меньший массив. Результат — обращение за границы памяти, падение приложения и появление непредсказуемого поведения на контроллере.
История
В банковском ПО пытались модифицировать структуру, передавая её по значению, а не по указателю. Изменения не сохранялись, из-за чего процессинговый модуль не обновлял состояние счетов, приводя к ошибкам в расчётах.
История
В системе телеметрии студент добавил функцию очистки массива, но забыл передать длину, а массивы были разного размера. Ошибка обнаружилась только после сбора большого объёма некорректных данных и длительного времени поиска багов.