Aktyw Forum

Zarejestruj się na forum.ep.com.pl i zgłoś swój akces do Aktywu Forum. Jeśli jesteś już zarejestrowany wystarczy, że się zalogujesz.

Sprawdź punkty Zarejestruj się

przesyłanie tablic do funkcji w C

Awatar użytkownika
pajaczek
Moderator
Moderator
Posty:2653
Rejestracja:24 sty 2005, o 00:39
Lokalizacja:Winny gród

Postautor: pajaczek » 2 cze 2006, o 13:20

Guru:

Ups. Faktycznie sie zagalopowalem z tym przekazywaniem bezposrednio. Wskaznik wskaznik i jeszcze raz szpachla.

Slawek:

a w tym przykladzie

Kod: Zaznacz cały

char tab[4][2];

to tablica ile ma wierszy a ile kolumn (a moze ile ma kolumn, a ile wierszy) ?? Jak sadzisz ??

Sławek5
-
-
Posty:485
Rejestracja:15 sie 2003, o 16:40
Lokalizacja:Szczecin
Kontaktowanie:

Postautor: Sławek5 » 3 cze 2006, o 04:38

Zainteresował minie coś co napisałeś a_antoniak:
Dlatego, ze mozesz zadeklarowac wielowymiarowa, a odwolywac sie jak do jednowymiarowej, co w roznych pascalach czy basicach nie jest mozliwe
Mam prośbę, czy możesz pokazać taki przykład.

Awatar użytkownika
bis
-
-
Posty:134
Rejestracja:12 maja 2005, o 08:11
Lokalizacja:Warszawa

Postautor: bis » 3 cze 2006, o 18:31

W C tablica dowolnej komplikacji jest rozróżniana nazwą. np

Kod: Zaznacz cały

typ_elementu Tablica[10][20][30];
ale nazwa Tablica jest tożsama ze wskażnikiem do początkowego elementu tablicy,

Kod: Zaznacz cały

typ_elementu *pPtr;
i można zapisać

Kod: Zaznacz cały

pPtr = Tablica;
i jest to całkowicie uprawnione. Co to jest tablica: jest to po prostu obszar pamięci, ciągły, którego kolejne elementy o rozmiarze sizeof(typ_elementu) są elementami tejże tablicy. już z tego prostego faktu wynika że dowolna tablica jest w pewnym sensie "jednowymiarowa".

Kod: Zaznacz cały

n = sizeof(Tablica[0]); m = sizeof(Tablica[0][0]);
Aby dostać się do elementu okreslonego indeksami a,b,c

Kod: Zaznacz cały

val1 = Tablica[a][b][c]; val2 = *(pPtr + n*a + m*b + c);
val1 i val2 będą miały tę samą wartość. Zapis wskażnikowy jest tak naprawdę tym co robi za nas kompilator generując dostęp do elementu opisanego z pomocą zapisu tablicowego. dla obrabiania tablic wielowymiarowych jest to wygodne w zapisie tekstowym ale generuje duży i powolny kod. np przy przeskanowaniu tablicy po jednym indeksie

Kod: Zaznacz cały

for( i=0; i<30; i++ ) {...... val = Tablica[a][b][i]; ...... }
wartość odpowiedniego wskazania do rzeczywistej pamięci jest wyliczana od podstaw za każdym obrotem pętli, ale można (zachowując niezbędną ostrożność)

Kod: Zaznacz cały

pPtr = &Tablica[a][b][0];// pierwszy element for( i=0; i<30; i++ ) {...... val = *pPtr; ....... pPtr++;// następny element }
takie podejście pozwala skracać czas wykonania pętli (z reguły daje też mniejszy kod). dla pętli po innych wymiarach tablicy trzeba będzie modyfikować wskażnik o odpowiedni rozmiar

Kod: Zaznacz cały

pPtr += sizeof( Tablica[0][0] );// dla pętli po drugim indeksie pPtr += sizeof( Tablica[0] ) ;// dla pętli po pierwszym indeksie


a teraz inaczej:

Kod: Zaznacz cały

pPtr = Tablica; val 1 = Tablica[a][b][c]; val 2 = pPtr[ a*n+ b*m + c ];
jak widać do tablicy można się dostać zarówno jako do wielowymiarowej jak i jednowymiarowej tylko trzeba wiedzieć jak się poruszać po indeksach.

Może to ułatwi zrozumienie sprawy tablic i wskaźników.

a_antoniak
-
-
Posty:651
Rejestracja:13 sty 2005, o 18:38
Lokalizacja:Krasnystaw
Kontaktowanie:

Postautor: a_antoniak » 3 cze 2006, o 19:48

bis - super wyjasnienie! Chcialbym dodac 1 rzecz:
W C tablica dowolnej komplikacji jest rozróżniana nazwą. np

Kod: Zaznacz cały

typ_elementu Tablica[10][20][30];
ale nazwa Tablica jest tożsama ze wskażnikiem do początkowego elementu tablicy,

Kod: Zaznacz cały

typ_elementu *pPtr;
i można zapisać

Kod: Zaznacz cały

pPtr = Tablica;
i jest to całkowicie uprawnione.

Popatrzmy:

Kod: Zaznacz cały

char Tablica[3][4][5]; char *pPtr; //To jest wskaznik na char char (*tabPtr)[4][5]; //To jest wskaznik na 1. element //tablicy Tablica,czyli inna tablice (2 wym) pPtr=Tablica; //!!! warning tabPtr=Tablica; //OK //Porownanie rozmiarow pierwszego el. tablicy Tablica //(pobranego na 2 sposoby) i typu 'char' printf("sizeof(Tablica[0])=%d, sizeof(*Tablica)=%d, sizeof(char)=%d \n", sizeof(Tablica[0]), sizeof(*Tablica), sizeof(char));
Warning przy kompilacji:
'char *' differs in levels of indirection from 'char (*)[4][5]'

Efekt dzialania programu:
sizeof(Tablica[0])=20, sizeof(*Tablica)=20, sizeof(char)=1

Z tego, ze typy maja rozne dlugosci wynika, ze nie sa to te same typy (twierdzenie odwrotne oczywiscie nie jest prawdziwe).

Wszyscy zgodzimy sie, ze zapis:

Tablica[0] lub *Tablica

pobiera 1. element tablicy (o indeksie 0), jakikolwiek by on nie byl. Powyzsze pokazuje, ze pierwszym elementem tablicy Tablica nie jest char (czyli typ_elementu). Jest nim tablica xxx[4][5], ktorej elemenatmi sa tablice yyy[5], ktorej elementami dopiero sa char-y.

Awatar użytkownika
bis
-
-
Posty:134
Rejestracja:12 maja 2005, o 08:11
Lokalizacja:Warszawa

Postautor: bis » 3 cze 2006, o 20:12

a_antoniak: święta racja, no trochę się omsknąłem. To przypisamie w moich przykładach powinno wyglądać tak

Kod: Zaznacz cały

pPtr = (typ_elementu *)Tablica;
teraz nie będzie problemów.
bis

Sławek5
-
-
Posty:485
Rejestracja:15 sie 2003, o 16:40
Lokalizacja:Szczecin
Kontaktowanie:

Postautor: Sławek5 » 4 cze 2006, o 07:55

Cześć.
Dzięki serdeczne za wyjaśnienie.

Napoisałem prymitywną rzecz jak u was :

Kod: Zaznacz cały

void main(void) { char tab[4][3]; char *ptr; ptr=tab; }

I kompilator wyrzucił:
E E:\icc\TEST\main.c(13): operands of = have illegal types `pointer to char' and `pointer to array 3 of char'

Po napisaniu

Kod: Zaznacz cały

ptr=(char *)tab;
Wszystko jest OK.

Dzięki.

Awatar użytkownika
bis
-
-
Posty:134
Rejestracja:12 maja 2005, o 08:11
Lokalizacja:Warszawa

Postautor: bis » 4 cze 2006, o 14:28

Tak na marginesie to nie ma sie co martwić zawiłością i błędami w rozumieniu typów tablicowych w C. Nawet twórcy języka i bibliotek nie uniknęli niezreczności z tym związanych. Przykładem na to sa deklaracje dla modułu standardowego "setjmp" gdzie właśnie strukturę dla przechowywania stanu programu (dla powrotu poprzez longjmp()) zdefiniowano kiedyś jako tablicę i tak zostało(choć ma to swoje uzasadnienie praktyczne). Zawsze rodzi to problemy przy używaniu (bardzo przydatnych) funkcji setjmp() i longjmp() bo zapis wywołania jest "nienaturalny" dla C.
bis

Wróć do „PLD/FPGA i inne zagadnienia techniki cyfrowej”

Kto jest online

Użytkownicy przeglądający to forum: Obecnie na forum nie ma żadnego zarejestrowanego użytkownika i 25 gości