Я попытаюсь дать вам технически правильное объяснение, чтобы вы знали, что происходит. Не очень сложный, но на самом деле противоречащий интуиции.
Введение:
В C есть «lvalues», которые в основном представляют собой «назначаемые» объекты, которые имеют место где-то в памяти, и «rvalues», которые представляют собой, хорошо, «концептуальные» значения (не требуется для размещения в любом месте).
Например, если вы определяете int a = 5;
, то a
является lvalue типа int и value 5. Также он может быть интерпретирован как (или, скорее, преобразован) в rvalue типа int. Такое значение r еще будет известно, что оно равно 5, но оно больше не будет содержать информацию о местоположении a
в памяти.
Некоторые выражения требуют lvalues (например, левая сторона оператора =, потому что вам нужно назначить объект), а некоторые нужны rvalues (например, operator +, потому что вам нужны только интегральные значения, когда вы добавляете, или правую сторону оператора =). Если выражение требует rvalue, но вы передаете lvalue, тогда оно преобразуется в rvalue.
Кроме того, для функций в C передаются только rvalues (что означает, что C строго по умолчанию, а не по вызову).
Некоторых примеры:
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`
Преобразование из именующих к RValue, как правило, тривиальны и unnoticable (это как принимая число 5 с полков меченых a
). Массивы в основном являются исключением.
Большая вещь: В C нет значений типа массива. Имеются указатели lvalues и rvalues, целочисленные lvalues и rvalues, lvalues структуры и rvalues и т. Д. Но только массивы lvalue. Когда вы пытаетесь преобразовать lvalue типа массива в rvalue, у вас больше нет массива, у вас есть указатель на первый элемент массива. Это корень путаницы в массивах в C (и C++).
Пояснение:
array
*(array)
array+1
*(array)+1
array
представляет собой объект типа int[3][5]
(массив из 3 целых 5 цепей). Когда вы пытаетесь передать его функции, он получает указатель типа int (*)[5]
(указатель на массив из 5 целых чисел), потому что это то, что осталось после преобразования lvalue-to-rvalue.
*(array)
- tricker. Сначала выполняется lvalue-to-rvalue, что приводит к значению типа int(*)[5]
, затем operator*
принимает это значение rvalue и возвращает lvalue типа int[5]
, после чего вы пытаетесь перейти к функции. Следовательно, он снова преобразуется в значение r, что приводит к int*
.
array+1
вызывает массив, который будет преобразован в RValue типа int(*)[5]
и Rvalue получает приращение на единицу, так что (в соответствии с правилами указателей арифметика) перемещает указатель 1 * sizeof(int[5])
байт вперед.
*(array)+1
: см 2 пункта выше, но окончательное Rvalue типа int*
получает приращение, опять же по правилам указателей арифметика, по 1 * sizeof(int)
.
Никакой тайны здесь!
так в чем разница b/w array + 1 и * (array + 1)? Когда я распечатываю их оба, я получаю одинаковое расположение памяти –