2010-02-01 14 views
6
int **a = malloc2d(M, N) // dynamically allocates a 2D array 

Jaki jest cel posiadanie int ** a vice int * a. Rozumiem, że wskaźniki są potrzebne do alokacji dynamicznej, ale dlaczego mają wskaźnik do wskaźnika?Dlaczego wskaźnik do wskaźnika (int ** a)?

Dla 3-wymiarowej tablicy byłoby:

int ***a 

?

+2

Tak Byłoby 3 tablice wymiar jest gdzie zaczyna się dostać nieco trudny, po 3 wymiarowych tablicach moja głowa zaczyna boleć i próbuję znaleźć inny sposób przechowywania moich danych. – Craig

+0

Tablica 3 wymiarowa jest jak przechowywanie informacji w podzielonym na sekcje polu, więc jeśli masz pudełko wielkości 10x10x10, a każdy 1x1x1 przechowuje pewną informację, możesz przechowywać 1000 informacji. Ale tak jak powiedziałem po trzech wskaźnikach, możesz chcieć spojrzeć na inny sposób przechowywania danych. Przykład użycia tablicy 3D to obraz, np. Mapa bitowa wielkości 1024x1024, a przy każdym z pikseli na obrazie, który chcesz zapisać wartość R, G, B, możesz mieć tablicę o wymiarach 1024x1024x3, co oznacza pozycja na siatce 1024x1024 możesz zapisać [0] [1] i [2] liczbę danych. – Craig

Odpowiedz

8

Potrzebujesz wskaźnika do wskaźnika z kilku powodów.

W podanym przykładzie zastosowano podwójny wskaźnik do przechowywania tablicy 2D.

Tablica 2D w C jest traktowana jako tablica 1D, której elementami są tablice 1D (wiersze).

Na przykład, macierz 4x3 T (gdzie "t" jest jakiś rodzaj danych) może być uznana za "t maty [4], [3]" i opisany następującym schematem:

     +-----+-----+-----+ 
    mat == mat[0] ---> | a00 | a01 | a02 | 
         +-----+-----+-----+ 
         +-----+-----+-----+ 
     mat[1] ---> | a10 | a11 | a12 | 
         +-----+-----+-----+ 
         +-----+-----+-----+ 
     mat[2] ---> | a20 | a21 | a22 | 
         +-----+-----+-----+ 
         +-----+-----+-----+ 
     mat[3] ---> | a30 | a31 | a32 | 
         +-----+-----+-----+ 

Inną sytuacją jest sytuacja, w której przekazałeś wskaźnik do funkcji i chcesz, aby ta funkcja przyporządkowała ten wskaźnik. Do tego trzeba adres zmiennej wskaźnik, stąd wskaźnik do wskaźnika

void make_foofoo(int** change) { 
    *change = malloc(4); 
} 
1

Pomaga narysować zdjęcie. Wyobraź sobie tablicę jednowymiarową, w której każdy element zawiera wskaźnik. Każdy z tych wskaźników wskazuje na inną jednowymiarową tablicę. malloc2d nie jest standardową funkcją biblioteczną, ale domyślam się, że zwraca ona dwuwymiarową tablicę skonstruowaną w ten sposób.

1

Możesz użyć tej opcji, aby utworzyć tablicę o wymiarach 2, rodzaj matrycy matematycznej lub szachownicy. Dzięki temu możesz przechowywać tabelę danych.

1

Normalna tablica C jest wskaźnikiem do bloku pamięci.

Tablica 2D jest wskaźnikiem do listy wskaźników do każdego wiersza tablicy.

tak, wskaźnik do wskaźnika.

2

Właśnie przez wzgląd na zabawy, oto ***** przykład:

  1. mamy tekstur 3D (a objętościowy tekstury) - 3 wymiary, stąd ***
  2. każdy wokseli w tekstury ma kolor (*)
  3. tekstury jest animowana, ma framecount w czasie (*)

Stąd mamy tex [2] [3] [10] [2] [10] ....który jest:

  1. 2,3,10 współrzędnych 3D
  2. 2 kolor (kolor zielony)
  3. ramy 10

je zaliczyć do danych z możliwością modyfikowania go, to” d musi przejść int****** ... zabawy! xD

(i dlatego lubię struct i klasy ....)

0

tylko kiedykolwiek przejść wielkość wskaźnika (najczęściej 32 lub 64 bity), a nie całych obiektów.

7

W języku C wskaźnik do typu T wskazuje lokalizację, w której są przechowywane niektóre dane typu T. Aby wszystko było konkretne, omówię poniżej: T = int.

Najprostsze wykorzystanie wskaźnika może być wskazanie do jednej wartości:

int a = 42; 
int *pa = &a; 

Teraz *pa i a są zarówno takie same i równe 42. Również *pa i pa[0] oba równoważne: tak, na przykład, można zrobić:

*pa += 1; /* a is 43 */ 
pa[0] += 1; /* a is 44 */ 
a += 1; /* a is 45 */ 

W rzeczywistości, kompilator C przekłada pa[0] do *(pa+0) automatycznie.

Wskaźnik może wskazywać na miejscu, które znajduje się wewnątrz sekwencji danych:

int arr[] = { 1, 2, 3 }; /* 3 ints */ 
int *parr = arr; /* points to 1 */ 

Teraz nasza pamięć wygląda następująco:

  +---+---+---+ 
     arr: | 1 | 2 | 3 | 
      +---+---+---+ 
+------+  | 
| parr | ----+ 
+------+ 

parr to wskaźnik, który wskazuje na pierwszy element arr na powyższym rysunku. Nawiasem mówiąc, parr ma również pudełko dookoła, ponieważ musimy przechowywać obiekt gdzieś w pamięci obiektu parr. Wartość parr jest adresem pierwszego elementu z arr.

Teraz możemy użyć parr aby uzyskać dostęp do elementów arr:

arr[0] == parr[0]; /* true */ 
parr[1]++; /* make arr[1] equal to 3 */ 

Tak, wskaźnik może być używany w znaczeniu „Zwracam się do pierwszego z n elementów w ciągłym sklepie niektórych obiektów” . Oczywiście trzeba wiedzieć, ile obiektów istnieje, aby ten schemat działał: ale gdy już to pamiętamy, jest to bardzo wygodny sposób dostępu do pamięci w C.

Wskaźnik może wskazywać dynamicznie przydzielona pamięć, a także:

#include <stdlib.h> 
size_t n; 
/* now, obtain a value in n at runtime */ 
int *p = malloc(n * sizeof *p); 

Jeśli połączenie malloc() powiedzie powyżej p wskazuje teraz do pierwszego z przyległej strefy przeznaczonej dla 10 int s. Możemy teraz używać w naszym programie od p[0] do p[n-1].

Prawdopodobnie znasz większość lub wszystkie z powyższych :-), ale mimo to powyższe pomaga zrozumieć, co powiem dalej.

Pamiętaj, że powiedzieliśmy, że wskaźnik może wskazywać na ciągłą sekwencję obiektów tego samego typu? "Ten sam typ" może być również innym typem wskaźnika.

#include <stdlib.h> 
int **pp; 
pp = malloc(3 * sizeof *pp); 

Teraz pp punkty do int *. Wracając do naszych wcześniejszych zdjęciu:

  +------+------+------+ 
      |  |  |  | 
      +------+------+------+ 
+------+  | 
| pp | ----+ 
+------+ 

a każdy z 3 pól jest int *, które mogą wskazywać na pierwszy element ciągłej sekwencji int S:

for (i=0; i < 3; ++i) 
    pp[i] = malloc((i + 1) * sizeof *ppi[i]); 

Tutaj przydzielane przestrzeń dla jednej int w pp[0], 2 w pp[1] i 3 w pp[3]:

   +------+   +---+ 
pp -------->|  |-------->| | 
      +------+   +---+---+ 
      |  |-------->| | | 
      +------+   +---+---+---+ 
      |  |-------->| | | | 
      +------+   +---+---+---+ 

Więc pp[0] jest wskaźnikiem do jednego int, a int jest jedynym int w dynamicznie przydzielonym bloku int s. Innymi słowy, pp[0][0] jest int i wskazuje na najwyższe pole powyżej "width-3" powyżej. Podobnie, oba znaki są poprawne i są dwoma polami pod polem pp[0][0].

Najczęstsze zastosowanie wskaźnika do wskaźnika jest stworzenie 2-wymiarową tablicę „” w czasie wykonywania:

int **data; 
size_t i; 
data = malloc(n * sizeof *data); 
for (i=0; i < n; ++i) 
    data[i] = malloc(m * sizeof *data[i]); 

Teraz, przy założeniu, że wszystkie malloc() s uda, data[0] ... data[n-1] są prawidłowymi wartościami int * , z których każda wskazuje na osobną długość m sąsiednich obiektów .

Ale, jak pokazałem powyżej, wskaźnik do wskaźnika nie musi mieć tej samej "liczby elementów" w każdym z jej "wierszy". Najbardziej oczywistym przykładem jest argv in main().

Teraz, jak można się domyślić, to „głębokie” 3-poziomowy wskaźnik, takich jak int ***p; jest w porządku i mogą być przydatne w C.

+0

'int * pa = &42;' wygląda niepoprawnie, nie powinno to być 'int * pa = & a'? – Hasturkun

+0

Oczywiście. Nie mogę uwierzyć, że popełniłem ten błąd. Dzięki! –

Powiązane problemy