Передача массивов, указателей на int в C - PullRequest
2 голосов
/ 07 февраля 2011

Я новичок в C для численного анализа после многих лет работы с Matlab.У меня есть функция, которая создает массив, и мне нужно вернуть его к main ().У меня были обычные проблемы с массивами и указателями, и, поигравшись, выяснил, как это сделать.Но возмущение оставило мне концептуальный вопрос, основанный на следующем коде.

#include <stdio.h>
void array_set(int y_out[2][2]);
void int_set_wrong(int  y);
void int_set_right(int *y);


int main (int argc, const char * argv[]) {

    int y_array[2][2]={{0,0},{0,0}};
    int y_int_1 = 0;
    int y_int_2 = 0;

    array_set(y_array);
    int_set_wrong(  y_int_1 );
    int_set_right( &y_int_2 );

    printf("\nValue array: %d \n",y_array[0][0]);
    printf("Value int wrong: %d \n",y_int_1);
    printf("Value int right: %d \n",y_int_2);

    return 0;
}

void array_set(int y_out[2][2]){

    y_out[0][0] = 10;
    y_out[1][0] = 20;
    y_out[0][1] = 1;
    y_out[1][1] = 2;
}

void int_set_wrong(int y){

    y = 10;

}

void int_set_right(int * y){

    *y = 10;

}

Вышеприведенный фрагмент возвращает: массив значений: 10 значение int неправильное: 0 значение int right: 10

Myвопрос состоит в нескольких частях, сначала

, почему работает функция 'array_set'?Я ожидаю, что он потерпит неудачу так же, как это сделал int_set_wrong.

Как по-разному обрабатываются массивы ints и int при обработке?есть локальная версия y?

Если так, то почему нет локальной версии y_out при настройке массива?

Спасибо за помощь.Кроме того, если есть что-то, что вызовет проблемы с моей реализацией array_set, пожалуйста, включите.

- Эндрю

Ответы [ 5 ]

1 голос
/ 07 февраля 2011

В int_set_right() вы передали адрес переменной y_int_2 (которую вы объявили и определили в main()) через оператор &.

int_set_right( &y_int_2 );

Поскольку функция имела доступ к фактической переменной y_int_2 через указатель y (установленный на значение адреса y_int_2 из &y_int_2), вы присвоили y_int_2значение 10 при назначении *y = 10.

Вы можете прочитать *y = 10 как:

значение переменной, адрес которой хранится в y, теперьдля 10

Но для y_int_1, вы просто передали значение .Поэтому при вызове int_set_wrong() была создана временная переменная, которая была инициализирована значением из y_int_1.Поэтому все, что вы сделали, это изменили временное значение переменной local (local to int_set_wrong()).

Вот почему y_int_1, объявленное в main(), не затронутоint_set_wrong().

array_set работает, потому что вы передали адрес y_array функции через переменную y_out (которая является указателем типа y в int_set_right).

0 голосов
/ 07 февраля 2011

Вы создали 3 функции.

array_set(y_array);

До этого вы создали массив чисел со строкой.

int y_array[2][2]={{0,0},{0,0}};

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

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

При передаче массива для экономии памяти и времени C по умолчанию передается указатель.

void int_set_wrong(int  y);

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

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

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

0 голосов
/ 07 февраля 2011

Ваша функция работает, потому что в C самый внутренний [] в аргументах функции (и только там!) Эквивалентен аргументу-указателю.Ваша декларация эквивалентна

void array_set(int (*y_out)[2]){
..
}

То есть y_out является указателем на int[2].

0 голосов
/ 07 февраля 2011

Функция array_set работает, потому что когда вы передаете массив в функцию, вы действительно передаете указатель. Затем внутри функции вы отменяете ссылку на массив, используя «y_out [0] [0] = 10» и т. Д. Когда вы используете нотацию массива, она автоматически отменяет ссылку на указатель массива, чтобы вы могли установить значения в массив.

Ints полностью отличаются от массивов int. Массив можно рассматривать почти в каждом случае как указатель, в данном случае указатель на int. Int является фактическим числовым значением. Поэтому, когда вы передаете int в функцию int_set_wrong, она копируется (это именно то, что делает C / C ++), и вы устанавливаете локальную переменную y, а не int, в который вы передали.

На третий вопрос ответили и в первом абзаце. Надеюсь, это прояснит ситуацию.

0 голосов
/ 07 февраля 2011

Массивы передаются с использованием указателей, а не всего массива, копируемого по значению в стеке. Ваш двумерный массив делает объяснение этого сложного, но рассмотрим одномерную версию:

void f(int x[]){
    x[0] = 1;
    x[1] = 2;
}

Вы могли бы эквивалентно написать это как:

void f(int *x){
    x[0] = 1;
    x[1] = 2;
}

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

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