Другие ответы верны, но ни один из них не подчеркивает идею о том, что все три могут содержать одно и то же значение и , и поэтому они в некотором роде неполные.
Причина, по которой это не может быть понято из других ответов, заключается в том, что все иллюстрации, хотя они полезны и определенно обоснованы в большинстве случаев, не охватывают ситуацию, когда указатель x
указывает на себя.
Это довольно легко построить, но явно немного сложнее понять. В программе ниже мы увидим, как мы можем заставить все три значения быть идентичными.
ПРИМЕЧАНИЕ . Поведение в этой программе не определено, но я публикую его здесь просто как интересную демонстрацию того, что указатели могут делать, но не должны .
#include <stdio.h>
int main () {
int *(*x)[5];
x = (int *(*)[5]) &x;
printf("%p\n", x[0]);
printf("%p\n", x[0][0]);
printf("%p\n", x[0][0][0]);
}
Он компилируется без предупреждений как в C89, так и в C99, и вывод будет следующим:
$ ./ptrs
0xbfd9198c
0xbfd9198c
0xbfd9198c
Интересно, что все три значения идентичны. Но это не должно быть сюрпризом! Во-первых, давайте разберем программу.
Мы объявляем x
как указатель на массив из 5 элементов, где каждый элемент имеет указатель типа на int. Это объявление выделяет 4 байта в стеке времени выполнения (или больше в зависимости от вашей реализации; на моей машине указатели равны 4 байта), поэтому x
ссылается на фактическую ячейку памяти. В семействе языков C содержимое x
просто мусор, что-то, что осталось от предыдущего использования местоположения, поэтому x
само по себе никуда не указывает - конечно, не на выделенное пространство.
Итак, естественно, мы можем взять адрес переменной x
и поместить его куда-нибудь, так что это именно то, что мы делаем. Но мы пойдем дальше и поместим это в сам x. Так как &x
имеет тип, отличный от того x
, нам нужно выполнить приведение, чтобы мы не получали предупреждений.
Модель памяти будет выглядеть примерно так:
0xbfd9198c
+------------+
| 0xbfd9198c |
+------------+
Таким образом, 4-байтовый блок памяти по адресу 0xbfd9198c
содержит битовую комбинацию, соответствующую шестнадцатеричному значению 0xbfd9198c
. Достаточно просто.
Далее мы распечатываем три значения. Другие ответы объясняют, к чему относится каждое выражение, поэтому теперь отношения должны быть ясными.
Мы можем видеть, что значения одинаковы, но только в смысле очень низкого уровня ... их битовые комбинации идентичны, но тип данных, связанный с каждым выражением, означает, что их интерпретируемые значения различны. Например, если мы распечатали с x[0][0][0]
использованием строки формата%d
, мы получим огромное отрицательное число, поэтому «значения» на практике разные, но битовый шаблон одинаков.
Это на самом деле очень просто ... на диаграммах стрелки просто указывают на один и тот же адрес памяти, а не на разные. Однако, хотя мы смогли навязать ожидаемый результат из неопределенного поведения, оно просто неопределенное. Это не рабочий код, а просто демонстрация для полноты картины.
В разумной ситуации вы будете использовать malloc
для создания массива 5 указателей int и снова для создания целых чисел, на которые указывают в этом массиве.malloc
всегда возвращает уникальный адрес (если только у вас недостаточно памяти, в этом случае он возвращает NULL или 0), поэтому вам никогда не придется беспокоиться о самоссылочных указателях, подобных этому.
Надеюсь, это полный ответ, который вы ищете. Вы не должны ожидать x[0]
, x[0][0]
и x[0][0][0]
быть равными, но они могут быть, если вынуждены. Если что-то у вас над головой, дайте мне знать, чтобы я мог уточнить!
x[0]
,x[0][0]
Иx[0][0][0]
имеют разные типы. Их нельзя сравнивать. Что вы имеете в виду!=
?