2013-03-20 14 views
6

Zacząłem czytać kilka artykułów na temat wskaźników w C i mam jeden przykład, którego nie rozumiem.O wskaźnikach w C

Przykładem jest tutaj: http://en.wikibooks.org/wiki/C_Programming/Pointers_and_arrays

Oto ona:

Spójrzmy na nieco inny problem. Chcemy mieć tablicę dwuwymiarową, ale nie musimy mieć wszystkich wierszy tej samej długości. To, co robimy, to deklaracja szeregu wskaźników. Druga linia poniżej deklaruje A jako tablicę wskaźników. Każdy wskaźnik wskazuje na pływak. Oto niektóre stosowane Kod:

float linearA[30]; 
float *A[6]; 

A[0] = linearA;    /* 5 - 0 = 5 elements in row */ 
A[1] = linearA + 5;   /* 11 - 5 = 6 elements in row */ 
A[2] = linearA + 11;   /* 15 - 11 = 4 elements in row */ 
A[3] = linearA + 15;   /* 21 - 15 = 6 elements  */ 
A[4] = linearA + 21;   /* 25 - 21 = 4 elements  */ 
A[5] = linearA + 25;   /* 30 - 25 = 5 elements  */ 

A[3][2] = 3.66;   /* assigns 3.66 to linearA[17];  */ 
A[3][-3] = 1.44;   /* refers to linearA[12];   
          negative indices are sometimes useful. 
          But avoid using them as much as possible. */ 

Moje pytanie brzmi dlaczego A[0] jest wskaźnikiem tylko do pięciu elementów, a nie do wszystkich linearA, ponieważ nazwa tablicy jest wskaźnikiem do jej pierwszego elementu.

I A[1] = linearA + 5; to 6 elementów z rzędu - z tego samego powodu? Czy numer A[1] nie ma być wskaźnikiem dla 6. członka linearA?

Czy ktoś może wyjaśnić, gdzie jest mój błąd?

+0

Jest to zamierzone użycie, że 'A [0]' należy przyjąć jako wskaźnik do pierwszego elementu tablicy pięciu 'float'ów. Możesz także użyć go jako wskaźnika do pierwszego elementu tablicy 30 'float's, ponieważ to zapewnia' linearA'. To wszystko tylko interpretacja. –

+2

Wskaźniki nie mają informacji o * liczbie elementów *, do których prowadzą. Wskaźnik do pierwszego elementu tablicy o rozmiarze 42 jest dokładnie taki sam, jak dla * liczby elementów * tego, na co wskazują, jako wskaźnik do pierwszego elementu tablicy o rozmiarze 12000. W twoim przykładzie 'A [0] 'jest wskaźnikiem do pierwszego elementu tablicy złożonej z 30 elementów ... ale nie dba o * liczbę elementów *. Programista interpretuje go jako * 5 elementów * przed wykonaniem innych zadań. – pmg

+0

@pmg: * Typ * wskaźnika wskazuje rozmiar (i inne informacje) tego, co wskazuje. Informacje te zwykle nie są przechowywane w czasie wykonywania. –

Odpowiedz

3

Z wyjątkiem kilku wyjątków, w C nazwa tablicy jest konwertowana na wskaźnik do pierwszego elementu tablicy. linearA jest tablicą 30 float w wyrażeniu:

A[0] = linearA; 

jest przekształcany do wskaźnika do float.

A to tablica 6 wskaźnika do float. Element A jest wskaźnikiem typu na float. Tak więc A[0] jest wskaźnikiem do float, a nie wskaźnikiem do tablicy.

I A[i][j] w C jest równoważny *(A[i] + j) tak A[i][j] jest float (dereferencing wskaźnik do float daje float).

+0

Zgadzam się ze wszystkim, co powiedziałeś, ale nie rozumiem ich komentarzy: A [0] = linearA;/* 5 - 0 = 5 elementów w rzędzie */ A [1] = linearA + 5;/* 11 - 5 = 6 elementów w rzędzie */ – Farseer

+0

@Farseer, ponieważ '(linearA + 5) - linearA == 5' i' (linearA + 11) - (linearA + 5) == 6' – ouah

1

A[0] to wskaźnik do pierwszego elementu z linearA. Ponieważ linearA jest ciągłą tablicą, ten wskaźnik faktycznie umożliwia dostęp do dowolnego elementu linearA 30 przez dodanie odpowiedniego przesunięcia. Jednak w tym kawałku kodu emulujesz tablicę 2D, wskazując różne przesunięcia w tablicy linearA. Rezultatem jest dwuwymiarowe adresowanie tablic: A[n] doprowadzi cię do lokalizacji (tj. Przesunięcie w linearA) twojego n-tego wiersza, a A[n][m] przeniesie Cię do m-tego elementu w tym wierszu.

+0

Nie, 'A [0] 'jest typu' float * ', i wskazuje na pojedynczy obiekt' float', który okazuje się być 0 elementem 'linearA'. –

+0

@KeithThompson o to mi chodziło, będę przeformułować, aby było jasne. – SomeWittyUsername

1

To dlatego, że ta linia ustawia tablicę 6 Wskaźniki do float:

float *A[6]; 

I ta linia wyznacza pierwszego z tych wskaźników do pierwszego elementu z 30.

A[0] = linearA; 

Dlatego każdy element A wskazuje na podsekcję oryginalnej tablicy. Musisz je jednak przypisać - będą początkowo wskazywać losowe adresy.

Pierwszy to początkowy adres (&linearA[0]), a następne pięć to kolejne. Są one dostępne jako A[0][0] do A[0][5]. Ze względu na sposób, w jaki tablice odpowiadają wskaźnikom, możesz podnosić poziom, o ile nie przekroczysz 30-tego.

Ale można przypisać A[n] do dowolnej części tablicy, którą lubisz. Dopóki jest to część oryginalnej tablicy, wskaże tego członka i następne 5 (lub dowolną liczbę).

Na przykład, wskazując A[1] na &linearA[6], można skutecznie ustawić dwuwymiarową tablicę (będzie przypominać jedną, ale nie zachowywać się jak jedna).

1

Moje pytanie brzmi, dlaczego A [0] jest wskaźnikiem tylko do pięciu elementów, a nie wszystkich linearA, ponieważ nazwa tablicy jest wskaźnikiem do swojego pierwszego członka.

ty setup A[0] aby wskazać linearA który jest pierwszym pływak w tablicy, A[0] jest wskaźnikiem, a zatem ma nic na temat tego, co wskazuje rozstać się z adresu nie znam. Tak więc A[0] nie jest wskaźnikiem tylko pięciu elementów, które wskazuje na początek tablicy i nie ma pojęcia, gdzie kończy się tablica.

I A [1] = linearA + 5; to 6 elementów z rzędu - z tego samego powodu? Czy A [1] nie ma być wskaźnikiem dla szóstego elementu linearA?

tak A[1] wskazuje na szósty element, ale jak powiedziano przed jego adresem początkowym.

1

Przykład, opublikowanego przedstawia nieco ezoterycznych techniki zwanej Iliffe vector, który jest jednym z możliwych sposobów realizacji postrzępione tablic w C. poszarpaną macierzy jest macierz, w którym każdy rząd ma inną długość.

Ponieważ tablice są jednowymiarowe w C, tworzysz pojedynczą tablicę linearA zawierającą wszystkie elementy, które są interpretowane jako sekwencja wierszy, każda o innym rozmiarze. Tablica wskaźnika A zawiera wskaźniki do pierwszego elementu każdego wiersza, które umożliwiają dostęp do elementów za pomocą indeksów wierszy i kolumn.

kodu wyświetla kilka interesujących cech wskaźników C i tablic:

linearA + 5 

wskaźnikiem arytmetyczne: dodanie liczbę całkowitą wskaźnik (albo szeregu) daje wskaźnik wskazujący n elementów po pierwotnym wskaźnikiem.

A[3][2] = 3.66; 

Ta ładna składnia pozwala myśleć o tej strukturze jako dwuwymiarowej macierzy.

Ponadto, jest to prawdopodobnie główny punkt przykładu, wskaźniki i tablice są wymienne. Tutaj, A[3] jest wskaźnikiem do float, ponieważ A został zdefiniowany jako tablica wskaźników do pływaków; dołączając [2] daje nam element 2 miejsca po tym, który wskazywał oryginalny wskaźnik.Jest to podobne do arytmetyki wskaźnika powyżej, tylko w tym przypadku wskaźnik jest dereferencjonowany. W rzeczywistości dostęp do tablicy jest zdefiniowany w odniesieniu do wskaźników, więc X[5] jest odpowiednikiem *(X+5).

A[3][-3] 

To pokazuje, że nic nie powstrzymuje cię przed dostępem do elementu znajdującego się poza danym wierszem. W takim przypadku użytkownik uzyskuje dostęp do elementu 3, miejsca , przed wskazaniem wskazanym przez . Jest to coś, co jest rzadko potrzebne i działa tylko w tym przypadku, ponieważ zbudowałeś macierz, aby mieć sąsiadujące elementy. Zwykle dostęp do elementów spoza przydzielonego zakresu tablicy spowoduje awarię programu.

Wreszcie, aby odpowiedzieć na pytanie:

I A[1] = linearA + 5; jest 6 elementów w jednym rzędzie - z tego samego powodu? Czy numer A[1] nie ma być wskaźnikiem dla 6. członka linearA?

jako wskaźniki i tablice są wymienne A[1] jest zarówno wskaźnik do szóstego elementu w linearAi oraz świeże począwszy od szóstego elementu w linearA. W języku nie ma nic, co mówi, że ten drugi ma 6 elementów, musisz wprowadzić tę logikę w swoim kodzie.