Co robi poniższy kod?wskaźnik do tablicy C++
int g[] = {9,8};
int (*j) = g;
Z mojego rozumowania wynika, że tworzy on wskaźnik do tablicy złożonej z 2 elementów. Ale dlaczego to działa:
int x = j[0];
i to nie działa:
int x = (*j)[0];
Co robi poniższy kod?wskaźnik do tablicy C++
int g[] = {9,8};
int (*j) = g;
Z mojego rozumowania wynika, że tworzy on wskaźnik do tablicy złożonej z 2 elementów. Ale dlaczego to działa:
int x = j[0];
i to nie działa:
int x = (*j)[0];
Nawias w twoim przykładzie jest zbędny. Wskaźnik nie obchodzi, czy jest tam tablica zaangażowana - to tylko wie, że jego wskazując na int
int g[] = {9,8};
int (*j) = g;
mogą być również zapisane jako
int g[] = {9,8};
int *j = g;
które mogłyby także być zapisane jako
int g[] = {9,8};
int *j = &g[0];
Wskaźnik do tablicy wyglądałby tak:
int g[] = {9,8};
int (*j)[2] = &g;
//Dereference 'j' and access array element zero
int n = (*j)[0];
Jest dobry odczyt na deklaracjach wskaźnik (i jak je grok) pod tym linkiem tutaj: http://www.codeproject.com/Articles/7042/How-to-interpret-complex-C-C-declarations
ten artykuł jest bardzo pomocny, szczególnie prawo do lewej zasady, dzięki. –
to '2' niezbędne w' int (* j) [2] = & g; '? Czy nie byłby to wskaźnik do tablicy, gdyby pominięto '2'? – johnbakers
@johnbakers Tak, bezwzględnie konieczne jest określenie długości tablicy, w przeciwnym razie nie będziesz miał wskaźnika do tablicy, a kod nie będzie się kompilował, chyba że użyłeś rzutowania. Wskazanie do tablicy oznacza, że masz wiedzę o jej długości w czasie kompilacji. Komunikat kompilatora wynikający z pominięcia długości tablicy w MSVC++ brzmi "błąd C2440:" inicjowanie ": nie można przekonwertować z 'int (*) [2]' na 'int (*) []'' –
j[0];
dereferences wskaźnik do int
, więc jej typ jest int
.
(*j)[0]
nie ma typu. *j
odmienia wskaźnik na int
, więc zwraca int
i (*j)[0]
próbuje dereferencji int
. To jest jak próba int x = 8; x[0];
.
Ponadto należy pamiętać, że 'j [0]' jest równoważne '* (j + 0)'. '(* j) [0]' jest zatem równoważne 'j [0] [0]', które jest równoważne '* (* (j + 0) + 0)', które działa na '** j '. Jakkolwiek na to spojrzysz, to nie zadziała. – chris
, więc w jaki sposób utworzyć wskaźnik do grupy elementów tablicy? –
Ustawiasz wskaźnik na pierwszy element i używasz go jak tablicy, ponieważ 'j [1] == * (j + 1) == następny element tablicy. – chris
int g[] = {9,8};
Ten deklaruje obiekt typu int [2], a następnie inicjuje jego elementy do {9 8}
int (*j) = g;
to stwierdza obiektu typu int * i inicjuje to ze wskaźnikiem pierwszego elementu g.
Fakt, że druga deklaracja inicjuje j z czymś innym niż g jest dość dziwny. C i C++ mają tylko te dziwne reguły dotyczące tablic i to jest jedna z nich. Tutaj wyrażenie g
jest niejawnie przekształcone z lwartości odnoszącej się do obiektu g do wartości typu int*
, która wskazuje na pierwszy element g.
Konwersja odbywa się w kilku miejscach. W rzeczywistości pojawia się, gdy wykonujesz g[0]
. Operator indeksu tablic nie działa na tablicach, tylko na wskaźnikach. Tak więc instrukcja int x = j[0];
działa, ponieważ g[0]
dzieje się tak samo niejawnej konwersji, która została wykonana po zainicjowaniu j
.
wskaźnik do tablicy jest zadeklarowany jak ten
int (*k)[2];
i jesteś dokładnie tak, jak miałoby to być stosowany
int x = (*k)[0];
(Zauważ, jak "declaration follows use", czyli składnia deklarowania zmienna typu naśladuje składnię przy użyciu zmiennej tego typu.)
Jednak zazwyczaj nie używa się wskaźnika do tablicy. Cały cel specjalnych reguł wokół tablic jest taki, że możesz użyć wskaźnika do elementu tablicy tak, jakby był tablicą. Tak więc idiomatyczne C generalnie nie dba o to, że tablice i wskaźniki nie są tym samym, a reguły uniemożliwiają wykonanie wielu użytecznych rzeczy bezpośrednio z tablicami. (Na przykład nie można skopiować tablicę jak: int g[2] = {1,2}; int h[2]; h = g;
)
Przykłady:
void foo(int c[10]); // looks like we're taking an array by value.
// Wrong, the parameter type is 'adjusted' to be int*
int bar[3] = {1,2};
foo(bar); // compile error due to wrong types (int[3] vs. int[10])?
// No, compiles fine but you'll probably get undefined behavior at runtime
// if you want type checking, you can pass arrays by reference (or just use std::array):
void foo2(int (&c)[10]); // paramater type isn't 'adjusted'
foo2(bar); // compiler error, cannot convert int[3] to int (&)[10]
int baz()[10]; // returning an array by value?
// No, return types are prohibited from being an array.
int g[2] = {1,2};
int h[2] = g; // initializing the array? No, initializing an array requires {} syntax
h = g; // copying an array? No, assigning to arrays is prohibited
Ponieważ tablice są więc niezgodne z innych typów w C i C++ należy po prostu unikać im. C++ ma std::array
, który jest dużo bardziej spójny i powinieneś go używać, gdy potrzebujesz macierzy o rozmiarach statycznych. Jeśli potrzebujesz tablic o rozmiarze dynamicznym, pierwszą opcją jest std :: vector.
+1, dokładny opis relacji tablica/wskaźnik, bez użycia zaniku tekstu. –
@mjfgates: tablice nie są wskaźnikami. Przestańcie to mówić ludziom. –
@mjfgates Rzeczywiście istnieje obiekt tablicy w C i C++. Zdarza się, że istnieją dziwne reguły, które na przykład powodują nieplanowane konwersje z tablicy do wskaźnika do pierwszego elementu tablicy. – bames53