Tablica tablic a wskaźniki

0

Taką tablicę tablic:

 
int tab[4][3];

Można przypisać do wskaźnika w ten sposób:

 
int (*wsk)[3] = tab;

Równoważnym zapisem jest:

 
int (*wsk)[3] = &tab[0];

Możliwe są także przypisania takie jak:

 
int (*wsk)[3] = *(&tab);
int (*wsk)[3] = &(*tab);

Jak wytłumaczyć poprawność tych dwóch ostatnich zapisów ?

0

W obu ostatnich przypadkach operatory adresu i dereferencji zniosą się wzajemnie, co oznacza, że będą równoważne zapisowi int (*wsk)[3] = tab;.

Pierwszy z nich to odwołanie się do miejsca w pamięci wskazywanego przez adres zmiennej tab, co w praktyce jest równoważne tab.

Drugi to adres w pamięci zmiennej, która jest wskazywana przez tab, czyli znów równoważność z tab.

0

Mam jeszcze pare innych wątpliwości. Kompilator pozwala na zapis:

 
cout<<&tab;

i wydruk jest równoważny:

cout<<tab;
 

natomiast już próba przypisania:

 
int (*wsk)[3] = &tab;

jest błędem.

Poniższe dwa zapisy są równoważne (jeśli się mylę to poprawcie mnie):

 
//tab[0] to samo co *tab

Błędem są takie instrukcje:

 
int (*wsk)[3] = tab[0];
int (*wsk)[3] = *tab;

Jak wytłumaczyć dlaczego tak jest ?

0

tab[0] to konkretna zmienna typu int a nie wskaźnik do int, tak samo w drugim przypadku: wyłuskujesz wskaźnik do int a więc dostajesz obiekt typu int i próbujesz go przypisać do wskaźnika

0

W przypadku tablicy tablic a taką jest przecież tab:

 
int tab[4][3];

tab[0] nie oznacza konkretnej zmiennej typu int, tylko adres (chyba początku wiersza) podobnie jak *tab, aby wydobyć konkretną zmienną trzeba napisać tab[0][0] albo **tab. Intuicyjnie wyczuwam o co z tym chodzi, ale proszę o wytłumaczenie dlaczego te zapisy są błędne:

 
int (*wsk)[3] = tab[0];
int (*wsk)[3] = *tab;
0

*Tab jest typu wskaźnik do tablicy int[3], Tab jest tablicą int [4][3], ale w niektórych wyrażeniach może być automatycznie przekonwertowana na wskaźnik to int [3]. &Tab jest wskaźnikiem do tablicy int[4][3]. Wartości wymienionych w poście powyżej wskaźników są identyczne, ale się różnią typami. Pamiętaj o tym, że system typów nie jest dla kompilatora, jest dla Ciebie, w wynikowym programie nic na ten temat nie ma (trochę może jest dla kompilatora, musi wiedzieć jak przeprowadzać arytmetykę na wskaźnikach, pobaw się z sizeof, żeby to lepiej zrozumieć)

0

Tablica a wskaźnik to dwa osobne typy. Nie mniej jednak tablica może być niejawnie konwertowana na wskaźnik - wtedy jest ona zamieniana na wskaźnik do pierwszego elementu tablicy.

Natomiast tablica dwuwymiarowa to jednowymiarowa tablica jednowymiarowych tablic. Tak samo może być niejawnie konwertowana na wskaźnik do pierwszego elementu, z tym że w tym przypadku pierwszym elementem jest cały wiersz (tablica jednowymiarowa).

Zatem:

cout<<&tab;

Tutaj niejawna konwersja nie zachodzi - jawnie pobierasz adres tablicy. Jest to wskaźnik typu int (*)[4][3] (wskaźnik do tablicy dwuwymiarowej). Wskaźnik ten wskazuję na miejsce w pamięci w którym leży tablica - będzie to ten sam adres co adres pierwszego wiersza, czy elementu [0][0] (adres ten sam, ale typ wskaźnika już inny).

cout<<tab;

Tutaj zachodzi niejawna konwersja na adres pierwszego elementu czyli tak jakbyśmy pobrali &tab[0] (adres pierwszego wiersza). Wskaźnik ten jest typu int (*)[3] (wskaźnik do tablicy jednowymiarowej).

int (*wsk)[3] = &tab;

Tutaj nie mamy niejawnej konwersji - jawnie pobierasz adres całej tablicy dwuwymiarowej. Tak jak w pierwszym przypadku będzie to wskaźnik typu int (*)[4][3] (wskaźnik do tablicy dwuwymiarowej). Zmienna wsk ma typ int (*)[3] (wskaźnik do tablicy jednowymiarowej) więc typy się nie zgadzają.

//tab[0] to samo co *tab

Tak. Ale czym to jest? Jest to tablicą jednowymiarową typu int [3] (pierwszy wiersz tab). Dlaczego? Przy tab[0] wiadomo - pierwszy element tablicy dwuwymiarowej czyli pierwszy wiersz (tablica jednowymiarowa). Przy *tab sprawa jest ciut bardziej skomplikowana. Operatora * nie można użyć na tablicy, ale można użyć na wskaźniku. Więc najpierw zachodzi niejawna konwersja na wskaźnik czyli tak jakby tab było zamieniane na &tab[0]. Następnie zachodzi dereferencja (*) i otrzymujemy *&tab[0] czyli adres pierwszego wiersza zamieniany jest na wiersz - pierwszy wiersz tablicy tab, wiersz typu int [3]. W pierwszym i drugim przypadku wynikiem jest tablica jednowymiarowa.

int (*wsk)[3] = tab[0];
int (*wsk)[3] = *tab;

Jak ustaliliśmy tab[0] jaki i *tab to tablica jednowymiarowa (pierwszy wiersz). Natomiast wsk to wskaźnik. Przypisując tablicę wskaźnikowi zachodzi niejawna konwersja - ów pierwszy wiersz zamieniany jest na wskaźnik do pierwszego elementu tegoż wiersza czyli &tab[0][0] lub &*tab - jest to wskaźnik typu int* czyli inny niż typ wsk.

1 użytkowników online, w tym zalogowanych: 0, gości: 1