Почему тип arrayp [] совпадает с типом * arrayp в качестве параметра функции? - PullRequest
2 голосов
/ 06 января 2020

Почему fe int arrayp[] совпадает с int* arrayp, как параметр в определении / объявлении функции?

 int* foo(int arrayp[]){}

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

Как:

 #include <stdio.h>

 int* foo (int arrayp[]);

 int main(void)
 {
    int a[] = { 10,5,4,2,1 };
    int *p;

    p = foo(a);

    printf("%d",*p);

    return 0;
 }

 int* foo(int arrayp[])
 {
     *arrayp = 0;
     return arrayp;          
 }

Почему int arrayp[] является указателем на первый элемент массива типа int? ИМХО я думаю это очень запутанно. Некоторые люди могут подумать, что они передают введенный массив (передаваемый по значению) с этим выражением.

Ответы [ 2 ]

4 голосов
/ 06 января 2020

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

Таким образом, эти пары объявлений функций, например, совместимы:

void foo(int a[]);
void foo(int *a);  //compatible declaration

void bar(int a[][2][3]);
void bar(int (*a)[2][3]);  //compatible declaration

Деннис Ритч ie (автор языка) объясняет это запутанное правило в https://www.bell-labs.com/usr/dmr/www/chist.html

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

int f (a) int a []; {...} живое ископаемое, остаток от способа объявления указателя НБ; a, только в этом особом случае, интерпретируется в C как указатель. Нотация сохранилась частично ради совместимости, частично благодаря рационализации, которая позволила бы программистам сообщать своим читателям намерение передать указатель fa, сгенерированный из массива, а не ссылку на одно целое число. К сожалению, это сбивает с толку ученика и предупреждает читателя.

(Примечание. В Chist. html используется определение функции в стиле K & R. Прототипом эквивалента приведенного выше определения функции будет int f( int a[]){ ... }.)

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

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

void takeFuncPtr(void Func(void));
void takeFuncPtr(void (*Func)(void)); //compatible declaration

Возможно, более глубокий вопрос заключается в том, «почему массивы распадаются на указатели в C»? Связанный документ также дает ответ на этот вопрос:

... Эта семантика представляет собой простой переход от B, и я экспериментировал с ними в течение нескольких месяцев. Проблемы стали очевидны, когда я попытался расширить нотацию типов, особенно для добавления структурированных (записей) типов. Кажется, структуры должны интуитивно отображаться в памяти на машине, но в структуре, содержащей массив, не было хорошего места для хранения sh указателя, содержащего основание массива, или какого-либо удобного способа размещения чтобы оно было инициализировано. Например, записи каталога ранних систем Unix могут быть описаны в C как

struct {int inumber; имя персонажа [14]; };

Я хотел, чтобы структура не просто характеризовала абстрактный объект, но и описывала набор битов, которые могут быть прочитаны из каталога. Где компилятор может скрыть указатель на имя, требуемое семантикой? Даже если бы структуры рассматривались более абстрактно, а пространство для указателей могло бы быть каким-то образом скрыто, как я мог бы решить техническую проблему правильной инициализации этих указателей при выделении сложного объекта, возможно, такого, который указывал структуры, содержащие массивы, содержащие структуры на произвольную глубину? Решение представляет собой решающий скачок в эволюционной цепочке между типизированным BCPL и типизированным C. Это исключило материализацию указателя в хранилище и вместо этого вызвало создание указателя, когда имя массива упоминается в выражении. Правило, которое сохраняется в сегодняшнем C, состоит в том, что значения типа массива, когда они появляются в выражениях, преобразуются в указатели на первый из объектов, составляющих массив.

...

0 голосов
/ 06 января 2020

Очень сложно ответить на вопрос «Почему?». В C двойственность массива / указателя используется повсеместно. Как только вы к этому привыкнете, это не будет смущать.

Не думайте об этом как о указателе на первый элемент - думайте об этом как о указателе на весь массив. *a - первый элемент, но *(a+1) - следующий.

...