Pozostałe odpowiedzi są poprawne, ale żadna z nich nie podkreśla idei, że wszystkie trzy mogą zawierać tę samą wartość , a więc są w pewnym sensie niekompletne.
Powodem, dla którego nie można tego zrozumieć na podstawie innych odpowiedzi, jest to, że wszystkie ilustracje, choć pomocne i zdecydowanie rozsądne w większości przypadków, nie obejmują sytuacji, w której wskaźnik x
wskazuje na siebie.
Jest to dość łatwe do skonstruowania, ale wyraźnie trudniejsze do zrozumienia. W poniższym programie zobaczymy, jak możemy wymusić identyczność wszystkich trzech wartości.
UWAGA: Zachowanie w tym programie jest nieokreślone, ale zamieszczam je tutaj wyłącznie jako interesującą demonstrację czegoś, co wskaźniki mogą zrobić, ale nie powinny .
#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]);
}
To kompiluje się bez ostrzeżeń w obu C89 i C99, a wynik jest następujący:
$ ./ptrs
0xbfd9198c
0xbfd9198c
0xbfd9198c
Co ciekawe, wszystkie trzy wartości są identyczne. Ale to nie powinno być zaskoczeniem! Najpierw podzielmy program.
Deklarujemy x
jako wskaźnik do tablicy 5 elementów, gdzie każdy element jest wskaźnikiem typu do int. Ta deklaracja przydziela 4 bajty na stosie środowiska wykonawczego (lub więcej w zależności od implementacji; na moim komputerze wskaźniki mają 4 bajty), więc x
odnosi się do rzeczywistej lokalizacji pamięci. W rodzinie języków C zawartość x
jest po prostu śmieciami, czymś pozostałym po poprzednim użyciu lokalizacji, więc x
sama nigdzie nie wskazuje - na pewno nie dotyczy przydzielonej przestrzeni.
Więc naturalnie możemy wziąć adres zmiennej x
i gdzieś go umieścić, więc to jest dokładnie to, co robimy. Ale pójdziemy dalej i umieścimy to w samym x. Ponieważ &x
ma inny typ niż x
, musimy wykonać rzut, aby nie otrzymywać ostrzeżeń.
Model pamięci wyglądałby mniej więcej tak:
0xbfd9198c
+------------+
| 0xbfd9198c |
+------------+
Zatem 4-bajtowy blok pamięci pod adresem 0xbfd9198c
zawiera wzorzec bitów odpowiadający wartości szesnastkowej 0xbfd9198c
. Wystarczająco proste.
Następnie drukujemy trzy wartości. Pozostałe odpowiedzi wyjaśniają, do czego odnosi się każde wyrażenie, więc związek powinien być teraz jasny.
Widzimy, że wartości są takie same, ale tylko w sensie bardzo niskiego poziomu ... ich wzorce bitowe są identyczne, ale typ danych skojarzonych z każdym wyrażeniem oznacza, że ich interpretowane wartości są różne. Na przykład, jeśli wydrukowaliśmy przy x[0][0][0]
użyciu ciągu formatu%d
, otrzymalibyśmy ogromną liczbę ujemną, więc „wartości” są w praktyce różne, ale wzór bitowy jest taki sam.
To jest naprawdę proste ... na diagramach strzałki wskazują po prostu ten sam adres pamięci, a nie różne. Jednakże, chociaż byliśmy w stanie wymusić oczekiwany rezultat z niezdefiniowanego zachowania, to po prostu - niezdefiniowany. To nie jest kod produkcyjny, ale po prostu demonstracja w celu zapewnienia kompletności.
W rozsądnej sytuacji użyjesz malloc
do utworzenia tablicy 5 wskaźników int, a następnie do utworzenia ints, które są wskazywane w tej tablicy.malloc
zawsze zwraca unikalny adres (chyba że brakuje Ci pamięci, w takim przypadku zwraca NULL lub 0), więc nigdy nie będziesz musiał martwić się o takie wskaźniki odwołujące się do siebie.
Mam nadzieję, że to pełna odpowiedź, której szukasz. Nie należy się spodziewać x[0]
, x[0][0]
i x[0][0][0]
być równe, ale mogą być, jeśli zmuszony. Jeśli coś przeszło Ci przez głowę, daj mi znać, abym mógł wyjaśnić!
x[0]
,x[0][0]
Ix[0][0][0]
mają różne typy. Nie można ich porównać. Co masz na myśli!=
?