Mam pytanie dotyczące składni wskaźnika dotablice. Cóż, wiemy, że tablice są same w sobie wskaźnikami (co powiedział nasz profesor uni), więc gdy wskażemy je za pomocą innego wskaźnika (który byłby wskaźnikiem do wskaźnika), używamy tej składni:
int array[10];
int *pointer = array;
Zamiast tej składni:
int array[10];
int **pointer = &array;
Chociaż wiem, że to byłoby poprawne przy użyciu malloc, ale dlaczego nie w normalny sposób, czy jest to kompilator lub rzecz składniowa, czy też jestem w błędzie gdzieś indziej?
Odpowiedzi:
2 dla odpowiedzi № 1Cóż, wiemy, że tablice są same w sobie wskaźnikami
Nie. Tablice nie są wskaźnikami. Tablice są tablicami. Z wyjątkiem gdy jest operandem sizeof
lub unary &
operator, wyrażenie typu "Tablica N elementów T
"zostanie przekonwertowane (" rozpad ") na wyrażenie typu" wskaźnik doT
", a wartością wyrażenia będzie adres pierwszego elementu tablicy, ale nie zapisuje się pamięci dla wskaźnika oprócz samych elementów tablicy.
Tak więc, biorąc pod uwagę deklarację
int array[10];
typ wyrażenia array
jest "10-elementową tablicą int
"; chyba że array
jest operandem sizeof
lub jednoargumentowy &
, zepsuje się, by pisać int *
. Więc
int *ptr = array;
Prace.
Typ &array
jest nie int **
; typ to int (*)[10]
lub "wskaźnik do tablicy 10-elementowej int
"Zadeklarowałeś i zainicjalizowałeś taki wskaźnik jako
int (*ptr)[10] = &array;
4 dla odpowiedzi nr 2
Powiedz swojemu profesorowi, że się mylą. Tablice są nie wskaźniki. Tablice mogą rozkład do wskaźników, ale oni są nie wskaźniki.
int* pointer = array;
deklaruje wskaźnik wskazujący na pierwszy element w array
.
int** pointer = &array;
nie jest poprawne. Jak wspomniano jschultz410 w komentarzach, typ &array
jest nie int**
, to jest int (*)[10]
aka wskaźnik do tablicy 10 elementów, które nie mogą się zepsuć int**
.
3 dla odpowiedzi nr 3
Przede wszystkim ta definicja wskaźnika
int array[10];
int **pointer = &array;
jest nieważny. Po prawej stronie deklaracji znajduje się wyrażenie mające typ int ( * )[10]
natomiast po lewej stronie znajduje się identyfikator typu int **
. Nie ma żadnej niejawnej konwersji pomiędzy wskaźnikami int ( * )[10]
i int **
. Dlatego kompilator powinien wysłać komunikat diagnostyczny.
Poprawna definicja będzie wyglądać
int array[10];
int ( *pointer )[10] = &array;
Teraz możemy zastanowić się, jaka jest różnica między tymi dwoma definicjami
int array[10];
int *pointer = array;
i
int array[10];
int ( *pointer )[10] = &array;
W pierwszym przypadku wielkość obiektu wskazywanego przez wskaźnik pointer
jest równe sizeof( int )
. Więc jeśli użyć wskaźnika arytmetycznego, to po ocenie wyrażenia ++pointer
wartość w wskaźniku zostanie zwiększona o sizeof( int )
bajty. Jeśli na przykład sizeof( int )
jest równe 4
wtedy wartość w wskaźniku zostanie zwiększona o 4
.
W drugim przypadku wielkość obiektu wskazywanego przez wskaźnik pointer
jest równe 10 * sizeof( int )
to jest, jeśli sizeof( int )
jest równe 4, wtedy rozmiar obiektu jest równy 40
. Więc jeśli wskaźnik zostanie zwiększony ++pointer
jego wartość zostanie zwiększona o 40
.
Również wyłuskiwanie wskaźnika w pierwszym przypadku da obiekt typu int
podczas dereferencji wskaźnik w drugim przypadku daje obiekt typu int[10]
to jest tablica.
A tablice nie są wskaźnikami. Po prostu zwykle są konwertowane na wskaźniki do ich pierwszych elementów w wyrażeniach. Od normy C.
3 Z wyjątkiem gdy jest operandem sizeofoperator lub unary i operator, lub jest literałem łańcuchowym używanym do inicjowania tablicy, wyrażenie, które ma typ tablicy typów, jest konwertowane na format wyrażenie z typem "wskaźnik do typu", który wskazuje na początkowy element obiektu tablicy i nie jest lwartością. Jeśli obiekt tablicy ma klasę pamięci rejestru, zachowanie jest niezdefiniowane.
Jeśli piszesz na przykład
int array[10];
int *pointer = array;
następnie sizeof( array )
nie jest równy sizeof( pointer )
choć można użyć wspólnej składni, aby uzyskać dostęp do elementów tablicy:
array[ i ]
i pointer[ i ]
i uzyska ten sam wynik ..