Массив распадается на указатель как параметр функции

Я знаю, что следующие определения функций считаются одинаковыми компилятором c

void test(int* array);   // all converted to first one
void test(int array[]);
void test(int array[3]);

и в стандарте C99

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

мои вопросы после того, как int array[] распадается на указатель, тогда это также lvalue как локальная переменная в вызове функции, нарушает ли это стандарт, согласно которому преобразованный указатель не должен быть lvalue?

Цитата касается выражений, а не объявлений. В объявлениях параметров нет «распада», все они просто эквивалентны объявлениям указателей.

Barmar 20.04.2023 18:19

Привет @Barmar, хороший улов, ты случайно не знаешь, где в стандарте я могу найти правило преобразования объявлений? Спасибо

mzoz 20.04.2023 18:22

См. C99 6.7.5.3 параграф 7.

Ian Abbott 20.04.2023 18:23
Структурированный массив Numpy
Структурированный массив Numpy
Однако в реальных проектах я чаще всего имею дело со списками, состоящими из нескольких типов данных. Как мы можем использовать массивы numpy, чтобы...
T - 1Bits: Генерация последовательного массива
T - 1Bits: Генерация последовательного массива
По мере того, как мы пишем все больше кода, мы привыкаем к определенным способам действий. То тут, то там мы находим код, который заставляет нас...
Что такое деструктуризация массива в JavaScript?
Что такое деструктуризация массива в JavaScript?
Деструктуризация позволяет распаковывать значения из массивов и добавлять их в отдельные переменные.
0
3
60
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

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

Эквивалентность трех объявлений, которые вы дали, прописана в разделе 6.7.6.3p7 стандарта C:

Объявление параметра как «массива типа» должно быть скорректировано для ‘‘квалифицированный указатель на тип’’, где квалификаторы типа (если есть) те, которые указаны в [ и ] производного типа массива. Если ключевое слово static также появляется в [ и ] типа массива вывод, то для каждого вызова функции значение соответствующий фактический аргумент должен обеспечивать доступ к первому элемент массива, содержащий как минимум столько элементов, сколько указано в выражение размера

Таким образом, это означает, что во всех вышеперечисленных случаях тип параметра arrayint *.

Затем, как параметры заполняются. Это указано в 6.5.2.2p4 относительно вызовов функций:

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

Итак, учитывая следующее:

int a[5];
test(a);

Внутри есть присваивание, то есть array = a от переданного значения параметра к фактическому параметру функции.

мои вопросы после того, как int array[] распадается на указатель, тогда это также lvalue как локальная переменная в вызове функции, нарушает ли она стандарт, что преобразованный указатель не должен быть lvalue?

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

int a[10];
++a;

В этом выражении ++a указатель массива a неявно преобразуется в указатель на его первый элемент, но указатель не является lvalue. Вы не можете увеличить его. Если бы вы написали вместо

int a[10];
int *p = a;
++p;

тогда выражение ++p верно, потому что p является lvalue.

Что касается такой функции

void test(int array[]);

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

Точно так же, если у вас есть функция, которая возвращает массив, который преобразуется в указатель на его первый элемент, например,

int * test( void )
{
    static int a[10];

    return a;
}

затем снова возвращаемый указатель не является lvalue. Например, вы не можете писать

printf( "%p\n", ( void * )++test() );

То есть вы не можете увеличивать возвращаемый указатель.

Другие вопросы по теме