Poruszanie się wskaźnikiem po tablicy 2D

0

Proszę o pomoc ze wskaźnikami. Chciał bym się dowiedzieć jak przesuwać wskaźnik po tablicy dwu wymiarowej.

jeśli mamy

tab[2][0] = 5;

ustawimy do niego wskaźnik.

wsk =& tab[0][0];

to przesunięcie wsk o 2 nie naprowadzi nas na adres [2][0].

Na razie doszedłem do tego że

cout << tab[0][5] << endl;
cout << *((wsk + 0*sizeof(int)) + 5 ) << endl;

wyświetlą ten sam wynik.

cout << *((wsk + X*sizeof(int)) + Y ) << endl;

zwiększanie zmiennej Y pozwoli nam przesuwać się po wierszu. Jednak zwiększanie zmiennej Y nie powoduje przeskakiwania do kolejnych kolumn. Czy ktoś ma jakieś propozycję dot. tego problemu ?

dodanie znaczników <code class="cpp"> oraz `` - fp

0

A czemu nie zrobisz po prostu

*wsk[2][0] = ...
0
#include <stdio.h>

int main()
  {
   unsigned y,x,p;
   int *ptr,tb[4][3]={{1,2,3},{4,5,6},{7,8,9},{10,11,12}};
   for(y=0;y<4;++y,printf("\n")) for(x=0;x<3;++x) printf("%3d",tb[y][x]);
   printf("\n");
   ptr=tb;
   for(p=y=0;y<4;++y,printf("\n")) for(x=0;x<3;++x,++p) printf("%3d",ptr[p]);
   printf("\n");
   for(p=y=0;y<4;++y,printf("\n")) for(x=0;x<3;++x,++p) printf("%3d",*(ptr+p));
   printf("\n");
   for(p=y=0;y<4;++y,printf("\n")) for(x=0;x<3;++x,++p) printf("%3d",p[ptr]);
   return 0;
  }
1

Jest tak jak _13th_Dragon napisał w komentarzu, czyli:
Jeśli masz wsk =& tab[0][0]; (zakładam że wsk to int*), i robisz wsk += 2, to trafisz nie na tab[2][0], a na tab[0][2].
Jeśli chcesz przesunąć wskaźnik na elementu [2][0], to musisz zrobić wsk += 2 * ilość_kolumn (np. dla int tab[3][5] będzie to wsk += 2 * 5).
Dodam, że standardy C/C++ gwarantują, że elementy w tablicy są po sobie (a więc że kolejne wiersze w tablicy dwówymiarowej również są po sobie), więc takie przeskakiwanie między wierszami jest jak najbardziej legalne.
(dla pewności, zazwyczaj się mówi, że jest tak: tab[numer_wiersza][numer_elementa_w_wierszu_ew_czasem_mowi_sie_na_to_numer_kolumny])

Ważny wzór do zapamiętania (baardzo się przydaje przy pracy na bitmapach / tablicach 2D i wskaźnikach na elementy będące w takich tablicach):
index_w_tablicy_1D = x + y * ilość_elementów_w_wierszu_tablicy_2D; // dla tab2d[y][x] oczywiśćie

Natomiast, jeszcze jedna uwaga - jeśli masz wsk który jest int*, to przy arytmetyce na pointerach nie używa się sizeof(typ) - C/C++ się same tym zajmują.
Jedynym wyjątkiem (w granicach standardu) jest jeśli wsk byłby pointerem na unsigned char (czyli de facto na bajt) - wtedy chcąc przeskoczyć na kolejne całkowite elementy pierwotnej tablicy (która ma inny typ - tak jak tutaj, gdzie pierwotna tablica to int[5][3]) musisz ofc pomnożyć numer elementu (lub przesunięcie) przez wielkość pojedynczego elementu faktycznej tablicy (wyrażoną w bajtach).

Czyli (na przykładzie):

int tab[3][5] = {0};
int *wsk = &tab[0][0];
unsigned char *wskb = (unsigned char*)&tab[0][0];
wsk += 2 * 5 + 1; // wskaż na element tab[2][1]; kompilator wie, że typem docelowym jest int, więc pomnoży tą wielkość przez sizeof(int)

ale

wskb += (2 * 5 + 1) * sizeof(int); // kompilator wie jedynie, że typem docelowym jest unsigned char, wiec sam musisz pomnożyć przez sizeof(int) - czyli ilość bajtów przypadającą na element faktycznego typu docelowego

I jeszcze jedna sprawa - to co Wojtek79 napisał - wsk[2][0] = ... - niestety nie zadziała dla wsk będącego int. Żeby coś takiego obliczyć kompilator musiałby znać ilość elementów w wierszu, a na podstawie typu tego nie wie.
Oczywiście, jeśli ilość elementów w wierszu jest stałą, możesz stworzyć wskaźnik na "tablicę z N intów w wierszu", np.:

#include <stdio.h>

int
main(void) {

  int tab[3][5] = {
    { 0, 1, 2, 3, 4 },
    { 10,11,12,13,14 },
    { 20,21,22,23,24 }
  };

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

  printf("1,3 == %u", wsk[1][3]);


  return 0;
}

W tym przykładzie typem wsk jest int(*)[5] (wskaźnik na tablicę intów z 5cioma elementami w wierszu), więc kompilator może sobie spokojnie wyliczyć docelowy adres, bo ma wszystkie potrzebne informacje.

Edit: trochę rozszerzyłem wyjaśnienie wyżej - _13th_Dragon zasugerował, że, mimo przykładu, nie wszystko może być dla wszystkich jasne ;)

0
Gynvael Coldwind napisał(a):

\Jedynym wyjątkiem (w granicach standardu) jest jeśli wsk byłby pointerem na unsigned char (czyli de facto na bajt) - wtedy chcąc przeskoczyć na kolejny element musisz ofc pomnożyć numer elementu przez ilość bajtów.

Przypomnij sobie IV -przekazanie.

#include <stdio.h>

int main()
  {
   unsigned y,x,p;
   unsigned char *ptr,tb[4][3]={{'1','2','3'},{'4','5','6'},{'7','8','9'},{'A','B','C'}};
   for(y=0;y<4;++y,printf("\n")) for(x=0;x<3;++x) printf("%2c",tb[y][x]);
   printf("\n");
   ptr=tb;
   for(p=y=0;y<4;++y,printf("\n")) for(x=0;x<3;++x,++p) printf("%2c",ptr[p]);
   printf("\n");
   for(p=y=0;y<4;++y,printf("\n")) for(x=0;x<3;++x,++p) printf("%2c",*(ptr+p));
   printf("\n");
   for(p=y=0;y<4;++y,printf("\n")) for(x=0;x<3;++x,++p) printf("%2c",p[ptr]);
   return 0;
  }

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