Я постараюсь дать вам технически правильное объяснение, чтобы вы знали, что происходит.Не очень сложно, но на самом деле нелогично.
Intro:
В C есть «lvalues», которые в основном представляют «присваиваемые» объекты, которые имеют место где-то впамять и «rvalues», которые представляют собой «концептуальные» значения (не требуется размещать их где-либо конкретно).
Например, если вы определите int a = 5;
, тогда a
будет lvalue типаint и значение 5. Также его можно интерпретировать как (или, скорее, преобразовать в) значение типа int.Такое значение r будет по-прежнему известно как 5, но оно больше не будет содержать информацию о местоположении a
в памяти.
Некоторым выражениям требуются значения l (например, слева от оператора= потому что вы должны присваивать объекту), а некоторым нужны значения r (например, operator +, потому что вам нужны только интегральные значения при добавлении или правая часть оператора =).Если выражению требуется значение rvalue, но вы передаете значение lvalue, оно преобразуется в значение rvalue.
Кроме того, в функции в C передаются только значения rval (что означает, что C является строго вызовом по значению, а неcall-by-reference).
Некоторые примеры:
int a = 1;
a; // a is an lvalue of type int and value 1
a = a+3; // here the `a` is converted to an rvalue of type int and value 1, then after the addition there's an assignment, on the lhs there's an lvalue `a` and an rvalue `4`
Преобразование из lvalue в rvalue обычно тривиально и незаметно (это похоже на взятие числа 5 с полки с надписью * 1021).*).Массивы в основном являются исключением.
Самое важное: В C нет значений типа массива.Существуют указатели lvalue и rvalues, целочисленные lvalue и rvalues, структурные lvalues и rvalues и т. Д. Но только массивы lvalue.Когда вы пытаетесь преобразовать lvalue типа массива в rvalue, у вас больше нет массива, у вас есть указатель на первый член массива.Это корень путаницы с массивами в C (и C ++).
Объяснение:
array
*(array)
array+1
*(array)+1
array
- это lvalue типа int[3][5]
(массив из 3-х или 5-ти).Когда вы пытаетесь передать его в функцию, он получает указатель типа int (*)[5]
(указатель на массив из 5 дюймов), потому что это то, что осталось после преобразования lvalue-в-значение.
*(array)
- обманщик,Сначала выполняется значение lvalue-to-rvalue, в результате чего получается rvalue типа int(*)[5]
, затем operator*
принимает это значение rvalue и возвращает значение lvalue типа int[5]
, которое затем вы пытаетесь передать функции.Следовательно, он снова преобразуется в значение r, в результате чего int*
.
array+1
приводит к преобразованию массива в значение типа int(*)[5]
, а значение rvalue увеличивается на единицу, поэтому (согласноправила арифметики указателя) указатель перемещается на 1 * sizeof(int[5])
байтов вперед.
*(array)+1
: см. 2 пункта ранее, но конечное значение типа int*
увеличивается, опять же по правилам арифметики указателя, на1 * sizeof(int)
.
Никаких загадок здесь!