it-swarm.com.de

Verwendung von Malloc für die Zuordnung von mehrdimensionalen Arrays mit unterschiedlichen Zeilenlängen

Ich habe den folgenden C-Code:

int *a;
size_t size = 2000*sizeof(int);
a = (int *) malloc(size);

das funktioniert gut. Wenn ich aber folgendes habe:

char **b = malloc(2000*sizeof *b);

wobei jedes Element von b eine unterschiedliche Länge hat.

Wie ist es möglich, dasselbe für b zu tun wie für a; Das heißt, der folgende Code würde korrekt sein?

char *c;
size_t size = 2000*sizeof(char *);
c = (char *) malloc(size);
65
asel

Zuerst müssen Sie ein Array von Zeigern wie char **c = malloc( N * sizeof( char* )) zuweisen und dann jeder Zeile einen separaten Aufruf von malloc zuweisen, wahrscheinlich 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. B. N*M), können Sie dies in einer einzelnen Zuordnung tun.

75

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);
  }
}
48
John Bode

Die äquivalente Speicherzuordnung für char a[10][20] wäre wie folgt.

char **a;

a=(char **) malloc(10*sizeof(char *));

for(i=0;i<10;i++)
    a[i]=(char *) malloc(20*sizeof(char));

Ich hoffe das sieht leicht verständlich aus.

27
Ramesh

Der andere Ansatz wäre, einen zusammenhängenden Speicherblock zuzuordnen, der einen Headerblock für Zeiger auf Zeilen sowie einen Bodyblock zum Speichern der tatsächlichen Daten in Zeilen umfasst. Markieren Sie dann einfach den Speicher, indem Sie den Zeigern im Header pro Zeile Adressen des Speichers im Hauptteil 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 die elegante Speicherfreigabe und die Möglichkeit, Array-artige Notationen für den Zugriff auf Elemente des resultierenden 2D-Arrays zu verwenden.

10
Dmitry Aleks

Wenn jedes Element in b unterschiedliche Längen hat, müssen Sie Folgendes tun:

int totalLength = 0;
for_every_element_in_b {
    totalLength += length_of_this_b_in_bytes;
}
return (char **)malloc(totalLength);
3
plinth

Ich denke, ein 2-Schritt-Ansatz ist am besten, weil c-2-d-Arrays nur Arrays und Arrays sind. Der erste Schritt besteht darin, ein einzelnes Array zuzuweisen und anschließend durchzugehen, wobei für jede Spalte Arrays zugewiesen werden. Dieser Artikel gibt gute Details.

2
zdav

Dynamische Speicherzuordnung für 2-D-Arrays

int **a,i;

// for any number of rows & columns this will work
a = (int **)malloc(rows*sizeof(int *));
for(i=0;i<rows;i++)
    *(a+i) = (int *)malloc(cols*sizeof(int));
1
Sridhar T

da malloc keine bestimmten Grenzen zuweist, muss davon ausgegangen werden, dass es sich auf eine Byte-Grenze bezieht.

Der zurückgegebene Zeiger kann nicht verwendet werden, wenn er in einen anderen Typ konvertiert wird, da der Zugriff auf diesen Zeiger wahrscheinlich zu einer Speicherzugriffsverletzung durch die CPU führt und die Anwendung sofort heruntergefahren wird.

0