Подтвердить что ты не робот

Передача массива в качестве аргумента функции в 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(), передавая значения, исходная копия int arr[] изменяется.

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

4b9b3361

Ответ 1

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

void arraytest(int a[])

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

void arraytest(int *a)

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

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

Ответ 2

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

Ответ 3

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

Ответ 4

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

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

  • sizeof a не совпадает с sizeof (&a[0]).
  • &a - это не то же самое, что &(&a[0]) (и не совсем то же самое, что &a[0]).
  • char b[] = "foo" не совпадает с char b[] = &("foo").

Ответ 5

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

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

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

Ответ 6

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

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

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

int func(int* arr, ...){
    .
    .
    .
}

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

Спасибо!!!

Ответ 7

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

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

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

Запись:

void arraytest(int a[])

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

void arraytest(int *a)

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

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

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

Ответ 8

Передача многомерного массива в качестве аргумента функции. Передача одного тусклого массива в качестве аргумента более или менее тривиальна. Позвольте взглянуть на более интересный случай прохождения 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 целых чисел. Я могу передать в качестве аргумента любой 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 элементов, и они являются указателями на разные типы!

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

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

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