Wskaźnik do wskaźnika, tablica dwuwymiarowa

1

Mam problem ze zrozumieniem pewnego zagadnienia, a mianowicie załóżmy, że mamy taki kod:

#include <stdio.h>
int main() {
    int tab[4][2];
    tab[0][0] = 0;
    printf("tab == %p, *tab == %p, **tab == %d, &tab[0][0] == %p\n", tab, *tab, **tab, &tab[0][0]);
    return 0;
}

po jego wykonaniu:

tab == 0022FF00, *tab == 0022FF00, **tab == 0, &tab[0][0] == 0022FF00

wynika zatem z tego, że tab to to samo co &tab[0][0], dlaczego zatem aby dojśc do wartości przechowywanej pod adresem 0022FF00
dla tab należy użyc podwójnej dereferencji?

0

Adres pierwszego elementu tablicy jest równy adresowi tablicy. Po co stosować podwójną dereferencję, skoro masz od tego operator?

0

Nie mówię, że będę stosował ten zapis, chcę tylko zrozumiec dlaczego tak jest. To co napisałeś wiem. Jednak nie tłumaczy dlaczego dzieje się tak jak napisałem. Ta równośc: tab == &tab[0][0] jest dla mnie jasna, nie jest natomiast jasne to: tab == *tab

0

A ściślej rzecz ujmując dlaczego skoro tab == &tab[0][0] to *tab != tab[0][0]

0

Ponieważ int tab[4][2] można rozumieć jako tablicę wielowymiarową - tzn. leży toto w pamięci mniej-więcej tak:
[[int1, int2], [int3, int4], [int5, int6], [int7, int8]]

I teraz pierwszy element tab == [int1, int2].
W ten sposób, adres tab i adres tab[0] są sobie równe - ale to nie znaczy że tab i tab[0] są sobie równe.

Podwójnej dereferencji musisz użyć, bo pierwsza zwraca tab[0], czyli [int1, int2] - dopiero druga zwraca faktyczną wartość.

0

MSM słusznie zauważył, że tab i tab[0] nie są sobie równe. W tym wypadku tab to 4-elementowa tablica 2-elementowych tablic intów, a tab[0] to 2-elementowa tablica intów.
Trzeba pamiętać, że w C/C++ tablica to osobny typ. Tablica nie jest wskaźnikiem. Tablica może zostać niejawnie skonwertowana do wskaźnika na jej pierwszy element, tam, gdzie zajdzie taka potrzeba.
I tak np. w trzecim przypadku, tj. **tab operator dereferencji oczekuje wskaźnika, więc tab konwertowane jest na wskaźnik do pierwszego elementu. Dostajemy pierwszy element, ale mamy drugi operator dereferencji. Ten oczekuje wskaźnika, więc tablica zostaje skonwertowana na wskaźnik do pierwszego jej elementu, czyli w tym wypadku już inta.

0

Rozumiem. Mógłbyś jeszcze tylko rozwinąc myśl: tablica to osobny typ?

0

Chodzi o to, że int tab[4][2] to nie jest to samo co int **tab. To całkowicie różne typy. Ten pierwszy może być skonwertowany na ten drugi w pewnych sytuacjach.

Często spotka się, że ludzie mówią "tablica to to samo co wskaźnik". A tak właśnie nie jest.

0

Można powiedzieć, że taka tablica składa się z 5 tablic:
jednej czteroelemnetowej o elementach typu int* i czterech dwuelementowych o elementach typu int.

Instrukcję int elem = tab[0][0] można rozbić na kilka operujących na wskaźnikach:

int (*wsk_tab)[2] = tab + 0;//(1) - pobranie wskaźnika do 1 tablicy dwuelementowej
int* wsk_elem = *wsk_tab + 0;//(2) - pobranie wskaźnika do 1 elementu tablicy
int elem = *wsk_elem;//pobranie wartości elementu 

Indeks tablicy jest zerowy zatem można go pominąć i dodatkowo połączyć instrukcje (1) i (2) w
jedną:

int* wsk_elem = *(tab + 0);//(3)
int elem = *(wsk_elem + 0);//(4) 

Rrównież indeks elementu można pominąć i połączyć instrukcje (3) i (4):

int elem = **tab;// równoważne int elem = *(*(tab + 0) + 0); 

Dlatego należy użyć podwójnej dereferencji, aby odczytać pierwszy element pierwszej
tablicy dwuelementowej.

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