Передача массива в функцию против передачи переменных в функцию - PullRequest
3 голосов
/ 15 апреля 2020

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

В чем разница между передачей переменной в функцию и передачей массива в функцию в C?

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

Чтобы прояснить вопрос, я прилагаю код, который объяснит что я спрашиваю -

Код 1:

//Passing variable to function
#include<stdio.h>
void swap(int x, int y);
int main(void)
{
//Nothing is happening to real values of variables
    int x, y;
    x = 1; 
    y = 2;
    swap(x, y);
    printf("%d = x \n %d = y", x, y);
}

void swap(int x, int y)
{
    int temp;
    temp = x;
    x = y;
    y = temp;
}

Код 2:

//Here you can see the values of arrays are swapped.
#include<stdio.h>
void swap(int arr[]);


int main(void)
{
    int idx, array[2];
    for(idx = 0; idx < 2; idx++ )
    {
        scanf("%d", &array[idx]);
    }
    swap(array);
    for(idx = 0; idx < 2; idx++, printf("\n"))
    {
        printf("%d", array[idx]);
    }
}

void swap(int arr[])
{
    int temp;
    temp = arr[0];
    arr[0] = arr[1];
    arr[1] = temp;
}

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

Ответы [ 5 ]

4 голосов
/ 15 апреля 2020

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

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

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

Из C стандарта (6.3.2.1 L-значения, массивы и обозначения функций)

3 За исключением случаев, когда это операнд оператора sizeof или унарный оператор &, или является строковым литералом, используемым для инициализации массива, выражение с типом '' массив типа '' преобразуется в выражение с типом '' указатель на тип '', которое указывает на начальный элемент объекта массива и не является lvalue. Если объект массива имеет класс хранения регистров, поведение не определено.

Таким образом, имея указатель на объект, вы можете изменить указанный объект.

Предположим, что у вас есть две функции .

void f( int x )
{
   x = 10;
}

and

void g( int *px )
{
    *px = 10;
}

и их вызовы

int n = 0;

f( n );
g( &n );

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

int n = 0;

f( n );
g( &n );

// ...

void f( /* int x */ )
{
   int x = n;
   x = 10;
}

void g( /* int *px */ )
{
    int *px = &n;
    *px = 10;
}

То есть обе функции имеют дело с копиями значений выражений, используемых в качестве аргументов функции. Но в случае функции g, поскольку функция получает значение адреса указанного объекта n, вы можете изменить указанный объект n, используя указатель (адрес).

В терминах C Передача объекта в функцию косвенно через указатель на объект называется передачей по ссылке.

Из C Стандарт

- Тип указателя может быть происходит от типа функции или типа объекта, называемого ссылочным типом. Тип указателя описывает объект, значение которого предоставляет ссылку на объект ссылочного типа. Тип указателя, полученный из ссылочного типа T, иногда называют «указателем на T». Конструкция типа указателя из ссылочного типа называется «выводом типа указателя». Тип указателя является полным типом объекта.

Обратите внимание на то, что объявление функции, подобное этому

void f( int a[], size_t n );

, эквивалентно следующему объявлению

void f( int *a, size_t n );

И оба объявляют одну и ту же функцию.

Если у вас есть массив, как, например,

#define N 10
//...
int a[N];

, то он передается в функцию, такую ​​как

f( a, N );

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

void f( int *a, size_t n )
{
    for ( int i = 0; i < n; i++ )
    {
        a[i] = i;
        // that is the same as
        // *( a + i ) = i;
    }
}
2 голосов
/ 15 апреля 2020

В чем разница между передачей переменной в функцию и передачей массива в функцию в C?

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

Если относительный параметр функции имеет соответствующий тип указателя, здесь int * или int a[], это допустимо.

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

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


Таким образом, в первом примере вы не меняете местами значения x и y в main(). Вы изменяете только x и y внутри swap(), что довольно бесполезно.

Если вы хотите поменять x и y в основном, вам нужно определить swap() как:

void swap(int* x, int* y)
{
    int temp;
    temp = *x;
    *x = *y;
    *y = temp;
}

и позвонить swap() как:

swap(&x, &y);

Предлагаю вам больше узнать об указателях.

2 голосов
/ 15 апреля 2020

Когда вы передаете массив, вы фактически передаете его базовый адрес, который является указателем на первый элемент массива в памяти. По сути, это вызов по ссылке, поэтому вам не нужно явно использовать ссылку или & при передаче в функцию подкачки. arr распадается на &(arr[0]).

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

1 голос
/ 15 апреля 2020

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

Когда вы передаете массив функции в качестве аргумента, адрес первого элемента массива копируется в локальную переменную, относящуюся к функции.

В этом и заключается разница между передачей обычной переменной и передачей массива в функцию.

Существует одна проблема с вашим восприятие хотя. Если вы хотите изменить обычную переменную, которая будет передана в функцию, вам нужно передать ее адрес функции, поэтому функция должна принимать тип указателя. Поэтому просто используйте обозначение указателя, то есть int *p, а не int p[], хотя они эквивалентны в качестве параметров функции.

Ваш код должен выглядеть следующим образом:

#include<stdio.h>

void swap(int *x, int *y);

int main(void)
{
    int x, y;

    x = 1;
    y = 2;

    swap(&x, &y);
    printf("%d = x \n %d = y", x, y);
}

void swap(int *x, int *y)
{
    int temp;
    temp = *x;
    *x = *y;
    *y = temp;
}
1 голос
/ 15 апреля 2020

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

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

void arraytest(int a[])

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

void arraytest(int *a)

, поэтому вы изменяете значения в main. Однако в C аргументы функции всегда передаются по значению. В случае массива (переменной), передаваемого в качестве аргумента функции, он распадается на указатель на первый элемент массива. Затем указатель передается по значению, как обычно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...