Передача массива в качестве аргумента функции в C

Я написал функцию, содержащую массив в качестве аргумента, и вызываю ее, передавая значение массива следующим образом.

void arraytest(int a[]) { // changed the array a a[0]=a[0]+a[1]; a[1]=a[0]-a[1]; a[0]=a[0]-a[1]; } void main() { int arr[]={1,2}; printf("%d \t %d",arr[0],arr[1]); arraytest(arr); printf("\n After calling fun arr contains: %d\t %d",arr[0],arr[1]); } 

Я обнаружил, что, хотя я arraytest() функцию arraytest() , передавая значения, изменяется исходная копия int arr[] .

Не могли бы вы объяснить, почему?

При передаче массива в качестве параметра это

 void arraytest(int a[]) 

означает то же самое, что и

 void arraytest(int *a) 

поэтому вы изменяете значения в основном.

По историческим причинам массивы не являются гражданами первого classа и не могут быть переданы по стоимости.

Вы не передаете массив как копию. Это только указатель, указывающий на адрес, где находится первый элемент в памяти.

Вы передаете адрес первого элемента массива

В C, за исключением нескольких особых случаев, ссылка на массив всегда «распадается» на указатель на первый элемент массива. Следовательно, невозможно передать массив «по значению». Массив в вызове функции будет передан функции как указатель, который аналогичен передаче массива по ссылке.

EDIT: Есть три таких особых случая, когда массив не распадается на указатель на его первый элемент:

  1. sizeof a не совпадает с sizeof (&a[0]) .
  2. &a не совпадает с &(&a[0]) (и не совсем так же, как &a[0] ).
  3. char b[] = "foo" не совпадает с char b[] = &("foo") .

Вы передаете значение ячейки памяти первого элемента массива.

Поэтому, когда вы начинаете изменять массив внутри функции, вы изменяете исходный массив.

Помните, что a[1]*(a+1) .

Если вы хотите передать одномерный массив в качестве аргумента в функции , вам придется объявить формальный параметр одним из следующих трех способов, и все три метода декларации дают похожие результаты, поскольку каждый сообщает компилятору, что целые указатели идут для получения .

 int func(int arr[], ...){ . . . } int func(int arr[SIZE], ...){ . . . } int func(int* arr, ...){ . . . } 

Таким образом, вы изменяете исходные значения.

Благодаря !!!

Массивы в C преобразуются, в большинстве случаев, в указатель на первый элемент самого массива. И более подробно массивы, переданные в функции, всегда преобразуются в указатели.

Здесь цитата из K & R2nd :

Когда имя массива передается функции, то передается местоположение исходного элемента. Внутри вызываемой функции этот аргумент является локальной переменной, поэтому параметр имени массива является указателем, то есть переменной, содержащей адрес.

Письмо:

 void arraytest(int a[]) 

имеет такое же значение, как и запись:

 void arraytest(int *a) 

Поэтому, несмотря на то, что вы не пишете его явно, это происходит, когда вы передаете указатель, и поэтому вы изменяете значения в главном.

Для более я действительно предлагаю прочитать это .

Более того, вы можете найти другие ответы на SO здесь

Передача многомерного массива в качестве аргумента функции. Передача одного тусклого массива в качестве аргумента более или менее тривиальна. Давайте рассмотрим более интересный случай прохождения 2-мерного массива. В C вы не можете использовать указатель на конструкцию указателя (int **) вместо 2 dim-массива. Приведем пример:

 void assignZeros(int(*arr)[5], const int rows) { for (int i = 0; i < rows; i++) { for (int j = 0; j < 5; j++) { *(*(arr + i) + j) = 0; // or equivalent assignment arr[i][j] = 0; } } 

Здесь я указал функцию, которая принимает в качестве первого аргумента указатель на массив из 5 ints. Я могу передать в качестве аргумента любой 2-мерный массив, который имеет 5 столбцов:

 int arr1[1][5] int arr1[2][5] ... int arr1[20][5] ... 

Вы можете придумать более общую функцию, которая может принимать любой 2-мерный массив и изменять сигнатуру функции следующим образом:

 void assignZeros(int ** arr, const int rows, const int cols) { for (int i = 0; i < rows; i++) { for (int j = 0; j < cols; j++) { *(*(arr + i) + j) = 0; } } } 

Этот код будет скомпилирован, но вы получите ошибку времени выполнения при попытке присвоить значения так же, как и в первой функции. Таким образом, в C многомерные массивы не совпадают с указателями на указатели ... указателями. Int (* arr) [5] является указателем на массив из 5 элементов, int (* arr) [6] является указателем на массив из 6 элементов, и они являются указателями на разные типы!

Ну, как определить аргументы функций для более высоких измерений? Просто, мы просто следуем шаблону! Он имеет ту же функцию, которая настроена так, чтобы иметь массив из трех измерений:

 void assignZeros2(int(*arr)[4][5], const int dim1, const int dim2, const int dim3) { for (int i = 0; i < dim1; i++) { for (int j = 0; j < dim2; j++) { for (int k = 0; k < dim3; k++) { *(*(*(arr + i) + j) + k) = 0; // or equivalent assignment arr[i][j][k] = 0; } } } } 

Как и следовало ожидать, в качестве аргумента он может принимать любые 3-х мерные массивы, которые имеют во втором измерении 4 элемента и в элементах третьего измерения 5. Что-нибудь вроде этого было бы в порядке:

 arr[1][4][5] arr[2][4][5] ... arr[10][4][5] ... 

Но мы должны указать все размеры размеров до первого.

@Bo Persson правильно заявляет в своем замечательном ответе здесь :

=================================================

При передаче массива в качестве параметра это

 void arraytest(int a[]) 

означает то же самое, что и

 void arraytest(int *a) 

=================================================

Однако позвольте мне также добавить, что это:

означает то же самое, что и

 void arraytest(int a[0]) 

что означает то же самое, что и

 void arraytest(int a[1]) 

что означает то же самое, что и

 void arraytest(int a[2]) 

что означает то же самое, что и

 void arraytest(int a[1000]) 

и т.п.

По сути, значение «размер» внутри параметра массива здесь, по-видимому, предназначено только для эстетической / самостоятельной документации, и может быть любым положительным целым числом (тип size_t я думаю) вам нужно!

На практике, однако, вы должны использовать его для указания минимального размера массива, который вы ожидаете получить от функции, так что при написании кода вам легко отслеживать и проверять. Стандарт MISRA-C-2012 ( купить / скачать 236-страничный PDF-версия стандарта стандарта за 15,00 фунтов стерлингов здесь ) доходит до того, чтобы заявить:

Правило 17.5. Аргумент функции, соответствующий параметру, объявленному для типа массива, должен иметь соответствующее количество элементов.

Если параметр объявлен как массив с указанным размером, соответствующий аргумент в каждом вызове функции должен указывать на объект, у которого есть как минимум столько же элементов, сколько массив.

Использование декларатора массива для параметра функции более четко определяет интерфейс функции, чем использование указателя. Минимальное количество элементов, ожидаемых функцией, явно указано, тогда как это невозможно с указателем. [выделено курсивом]

Другими словами, они рекомендуют использовать формат явного размера, даже несмотря на то, что стандарт C его технически не обеспечивает его соблюдение – он по крайней мере помогает разъяснить вам как разработчика, а другим – с помощью кода, какой размер массива ожидает функция вы должны пройти.

  • Почему индексирование начинается с нуля в 'C'?
  • Давайте будем гением компьютера.