Как вызываемая функция интерпретирует адрес массива при использовании вызываемого по ссылке? - PullRequest
0 голосов
/ 17 февраля 2020

В примере, взятом из книги, я хочу полностью понять, как на самом деле работает передача и массив по ссылке. Играя с приведенным ниже кодом в Code Blocks и немного читая здесь и там, я получаю, что передача по значению не меняет начальное значение переменной (example_pass_by_value). Что касается двух других переменных, адреса которых передаются по ссылке на функцию изменения, я понимал только пример example_pass_by_reference: при вызове функции, подобной этой «change (& example_pass_by_reference), вы фактически ставите знак« = »между формальным параметром «by_reference» (это объявляется как указатель в определении функции изменения) и адрес переменной «example_pass_by_reference», где c передается в функцию изменения (например: by_reference = 0x6644fe или лучше by_reference = & example_pass_by_reference); Не понимаю, как "=" помещается между адресом массива в вызове функции "change (array, ....) и формальным параметром" int arr [] "из определения функции" change ( int arr [], ...) ", поскольку int arr [] является массивом, а не указателем, чтобы иметь возможность получить адрес переменной" array ". (например, int arr [] = array или int arr [ ] = 0x7856ff, например); Заранее благодарю и извиняюсь за последующие ошибки в моем коде или языке.

#include <stdio.h>
#include <string.h>

main()
{
    int array[3] = {1,2,3};
    int example_pass_by_value = 5;
    int example_pass_by_reference = 6;

    change(array, example_pass_by_value, &example_pass_by_reference);

    printf("Back in main(), the array[1] is now %d.\n", array[1]);
    printf("Back in main(), the example_pass_by_value is now %d.\n, unchanged", example_pass_by_value);
    printf("Back in main(), the example_pass_by_reference is now %d.\n", example_pass_by_reference);
    return(0); 
}

/******************************************************************/

change(int arr[], int by_value, int *by_reference)  
{
    // Changes made to all three variables; 
      arr[1] = 10;
      by_value = 100;
      *by_reference = 1000;
      return; 
}

Ответы [ 2 ]

2 голосов
/ 17 февраля 2020

В этом объявлении функции:

void change(int arr[], int by_value, int *by_reference)

C не поддерживает передачу массивов в качестве аргументов. Когда вы объявляете параметр как массив, компилятор автоматически настраивает его как указатель. Таким образом, это объявление выглядит так:

void change(int *arr, int by_value, int *by_reference)

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

Для соответствия автомату c При корректировке в объявлении C также автоматически преобразует массивы в аргументы (и большинство других выражений). В вызове функции:

change(array, example_pass_by_value, &example_pass_by_reference);

Массив array автоматически преобразуется в указатель на свой первый элемент, как если бы это было:

change(&array[0], example_pass_by_value, &example_pass_by_reference);

Теперь давайте посмотрим на код внутри функции. Это утверждение:

arr[1] = 10;

говорит, что нужно взять указатель arr, который имеет адрес первого элемента array, добавить 1 к нему и использовать там элемент. Один элемент за array[0] равен array[1], поэтому arr[1] относится к array[1]. Это утверждение присваивает ему 10. Так что array[1] становится десятью. Обратите внимание, что массив не был передан по значению, потому что C автоматически преобразовал его в указатель. Указатель был передан по значению, и указатель дает нам ссылку на элементы массива, а arr[1] использует эту ссылку для доступа к элементам массива.

Этот оператор:

by_value = 100;

устанавливает параметр by_value равным 100. Поскольку он только изменяет параметр, он не изменяет аргумент example_pass_by_value в главной функции.

Этот оператор:

*by_reference = 1000;

использует указатель by_reference для доступа к int в памяти. Оператор * говорит использовать указатель для ссылки на объект, на который он указывает. Таким образом, этот оператор присваивает значение 1000 int, на которое указывает by_reference. Указатель by_reference был передан по значению и предоставляет ссылку на example_pass_by_reference, поскольку в качестве аргумента передан адрес example_pass_by_reference.

1 голос
/ 17 февраля 2020

Для начала типичной ошибкой тех, кто не знает C, является следующее утверждение:

C не передает ничего по ссылке, не имеет ссылок

C не имеет ссылок в том смысле, как в C ++, но имеет механизм передачи по ссылке .

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

В C указатели играют роль ссылок. Из C Standard

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

Таким образом, передача по ссылке в C означает передачу объекта через указатель на объект.

Что касается вашего вопроса, то массивы используемые в выражениях (за редким исключением, как, например, использование в операторе sizeof) неявно преобразуются в указатели на их первые элементы.

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

void f( int a[] );

//...
int a[] = { 1, 2, 3, 4, 6 };

f( a );

like

void f( int a[] );

//...
int a[] = { 1, 2, 3, 4, 6 };

int *tmp = a;    
f( tmp );

или то же самое

void f( int a[] );

//...
int a[] = { 1, 2, 3, 4, 6 };

int *tmp = &a[0];    
f( tmp );

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

Так, например, эти два объявления функций эквивалентны и объявляют одну и ту же функцию

void f( int a[] );
void f( int *a );

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

Например, этот оператор

arr[1] = 10;

оценивается компилятором как

*( arr + 1 ) = 10;

где arr - указатель на первый элемент массива.

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