Передача массива в качестве аргумента функции в 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: %dt %d",arr[0],arr[1]);
}

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

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

9 57

9 ответов:

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

void arraytest(int a[])

значит, точно так же, как

void arraytest(int *a)

так are изменение значений в main.

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

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

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

в 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)

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

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

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

передача многомерного массива в качестве аргумента функции. Передача одного тусклого массива в качестве аргумента более или менее тривиальна. Давайте взглянем на более интересный случай прохождения 2 dim массива. В 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 целых чисел. Я могу передать в качестве аргумента любой 2 dim массив, который имеет 5 колонки:
int arr1[1][5]
int arr1[2][5]
...
int arr1[20][5]
...

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

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] является a указатель на массив из 6 элементов, и они являются указателями на различные типы!

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

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]
...

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

@Бо Перссон правильно заявляет в своем великом ответе здесь:

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

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

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])

etc.

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

на практике, однако, вы должны использовать его, чтобы указать минимальный размер массива, который вы ожидаете функции по получению, так что при написании кода это легко для вас, чтобы отслеживать и проверять. The MISRA-C-2012 стандартные (купить / скачать 236-pg 2012-версия PDF стандарта за £15.00 здесь) доходит до того, чтобы заявить:

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

...

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

...

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

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