Poruszanie się wskaźnikiem po tablicy 2D

Arek Z.
2013-10-27 01:35
Arek Z.
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

edytowany 1x, ostatnio: furious programming, 2016-12-13 18:26
if(&amp;tab[0][0]+2==&amp;tab[0][2]) printf(&quot;OK&quot;); oraz if(&amp;tab[0][0]+2*ColCount==&amp;tab[2][0]) printf(&quot;OK&quot;); - _13th_Dragon 2013-10-27 07:27

Pozostało 580 znaków

Wojtek79
2013-10-27 02:42
Wojtek79
0

A czemu nie zrobisz po prostu

*wsk[2][0] = ...

Pozostało 580 znaków

2013-10-27 07:24

Rejestracja: 14 lat temu

Ostatnio: 2 dni temu

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;
  }

Wykonuję programy na zamówienie, pisać na Priv.
Asm/C/C++/Pascal/Delphi/Java/C#/PHP/JS oraz inne języki.

Pozostało 580 znaków

2013-10-27 10:24

Rejestracja: 16 lat temu

Ostatnio: 2 tygodnie temu

Lokalizacja: Zurich, Switzerland

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 ;)


peace,
gynvael.coldwind//vx

"Imagination is more important than knowledge..." Albert Einstein
edytowany 1x, ostatnio: Gynvael Coldwind, 2013-10-27 18:32

Pozostało 580 znaków

2013-10-27 11:38

Rejestracja: 14 lat temu

Ostatnio: 2 dni temu

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;
  }

Wykonuję programy na zamówienie, pisać na Priv.
Asm/C/C++/Pascal/Delphi/Java/C#/PHP/JS oraz inne języki.
edytowany 1x, ostatnio: _13th_Dragon, 2013-10-27 11:39
Pokaż pozostałe 7 komentarzy
Przeczytaj jeszcze raz fragment który zacytowałem, z tego absolutnie nie jasne że chodzi o rzutowanie na (char*) jakiegoś innego typu wskaźnika. Więc doprecyzowania powinny znaleźć się tam gdzie są wymagane. Ten post jedynie zwraca uwagę na to, a jest postem a nie komentarzem do twojego postu tylko dla tego że w komentarzach nie da się wsadzić przykładu. - _13th_Dragon 2013-10-27 17:33
Oczywiście, że to nie jest jasne z fragmentu który cytujesz, ponieważ wyrwałeś go z kontekstu ;p Rzuć okiem na mój post i zauważ, że zarówno nad, jak i pod fragmentem który cytujesz jest sporo tekstu. Nad jest m.in. zdefiniowane czym jest tab (int[N][M]) oraz wsk (int*). Potem jest cytowany fragment (w którym pisze o innym typie dla wsk, który nadal wskazuje na tą samą tablicę intów - nigdzie nie napisałem, ani nie zasugerowałem, że typ tablicy się zmienia). A pod jest przykład wraz z komentarzami, z którego dokładnie wynika o jaki case mi chodził. - Gynvael Coldwind 2013-10-27 17:53
Możesz czytać razem z poprzednim i nawet w całości - nigdzie nawet nie pojawia się słowo rzutowanie (nawet w postaci synonymów). Jedyna szansa zrozumienia tego co miałeś na myśli to przyjąć że: "... jeśli masz wsk który jest int* ..." - dotyczy tego int* w przytoczonym NIŻEJ kodzie, zaś kolejny wyraz "... jeśli wsk byłby pointerem na unsigned char ..." - dotyczy ewentualnej częściowej korekty w przytoczonym NIŻEJ kodzie. - _13th_Dragon 2013-10-27 18:04
Rzutowanie ładnie widać w przykładowym kodzie, dołączonym do zdania, na którego analizę poświęciliśmy już całkiem sporo czasu :D Cóż, nadal twierdzę, że w kontekście przykładu to zdanie jest jasne i zrozumiałe, i pozostaje mi mieć nadzieję, że większość zainteresowanych jednak zrozumie to co napisałem ;) (a nawet jeśli nie zrozumieją od razu - cóż, ewentualne * 1 nic w kodzie nie popsuje ;>). - Gynvael Coldwind 2013-10-27 18:19
Żeby zaoszczędzić nam obu trochę czasu, trochę przerobiłem zdanie o którym dyskutujemy ;) - Gynvael Coldwind 2013-10-27 18:34

Pozostało 580 znaków

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