Verwendung von malloc zur Zuweisung von mehrdimensionalen Arrays mit unterschiedlichen Zeilenlängen
Lesezeit: 4 Minuten
assel
Ich habe folgendes C Code:
int *a;
size_t size = 2000*sizeof(int);
a = malloc(size);
was gut funktioniert. Aber wenn ich folgendes habe:
char **b = malloc(2000*sizeof *b);
wo jedes Element von b hat eine andere Länge.
Wie ist es möglich, dasselbe für zu tun b wie ich für a; dh der folgende Code würde richtig halten?
char *c;
size_t size = 2000*sizeof(char *);
c = malloc(size);
Nikolai Fetissov
Zuerst müssen Sie ein Array von Zeigern wie zuweisen char **c = malloc( N * sizeof( char* ))und weisen Sie dann jeder Zeile einen separaten Aufruf von zu mallocwahrscheinlich in der Schleife:
/* N is the number of rows */
/* note: c is char** */
if (( c = malloc( N*sizeof( char* ))) == NULL )
{ /* error */ }
for ( i = 0; i < N; i++ )
{
/* x_i here is the size of given row, no need to
* multiply by sizeof( char ), it's always 1
*/
if (( c[i] = malloc( x_i )) == NULL )
{ /* error */ }
/* probably init the row here */
}
/* access matrix elements: c[i] give you a pointer
* to the row array, c[i][j] indexes an element
*/
c[i][j] = 'a';
Wenn Sie die Gesamtzahl der Elemente kennen (z N*M) können Sie dies in einer einzigen Zuordnung tun.
Wenn Sie N zuordnenM Bytes in einer einzigen Operation, dann füllen Sie alle c[i]s manuell: c[i] = p + Mich;
– Tadeusz A. Kadłubowski
28. Dezember 2009 um 18:28 Uhr
Das hängt vom Typ des c ab – wenn es char** ist, dann ja, wenn es char* ist, dann ändert sich die Indizierung: element[i][j] ~ c[i*M + j].
– Nikolai Fetissov
28. Dezember 2009 um 18:30 Uhr
@Nikolai N Fetissov, es gibt viele Mallocs im Code, wie kann das alles befreit werden? indem Sie auch for-Schleifen verwenden?
– e19293001
24. Oktober 2011 um 8:02 Uhr
@e19293001 ja, eins free für jeden malloc. Die müsstest du durchschleifen char* Variablen, die sie freigeben, und dann die freigeben char**.
– erickrf
8. Juni 2012 um 18:27 Uhr
Ich habe dasselbe in einem Buch gesehen, in dem stand: “… Speicher ist nicht garantiert zusammenhängend.”?
– dumm3
5. Dezember 2017 um 20:29 Uhr
Die typische Form für die dynamische Zuordnung eines NxM-Arrays vom Typ T ist
T **a = malloc(sizeof *a * N);
if (a)
{
for (i = 0; i < N; i++)
{
a[i] = malloc(sizeof *a[i] * M);
}
}
Wenn jedes Element des Arrays eine andere Länge hat, ersetzen Sie M durch die entsprechende Länge für dieses Element; zum Beispiel
T **a = malloc(sizeof *a * N);
if (a)
{
for (i = 0; i < N; i++)
{
a[i] = malloc(sizeof *a[i] * length_for_this_element);
}
}
Wenn ich die Gesamtzahl der Ints habe, die ich haben werde, aber nicht, wie viele davon in jedes Array gehen, wie soll ich vorgehen?
– Diätspeck
15. September 2014 um 23:01 Uhr
Sehr klare Antwort, danke! Könnten Sie auch eine Beschreibung hinzufügen, in welcher Reihenfolge richtig free der zugewiesene Speicher?
– Kagaratsch
18. Februar 2018 um 17:03 Uhr
@Kagaratsch: Im Allgemeinen kostenlos in der umgekehrten Reihenfolge, die Sie zugewiesen haben – dh jeweils kostenlos a[i] erst dann frei a.
– Johannes Bode
18. Februar 2018 um 17:59 Uhr
Ramesh
Äquivalente Speicherzuweisung für char a[10][20] wäre wie folgt.
Der andere Ansatz wäre, einen zusammenhängenden Speicherblock zuzuweisen, der einen Header-Block für Zeiger auf Zeilen sowie einen Body-Block zum Speichern tatsächlicher Daten in Zeilen umfasst. Markieren Sie dann einfach den Speicher, indem Sie die Adressen des Speichers im Körper den Zeigern im Header auf Zeilenbasis zuweisen. Es würde wie folgt aussehen:
int** 2dAlloc(int rows, int* columns) {
int header = rows * sizeof(int*);
int body = 0;
for(int i=0; i<rows; body+=columnSizes[i++]) {
}
body*=sizeof(int);
int** rowptr = (int**)malloc(header + body);
int* buf = (int*)(rowptr + rows);
rowptr[0] = buf;
int k;
for(k = 1; k < rows; ++k) {
rowptr[k] = rowptr[k-1] + columns[k-1];
}
return rowptr;
}
int main() {
// specifying column amount on per-row basis
int columns[] = {1,2,3};
int rows = sizeof(columns)/sizeof(int);
int** matrix = 2dAlloc(rows, &columns);
// using allocated array
for(int i = 0; i<rows; ++i) {
for(int j = 0; j<columns[i]; ++j) {
cout<<matrix[i][j]<<", ";
}
cout<<endl;
}
// now it is time to get rid of allocated
// memory in only one call to "free"
free matrix;
}
Der Vorteil dieses Ansatzes ist das elegante Freigeben von Speicher und die Fähigkeit, eine Array-ähnliche Notation zu verwenden, um auf Elemente des resultierenden 2D-Arrays zuzugreifen.
Sockel
Wenn jedes Element in b unterschiedliche Längen hat, müssen Sie so etwas tun:
Es weist einem eindimensionalen Array von char*-Zeigern keinen Speicher zu.
– Tadeusz A. Kadłubowski
28. Dezember 2009 um 18:29 Uhr
zdav
Ich denke, ein 2-Schritt-Ansatz ist am besten, weil c 2-d-Arrays nur ein Array von Arrays sind. Der erste Schritt besteht darin, ein einzelnes Array zuzuweisen, dann eine Schleife durchzugehen und dabei Arrays für jede Spalte zuzuweisen. Dieser Artikel gibt gute Details.
Es weist einem eindimensionalen Array von char*-Zeigern keinen Speicher zu.
– Tadeusz A. Kadłubowski
28. Dezember 2009 um 18:29 Uhr
Sigisaft
Dynamische 2-D-Array-Speicherzuweisung
int **a,i;
// for any number of rows & columns this will work
a = malloc(rows*sizeof(int *));
for(i=0;i<rows;i++)
*(a+i) = malloc(cols*sizeof(int));
14158700cookie-checkVerwendung von malloc zur Zuweisung von mehrdimensionalen Arrays mit unterschiedlichen Zeilenlängenyes