• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

Deklaracja wskaźnika do tablicy wielowymiarowej

Object Storage Arubacloud
0 głosów
557 wizyt
pytanie zadane 13 sierpnia 2017 w C i C++ przez kario97 Nowicjusz (120 p.)

Witam, uczę się języka C z książki "Język C - szkoła programowania" S Praty i mam malutki problem ze wskaźnikami.

Jestem aktualnie na "Wskaźnikach do tablic wielowymiarowych" i mam problem z deklaracją takich wskaźników. W książce jest napisane, że żeby zadeklarować zmienną wskaźnikową, która byłaby zgodna z np. tablicą dwuwymiarową, nie wystarczy wskaźnik do int, gdyż ten typ jest zgodny tylko ze zmienną, która wskazuje pojedynczą wartość int - zmienna wskaźnikowa powinna wskazywać na całą tablice takich wartości. Potem jest przykład deklaracji takiej zmiennej:

int (*wz)[2]; // wz wskazuje do tablicy dwoch elementow typu int

Niby wszystko jasne - powyższa instrukcja tworzy jeden wskaźnik do tablicy składającej się z dwóch liczb typu int. Jednak potem jest przedstawiony przykładowy program, w którym można zobaczyć takie oto instrukcje (przepiszę skróconą wersje programu):

#include <stdio.h>
#include <stdlib.h>
 
int main()
{
    int zippo[4][2] = { {2,4}, {6,8}, {1,3}, {5,7} };
 
    int (*pz)[2]; //deklaracja wskaznika do tablicy wielowymiarowej
    pz = zippo; //przypisanie adresu pierwszego elementu tablicy wielowymiarowej, 
    //gdyz sama nazwa tablicy jest jednoczesnie adresem jej pierwszego elementu
 
    printf("*(*(pz+2)+1) = %d\n", *(*(pz+2)+1) );
    printf("pz[2][1] = %d\n", pz[2][1]);
 
    return 0;
}
 

Może mi ktoś wytłumaczyć, dlaczego w deklaracji wskaźnika do tablicy dwuwymiarowej mamy int (pz)[2]; , a nie np int(pz)[4][2], skoro jest to wskaźnik do tablicy [4][2]?
W powyższym przypadku napisaliśmy (pz)[2] - 2, ponieważ jest to tablica dwuwymiarowa? Czyli w przypadku tablicy trzy wymiarowej int zippo[4][6][2]; musielibyśmy napisać int (pz)[3]?

Może mi ktoś wytłumaczyć, na jakiej zasadzie deklaruje się wskaźniki do tablic wielowymiarowych? I jak by wyglądała deklaracja takiego wskaźnika dla np. takich tablic:

int zippo2[4][6][2];
int zippo3[2][4][6][8];

1 odpowiedź

+1 głos
odpowiedź 13 sierpnia 2017 przez Dzordzu Użytkownik (900 p.)
edycja 14 sierpnia 2017 przez Dzordzu

To przejdziemy od razu do wersji hard (3 wymiarowa tablica):
1. Jak wiesz wskaźnik przy tablicy jednowymiarowej odwołuje się do pierwszego elementu tj.

int a[3] = {1, 2, 3};
int *p;
p = a;
printf("%d\n%d", a[0], *p);

wypisze dwa razy "1"
2. Zapis

int (*a)[3];

oznacza że tworzymy tablicę trójwymiarową ze wskaźnikami wskaźnik na trójelementową tablicę intów. Czyli w pseudokodzie coś typu tablica -> [x1, x2, x3]

3. Oto jak to wygląda na przykładzie:

#include <stdio.h>
#include <stdlib.h>
 
int main()
{
    int zippo[6][5][4];
    
    
    for(int a = 0; a < 6; a++){
	    for(int b = 0; b < 5; b++){
		    for(int c = 0; c < 4; c++){
		    	
		    	zippo[a][b][c] = 100*a + 10*b + c;
		    	printf("zippo[%d][%d][%d] = %d\n", a, b, c, zippo[a][b][c]); //uzupełniam zippo
			}
		}
	}
    printf("\n");
    
 
    int (*pz)[5][4]; //deklaracja wskaznika do tablicy wielowymiarowej
    pz = zippo; //przypisanie adresu pierwszego elementu tablicy wielowymiarowej, 
    //gdyz sama nazwa tablicy jest jednoczesnie adresem jej pierwszego elementu
 
    printf("*(*(*(pz+1)+2)+3) = %d\n", *(*(*(pz+1)+2)+3));
    printf("pz[1][2][3] = %d\n", pz[1][2][3]);
 
    return 0;
}

4. Jak to działa?
Uzupełniania zippo nie będę tłumaczył.
 

int (*pz)[5][4];

tworzy nam tablicę dwuwymiarową ze wskaźnikami. Teraz kluczowa sprawa:

printf("*(*(*(pz+1)+2)+3) = %d\n", *(*(*(pz+1)+2)+3));

Rozbiję to na kilka części
1) *(pz+1) - ustala nam pierwszy indeks pz na "1" czyli chwilowo mamy pz[1]. Jednak pz[1] jest nadal wskaźnikiem do wskaźnika do zippo[1][0][0].
2) *(*(pz+1)+2) ustala nam drugi indeks na "2" czyli chwilowo mamy pz[1][2]. Jednak pz[1][2] jest nadal wskaźnikiem do zippo[1][2][0].
3) *(*(pz+1)+2) + 3 - przesuwa nam wskaźnik pz[1][2] o 3 miejsca do przodu. Czyli chwilowo mamy wskaźnik do zippo[1][2][3]
4) *(*(*(pz+1)+2) + 3) -odwołujemy się do zippo[1][2][3]
5) printf(...) - wypisujemy

komentarz 13 sierpnia 2017 przez kario97 Nowicjusz (120 p.)

Dobra, dzięki za wytłumaczenie. Czyli mam rozumieć, że deklaracja wskaźnika dla tablic:

int zippo2[4][6][2];
int zippo3[2][4][6][8];

Wyglądałaby tak:

int (*pz2)[6][2];
int (*pz3)[4][6][8];

Czyli o ile podanie pierwszego rozmiaru nie jest konieczne, to musimy podać pozostałe rozmiary.

Jeszcze raz dzięki za pomoc, ale mam pytanie jeszcze do następującej instrukcji:

 *(*(pz+1)+2) + 3;

Czy to przypadkiem nie działa tak, że do wartości *(*(pz+1)+2) jest dodawana wartość 3? Czyli jeżeli *(*(pz+1)+2) wskazuje na wartość 10, to dodawane jest 3, i po wyświetleniu tego przez specyfikator %d otrzymujemy 13?

 

 

1
komentarz 13 sierpnia 2017 przez Dzordzu Użytkownik (900 p.)

*(*(pz+1)+1) jest wskaźnikiem. Działanie dodawania na wskaźniku, przesuwa nam go o jakąś wartość. Poniżej masz przykład:
 

   int a[3];
    int *p = a;
    for(int i = 0; i<3; i++)printf("&a[%d] = 0x%08x \n", i, &a[i]);
    for(int i = 0; i<3; i++)printf("\np + %d = 0x%08x", i, p+i);

Da na nam wynik w stylu:
 

&a[0] = 0x0028fea8
&a[1] = 0x0028feac
&a[2] = 0x0028feb0

p + 0 = 0x0028fea8
p + 1 = 0x0028feac
p + 2 = 0x0028feb0

Zakładam, że znasz symbol referencji ('&').

komentarz 13 sierpnia 2017 przez kario97 Nowicjusz (120 p.)

Dzięki, już rozumiem. :)

A możesz jeszcze odpowiedzieć, czy moim powyższym komentarzu dobrze zadeklarowałem wskaźniki do tych tablic?

int zippo2[4][6][2];
int zippo3[2][4][6][8];

czyli:

int (*pz2)[6][2];
int (*pz3)[4][6][8];

 

komentarz 13 sierpnia 2017 przez Dzordzu Użytkownik (900 p.)
Skoro nic nie mówiłem to raczej tak ;)
komentarz 14 sierpnia 2017 przez Dzordzu Użytkownik (900 p.)
Dodałem poprawkę dotyczącą mechaniki działania (*p)[3]. Niby szczegół, ale ważny. Przepraszam za podanie błędnej informacji. Reszta wydaje się być OK.

Podobne pytania

0 głosów
1 odpowiedź 126 wizyt
pytanie zadane 3 kwietnia 2017 w C i C++ przez hacker09 Użytkownik (520 p.)
0 głosów
1 odpowiedź 430 wizyt
0 głosów
1 odpowiedź 279 wizyt

92,570 zapytań

141,422 odpowiedzi

319,643 komentarzy

61,958 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj.

Akademia Sekuraka

Kolejna edycja największej imprezy hakerskiej w Polsce, czyli Mega Sekurak Hacking Party odbędzie się już 20 maja 2024r. Z tej okazji mamy dla Was kod: pasjamshp - jeżeli wpiszecie go w koszyku, to wówczas otrzymacie 40% zniżki na bilet w wersji standard!

Więcej informacji na temat imprezy znajdziecie tutaj. Dziękujemy ekipie Sekuraka za taką fajną zniżkę dla wszystkich Pasjonatów!

Akademia Sekuraka

Niedawno wystartował dodruk tej świetnej, rozchwytywanej książki (około 940 stron). Mamy dla Was kod: pasja (wpiszcie go w koszyku), dzięki któremu otrzymujemy 10% zniżki - dziękujemy zaprzyjaźnionej ekipie Sekuraka za taki bonus dla Pasjonatów! Książka to pierwszy tom z serii o ITsec, który łagodnie wprowadzi w świat bezpieczeństwa IT każdą osobę - warto, polecamy!

...