Jak pracować z dynamicznymi tablicami wielowymiarowymi w C?
Czy ktoś wie jak Mogę używać dynamicznie przydzielanych tablic wielowymiarowych używając C? Czy to możliwe?
9 answers
Z dynamiczną alokacją, używając malloc:
int** x;
x = malloc(dimension1_max * sizeof(*x));
for (int i = 0; i < dimension1_max; i++) {
x[i] = malloc(dimension2_max * sizeof(x[0]));
}
//Writing values
x[0..(dimension1_max-1)][0..(dimension2_max-1)] = Value;
[...]
for (int i = 0; i < dimension1_max; i++) {
free(x[i]);
}
free(x);
To przydziela tablicę 2D wielkości dimension1_max
* dimension2_max
. Na przykład, jeśli chcesz mieć tablicę 640 * 480 (np. piksele obrazu), użyj dimension1_max
= 640, dimension2_max
= 480. Następnie można uzyskać dostęp do tablicy używając x[d1][d2]
Gdzie d1
= 0..639, d2
= 0..479.
Ale wyszukiwanie w SO lub Google ujawnia również inne możliwości, na przykład w tym pytaniu SO
Zauważ, że tablica nie przydzieli sąsiadującego obszaru pamięci (640*480 bajtów), co mogłoby powodować problemy z funkcjami, które to zakładają. Tak więc, aby tablica spełniała warunek, zastąp powyższy blok malloc tym:
int** x;
int* temp;
x = malloc(dimension1_max * sizeof(*x));
temp = malloc(dimension1_max * dimension2_max * sizeof(x[0]));
for (int i = 0; i < dimension1_max; i++) {
x[i] = temp + (i * dimension2_max);
}
[...]
free(temp);
free(x);
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-01-24 10:56:35
Od C99, C ma tablice 2D z dynamicznymi granicami. Jeśli chcesz uniknąć tego, że takie bestie są przydzielane na stosie( co powinieneś), możesz je łatwo przydzielić jednym ruchem w następujący sposób
double (*A)[n] = malloc(sizeof(double[n][n]));
I to wszystko. Następnie można go łatwo używać, ponieważ są używane do tablic 2D z czymś takim jak A[i][j]
. I nie zapomnij tego na końcu
free(A);
Randy Meyers napisał serię artykułów wyjaśniających tablice o zmiennej długości (VLAs) .
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-03-20 06:21:27
Podstawy
Tablice w c są deklarowane i dostępne za pomocą operatora []
. Tak, że
int ary1[5];
Deklaruje tablicę 5 liczb całkowitych. Elementy są numerowane od zera, więc ary1[0]
jest pierwszym elementem, a {[10] } jest ostatnim elementem. Uwaga 1: nie ma domyślnej inicjalizacji, więc pamięć zajmowana przez tablicę może początkowo zawierać cokolwiek. Note2: ary1[5]
uzyskuje dostęp do pamięci w stanie nieokreślonym (który może nie być nawet Dostępny dla ciebie), więc nie rób tego to!
Tablice wielowymiarowe są zaimplementowane jako tablica tablic (of arrays (of ... ) ). Więc
float ary2[3][5];
Deklaruje tablicę 3 jednowymiarowych tablic po 5 liczb zmiennoprzecinkowych każda. Teraz ary2[0][0]
jest pierwszym elementem pierwszej tablicy, {[13] } jest ostatnim elementem pierwszej tablicy, a ary2[2][4]
jest ostatnim elementem ostatniej tablicy. Standard '89 wymaga, aby te dane były zgodne (sek. A8. 6. 2 na stronie 216 mojego K & R 2nd. ed.) ale wydaje się być agnostykiem na wyściółka.
Próbuje przejść dynamicznie w więcej niż jednym wymiarze
Jeśli nie znasz rozmiaru tablicy podczas kompilacji, będziesz chciał dynamicznie przydzielić tablicę. To kuszące, aby spróbować
double *buf3;
buf3 = malloc(3*5*sizeof(double));
/* error checking goes here */
Które powinno zadziałać, jeśli kompilator nie dokona zadanej alokacji (wstawia dodatkową przestrzeń między jednowymiarowymi tablicami). Może być bezpieczniej:
double *buf4;
buf4 = malloc(sizeof(double[3][5]));
/* error checking */
/ Align = "left" / Nie możesz pisać buf[i][j]
ponieważ buf
ma zły typ. Nie można też używać
double **hdl4 = (double**)buf;
hdl4[2][3] = 0; /* Wrong! */
Ponieważ kompilator oczekuje, że hdl4
będzie adresem adresu podwójnego. Nie można też używać double incomplete_ary4[][];
, ponieważ jest to błąd;
- wykonaj arytmetykę wierszy i kolumn samodzielnie
- przydzielaj i wykonuj pracę w funkcji
- użyj tablicy wskaźników (mechanizm o którym mówi qrdl)
Do the math yourself
Po prostu Oblicz przesunięcie pamięci do każdego elementu tak:
for (i=0; i<3; ++i){
for(j=0; j<3; ++j){
buf3[i * 5 + j] = someValue(i,j); /* Don't need to worry about
padding in this case */
}
}
Przydzielaj i wykonuj pracę w funkcji
Zdefiniuj funkcję, która przyjmuje wymagany rozmiar jako argument i postępuje normalnie
void dary(int x, int y){
double ary4[x][y];
ary4[2][3] = 5;
}
Oczywiście, w tym przypadku ary4
jest zmienną lokalną i nie można jej zwrócić: cała praca z tablicą musi być wykonana w funkcji, którą wywołujesz w funkcjach, które wywołuje ona .
Tablica wskaźników
Rozważ to:
double **hdl5 = malloc(3*sizeof(double*));
/* Error checking */
for (i=0; i<3; ++i){
hdl5[i] = malloc(5*sizeof(double))
/* Error checking */
}
Teraz hdl5
wskazuje na tablicę wskaźników każdy z nich wskazuje na tablicę sobowtórów. Fajnym bitem jest to, że możesz użyć dwuwymiarowej tablicy, aby uzyskać dostęp do tej struktury---hdl5[0][2]
dostaje środkowy element pierwszego wiersza---ale to nie jest inny rodzaj obiektu niż dwuwymiarowa tablica zadeklarowana przez double ary[3][5];
.
Ta struktura jest bardziej elastyczna niż tablica dwuwymiarowa (ponieważ wiersze nie muszą być tej samej długości), ale dostęp do niej będzie na ogół wolniejszy i wymaga więcej pamięci (potrzebujesz miejsce w klasyfikacji średniej punktów).
Zauważ, że ponieważ nie ustawiłem żadnych strażników, będziesz musiał śledzić rozmiar wszystkich tablic samodzielnie.
Arytmetyka
C nie zapewnia wsparcia dla matematyki wektorowej, macierzowej czy tensorowej, będziesz musiał ją zaimplementować samodzielnie lub wprowadzić bibliotekę.
Mnożenie przez Skaler oraz dodawanie i odejmowanie tablic o tej samej randze są łatwe: wystarczy zapętlić elementy i wykonać operację w miarę upływu czasu. Inner produkty są podobnie proste.
Produkty zewnętrzne oznaczają więcej pętli.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-01-07 17:54:26
Jeśli znasz liczbę kolumn w czasie kompilacji, jest to dość proste:
#define COLS ...
...
size_t rows;
// get number of rows
T (*ap)[COLS] = malloc(sizeof *ap * rows); // ap is a *pointer to an array* of T
Możesz traktować ap
jak dowolną tablicę 2D:
ap[i][j] = x;
Kiedy skończysz, deallokujesz to jako
free(ap);
Jeśli nie znasz liczby kolumn w czasie kompilacji, ale pracujesz z kompilatorem C99 lub kompilatorem C2011, który obsługuje tablice o zmiennej długości, to nadal jest to dość proste:
size_t rows;
size_t cols;
// get rows and cols
T (*ap)[cols] = malloc(sizeof *ap * rows);
...
ap[i][j] = x;
...
free(ap);
Jeśli nie znasz liczby kolumn w czasie kompilacji i pracujesz z wersją C, który nie obsługuje tablic o zmiennej długości, musisz zrobić coś innego. Jeśli chcesz, aby wszystkie elementy zostały przydzielone w ciągłym fragmencie (jak zwykła tablica), możesz przydzielić pamięć jako tablicę 1D i obliczyć przesunięcie 1D:
size_t rows, cols;
// get rows and columns
T *ap = malloc(sizeof *ap * rows * cols);
...
ap[i * rows + j] = x;
...
free(ap);
Jeśli nie potrzebujesz, aby pamięć była sąsiadująca, możesz zastosować dwuetapową metodę alokacji:
size_t rows, cols;
// get rows and cols
T **ap = malloc(sizeof *ap * rows);
if (ap)
{
size_t i = 0;
for (i = 0; i < cols; i++)
{
ap[i] = malloc(sizeof *ap[i] * cols);
}
}
ap[i][j] = x;
Ponieważ alokacja była procesem dwuetapowym, dealokacja również musi być procesem dwuetapowym:
for (i = 0; i < cols; i++)
free(ap[i]);
free(ap);
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-10-09 18:19:50
Malloc się nada.
int rows = 20;
int cols = 20;
int *array;
array = malloc(rows * cols * sizeof(int));
Aby uzyskać pomoc, zapoznaj się z poniższym artykułem: -
Http://courses.cs.vt.edu / ~ cs2704/spring00/Mcquain/Notes/4up / Managing2DArrays.pdf
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-10-09 16:24:51
Oto roboczy kod, który definiuje podprogram make_3d_array
do przydzielania wielowymiarowej tablicy 3D z N1
, N2
i N3
elementów w każdym wymiarze, a następnie zapełnia go przypadkowymi liczbami. Możesz użyć notacji A[i][j][k]
, aby uzyskać dostęp do jej elementów.
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
// Method to allocate a 2D array of floats
float*** make_3d_array(int nx, int ny, int nz) {
float*** arr;
int i,j;
arr = (float ***) malloc(nx*sizeof(float**));
for (i = 0; i < nx; i++) {
arr[i] = (float **) malloc(ny*sizeof(float*));
for(j = 0; j < ny; j++) {
arr[i][j] = (float *) malloc(nz * sizeof(float));
}
}
return arr;
}
int main(int argc, char *argv[])
{
int i, j, k;
size_t N1=10,N2=20,N3=5;
// allocates 3D array
float ***ran = make_3d_array(N1, N2, N3);
// initialize pseudo-random number generator
srand(time(NULL));
// populates the array with random numbers
for (i = 0; i < N1; i++){
for (j=0; j<N2; j++) {
for (k=0; k<N3; k++) {
ran[i][j][k] = ((float)rand()/(float)(RAND_MAX));
}
}
}
// prints values
for (i=0; i<N1; i++) {
for (j=0; j<N2; j++) {
for (k=0; k<N3; k++) {
printf("A[%d][%d][%d] = %f \n", i,j,k,ran[i][j][k]);
}
}
}
free(ran);
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-07-31 21:18:13
Nie da się przeznaczyć całości za jednym zamachem. Zamiast tego utwórz tablicę wskaźników, a następnie dla każdego wskaźnika utwórz dla niej pamięć. Na przykład:
int** array;
array = (int**)malloc(sizeof(int*) * 50);
for(int i = 0; i < 50; i++)
array[i] = (int*)malloc(sizeof(int) * 50);
Oczywiście można również zadeklarować tablicę jako {[2] } i pominąć pierwszy malloc, ale drugi zestaw jest potrzebny do dynamicznego przydzielania wymaganego miejsca.
Możliwe jest zhakowanie sposobu przydzielania go w jednym kroku, ale wymagałoby to niestandardowej funkcji wyszukiwania, ale napisanie tego w taki sposób, że to zawsze będzie działać może być irytujące. Przykładem może być L(arr,x,y,max_x) arr[(y)*(max_x) + (x)]
, Następnie malloc blok 50 * 50 ints lub cokolwiek i dostęp za pomocą tego makra L
, np.
#define L(arr,x,y,max_x) arr[(y)*(max_x) + (x)]
int dim_x = 50;
int dim_y = 50;
int* array = malloc(dim_x*dim_y*sizeof(int));
int foo = L(array, 4, 6, dim_x);
Ale to jest o wiele groźniejsze, chyba że znasz efekty tego, co robisz z makrem preprocesora.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-10-09 16:22:37
int rows, columns;
/* initialize rows and columns to the desired value */
arr = (int**)malloc(rows*sizeof(int*));
for(i=0;i<rows;i++)
{
arr[i] = (int*)malloc(cols*sizeof(int));
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-10-09 16:47:00
// Użyj new zamiast malloc, ponieważ użycie malloc prowadzi do wycieków pamięci 'wpisz tutaj kod
int **adj_list = new int*[rowsize];
for(int i = 0; i < rowsize; ++i)
{
adj_list[i] = new int[colsize];
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-07-14 05:56:09