Інші відповіді правильні, але жодна з них не підкреслює думку про те, що всі троє можуть містити однакове значення , і тому вони якимось чином неповні.
Причина цього неможливо зрозуміти з інших відповідей полягає в тому, що всі ілюстрації, хоча і корисні та, безумовно, розумні за більшості обставин, не вкривають ситуацію, коли вказівник 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
нам, нам потрібно зробити акторський склад, щоб ми не отримували попереджень.
Модель пам'яті виглядала б приблизно так:
0xbfd9198c
+------------+
| 0xbfd9198c |
+------------+
Отже, 4-байтовий блок пам'яті за адресою 0xbfd9198c
містить бітовий малюнок, відповідний шістнадцятковим значенням 0xbfd9198c
. Досить просто.
Далі роздруковуємо три значення. Інші відповіді пояснюють, на що посилається кожен вираз, тому стосунки мають бути зрозумілими вже зараз.
Ми можемо бачити, що значення однакові, але лише в сенсі дуже низького рівня ... їх бітові структури однакові, але дані типу, пов'язані з кожним виразом, означають, що інтерпретовані значення різні. Наприклад, якщо ми роздрукували за x[0][0][0]
допомогою рядка формату %d
, ми отримали б величезне від’ємне число, тому «значення» на практиці різні, але бітовий малюнок той самий.
Це насправді дуже просто ... на діаграмах стрілки просто вказують на одну і ту ж адресу пам'яті, а не на різні. Однак, хоча нам вдалося витіснити очікуваний результат із невизначеної поведінки, це просто так - невизначено. Це не виробничий код, а просто демонстрація заради повноти.
У розумній ситуації ви будете використовувати malloc
для створення масиву 5 вказівних покажчиків і знову для створення ints, на які вказується цей масив. malloc
завжди повертає унікальну адресу (якщо у вас немає пам’яті; в такому випадку вона повертає NULL або 0), тому вам ніколи не доведеться турбуватися про подібні вказівники.
Сподіваємось, це повна відповідь, яку ви шукаєте. Ви не повинні сподіватися x[0]
, x[0][0]
і x[0][0][0]
бути рівними, але вони можуть бути, якщо їх змусити. Якщо щось перейшло тобі над головою, дай мені знати, щоб я міг уточнити!
x[0]
,x[0][0]
іx[0][0][0]
мають різні типи. Їх не можна порівняти. Що ви маєте на увазі під!=
?