Kiedy masz wskaźnik do wskaźnika w C, musisz wiedzieć, w jaki sposób dane będą używane i rozmieszczone w pamięci. Teraz pierwsza kwestia jest oczywista i prawdziwa dla każdej zmiennej w ogóle: jeśli nie wiesz, w jaki sposób niektóre zmienne będą używane w programie, dlaczego tak jest? :-). Drugi punkt jest bardziej interesujący.
Na najbardziej podstawowym poziomie, wskaźnik do typu T
punkty jeden obiektu typu T
. Na przykład:
int i = 42;
int *pi = &i;
Teraz pi
punkty do jednego int
. Jeśli chcesz, możesz zrobić punkt wskaźnik do pierwszego z wielu takich obiektów:
int arr[10];
int *pa = arr;
int *pb = malloc(10 * sizeof *pb);
pa
wskazuje teraz na pierwszą z sekwencji 10 (ciągłych) int
wartości, przy założeniu, że malloc()
powiedzie, pb
punkty do pierwszego z innego zestawu 10 (ponownie, sąsiadującego) int
s.
To samo dotyczy jeśli masz wskaźnik do wskaźnika:
int **ppa = malloc(10 * sizeof *ppa);
Zakładając, że malloc()
powiedzie, teraz masz ppa
wskazując na pierwszą z sekwencji 10 ciągłych int *
wartości.
Więc, kiedy zrobić:
char **tmp = malloc(sizeof(char *)*CR_MULTIBULK_SIZE);
tmp
punkty do pierwszego char *
obiektu w sekwencji CR_MULTIBULK_SIZE
takich obiektów. Każdy z powyższych wskaźników nie został zainicjowany, więc wszystkie zawierają śmieci. Jednym ze sposobów, aby je zainicjować byłoby malloc()
nich:
size_t i;
for (i=0; i < CR_MULTIBULK_SIZE; ++i)
tmp[i] = malloc(...);
...
powyżej jest rozmiar danych i
th chcemy. Może to być stała lub zmienna, w zależności od i
, fazy księżyca, liczby losowej lub czegokolwiek innego. Najważniejsze, aby zwrócić uwagę, że w pętli masz CR_MULTIBULK_SIZE
połączenia z malloc()
i że podczas gdy każdy malloc()
zwróci ci sąsiedni blok pamięci, nie jest gwarantowane sąsiadowanie w połączeniach malloc()
. Innymi słowy, drugie wywołanie malloc()
nie zwróci wskaźnika, który rozpoczyna się w miejscu, w którym zakończyły się poprzednie dane.
Aby bardziej konkretne rzeczy, załóżmy CR_MULTIBULK_SIZE
to 3. Na zdjęciach, Twoje dane mogą wyglądać następująco:
+------+ +---+---+
tmp: | |--------+ +----->| a | 0 |
+------+ | | +---+---+
| |
| |
| +------+------+------+
+-------->| 0 | 1 | 2 |
+------+------+------+
| |
| | +---+---+---+---+---+
| +--->| t | e | s | t | 0 |
+------+ +---+---+---+---+---+
|
|
| +---+---+---+
+--->| h | i | 0 |
+---+---+---+
tmp
punktów do ciągłego bloku 3 char *
wartości. Pierwszy ze wskaźników, tmp[0]
, wskazuje na sąsiedni blok wartości 3 char
.Podobnie, tmp[1]
i tmp[2]
wskazują odpowiednio 5 i 2 char
s. Ale pamięć wskazywana przez tmp[0]
do tmp[2]
nie jest ciągła jako całość.
Od memcpy()
kopiuje sąsiednią pamięć, co chcesz zrobić, nie można zrobić przez jeden memcpy()
. Ponadto musisz wiedzieć, w jaki sposób przydzielono poszczególne numery tmp[i]
. Tak w ogóle, co chcesz zrobić, potrzebuje pętli:
char **realDest = malloc(CR_MULTIBULK_SIZE * sizeof *realDest);
/* assume malloc succeeded */
size_t i;
for (i=0; i < CR_MULTIBULK_SIZE; ++i) {
realDest[i] = malloc(size * sizeof *realDest[i]);
/* again, no error checking */
memcpy(realDest[i], tmp[i], size);
}
Jak wyżej, można zadzwonić memcpy()
wewnątrz pętli, więc nie trzeba zagnieżdżonych pętli w kodzie. (Najprawdopodobniej memcpy()
jest realizowana za pomocą pętli, więc efekt jest jak gdyby zagnieżdżone pętle.)
Teraz, jeśli miał kod jak:
char *s = malloc(size * CR_MULTIBULK_SIZE * sizeof *s);
size_t i;
for (i=0; i < CR_MULTIBULK_SIZE; ++i)
tmp[i] = s + i*CR_MULTIBULK_SIZE;
czyli ty przydzielone ciągłą przestrzeń dla wszystkich wskaźniki w jednym malloc()
rozmowy, można skopiować wszystkie dane bez pętli w kodzie:
size_t i;
char **realDest = malloc(CR_MULTIBULK_SIZE * sizeof *realDest);
*realDest = malloc(size * CR_MULTIBULK_SIZE * sizeof **realDest);
memcpy(*realDest, tmp[0], size*CR_MULTIBULK_SIZE);
/* Now set realDest[1]...realDest[CR_MULTIBULK_SIZE-1] to "proper" values */
for (i=1; i < CR_MULTIBULK_SIZE; ++i)
realDest[i] = realDest[0] + i * CR_MULTIBULK_SIZE;
z powyższego, odpowiedź jest prosta, jeśli miał więcej niż jeden malloc()
przydzielić pamięci dla tmp[i]
, będziesz potrzebował pętli do skopiowania wszystkich danych.
To całkowicie zależy od tego, jak zbudowana jest twoja "tablica wielowymiarowa". Pokaż kod, który go tworzy. – caf
jeśli nie masz wymiarów tablicowych, nie możesz ich skopiować również za pomocą pętli. –
@John Knoeller: Dzięki. Zaktualizowałem opis. – dan