So weisen Sie einem 2D-Array dynamisch einen zusammenhängenden Speicherblock zu

Lesezeit: 5 Minuten

Benutzer-Avatar
Traumkrach

Wenn ich ein 2D-Array so zuweise int ein[N][N]; es wird einen zusammenhängenden Speicherblock zuweisen.

Aber wenn ich versuche, es dynamisch so zu machen:

int **a = malloc(rows * sizeof(int*));
for(int i = 0; i < rows; i++) 
   a[i] = malloc(cols * sizeof(int));

Dadurch wird ein Einheitsschritt zwischen den Elementen in den Reihen aufrechterhalten, aber dies muss zwischen den Reihen nicht der Fall sein.

Eine Lösung ist die Konvertierung von 2D in 1D, gibt es außerdem eine andere Möglichkeit, dies zu tun?

  • Das ist kein mehrdimensionales C-Array, sondern ein Array von Zeigern auf getrennte Zeilen. Verwenden Sie einen Zeiger auf ein C99-VLA. Freakige Art, ein zweidimensionales Array zuzuweisen?

    – Peter Cordes

    31. März 2021 um 14:19 Uhr

Wenn Ihre Array-Dimensionen zur Kompilierzeit bekannt sind:

#define ROWS ...
#define COLS ...

int (*arr)[COLS] = malloc(sizeof *arr * ROWS);
if (arr) 
{
  // do stuff with arr[i][j]
  free(arr);
}

Wenn Ihre Array-Dimensionen zur Kompilierzeit nicht bekannt sind und Sie einen C99-Compiler oder einen C2011-Compiler verwenden, der Arrays mit variabler Länge unterstützt:

size_t rows, cols;
// assign rows and cols
int (*arr)[cols] = malloc(sizeof *arr * rows);
if (arr)
{
  // do stuff with arr[i][j]
  free(arr);
}

Wenn Ihre Array-Dimensionen zur Kompilierzeit nicht bekannt sind, und Sie sind es nicht Verwenden eines C99-Compilers oder eines C2011-Compilers, der Arrays mit variabler Länge unterstützt:

size_t rows, cols;
// assign rows and cols
int *arr = malloc(sizeof *arr * rows * cols);
{
  // do stuff with arr[i * rows + j]
  free(arr);
}

Tatsächlich sind n-dimensionale Arrays (auf dem Stapel zugewiesen) wirklich nur 1-dimensionale Vektoren. Die Mehrfachindizierung ist nur syntaktischer Zucker. Aber Sie können eine Accessor-Funktion schreiben, um so etwas wie das zu emulieren, was Sie wollen:

int index_array(int *arr, size_t width, int x, int y)
{
    return arr[x * width + y];
}

const size_t width = 3;
const size_t height = 2;
int *arr = malloc(width * height * sizeof(*arr));

// ... fill it with values, then access it:

int arr_1_1 = index_array(arr, width, 1, 1);

Wenn Sie jedoch C99-Unterstützung haben, ist es möglich, einen Zeiger auf ein Array zu deklarieren, und Sie können sogar den syntaktischen Zucker verwenden:

int (*arr)[width] = malloc(sizeof((*arr) * height);
arr[x][y] = 42;

Benutzer-Avatar
Matei Tene

Angenommen, Sie möchten ein zweidimensionales ganzzahliges Array von ROWS-Zeilen und COLS-Spalten dynamisch zuweisen. Dann können Sie zuerst einen kontinuierlichen Block von ROWS * COLS-Integern zuweisen und ihn dann manuell in ROWS-Zeilen aufteilen. Ohne syntaktischen Zucker liest sich das

int *mem = malloc(ROWS * COLS * sizeof(int));
int **A = malloc(ROWS * sizeof(int*));
for(int i = 0; i < ROWS; i++) 
   A[i] = mem + COLS*i;
// use A[i][j]

und kann effizienter durchgeführt werden, indem die Multiplikation vermieden wird,

int *mem = malloc(ROWS * COLS * sizeof(int));
int **A = malloc(ROWS * sizeof(int*));
A[0] = mem;
for(int i = 1; i < ROWS; i++) 
   A[i] = A[i-1] + COLS;
// use A[i][j]

Schließlich könnte man auf den zusätzlichen Zeiger ganz verzichten,

int **A = malloc(ROWS * sizeof(int*));
A[0] = malloc(ROWS * COLS * sizeof(int));
for(int i = 1; i < ROWS; i++) 
   A[i] = A[i-1] + COLS;
// use A[i][j]

aber es gibt ein wichtiges GOTCHA! Sie müssten darauf achten, zuerst A freizugeben[0] und dann A,

free(A[0]);
free(A);              // if this were done first, then A[0] would be invalidated

Die gleiche Idee kann auf 3- oder höherdimensionale Arrays erweitert werden, obwohl der Code unordentlich wird.

  • Code, der dies verwendet, muss immer noch die zusätzliche Indirektion des Arrays von Zeilenzeigern durchlaufen. Ich würde dies nicht empfehlen, es sei denn, Sie möchten Zeilen austauschen können, indem Sie Zeigerelemente neu anordnen.

    – Peter Cordes

    31. März 2021 um 14:43 Uhr

  • Übrigens übernehmen Compiler normalerweise die Optimierung der “Vermeidung der Multiplikation” für Sie tmp += COLS Anstatt von i*COLS. en.wikipedia.org/wiki/Strength_reduction. Deine Schreibweise als A[i-1]+COLS sollte auch ok optimieren, aber ich würde mich nicht darum kümmern.

    – Peter Cordes

    31. März 2021 um 14:44 Uhr

Sie können dynamisch zugewiesenen Speicher als Array von a behandeln irgendein Dimension, indem Sie in Schritten darauf zugreifen:

int * a = malloc(sizeof(int) * N1 * N2 * N3);  // think "int[N1][N2][N3]"

a[i * N2 * N3 + j * N3 + k] = 10;              // like "a[i, j, k]"

Der beste Weg ist, einen Zeiger auf ein Array zuzuweisen,

int (*a)[cols] = malloc(rows * sizeof *a);
if (a == NULL) {
    // alloc failure, handle or exit
}

for(int i = 0; i < rows; ++i) {
    for(int j = 0; j < cols; ++j) {
        a[i][j] = i+j;
    }
}

Wenn der Compiler keine Arrays mit variabler Länge unterstützt, funktioniert das nur, wenn cols ist ein konstanter Ausdruck (aber dann sollten Sie Ihren Compiler trotzdem aktualisieren).

  • Formulierung: das ist Zuordnung Platz für ein 2D-Array oder einfacher “ein echtes 2D-Array zuweisen”. Das Zeiger dazu (a) ist eine lokale Variable im automatischen Speicher, muss also nicht manuell zugewiesen werden.

    – Peter Cordes

    31. März 2021 um 14:38 Uhr

Benutzer-Avatar
136

Entschuldigen Sie meine fehlende Formatierung oder irgendwelche Fehler, aber das ist von einem Mobiltelefon.

Ich bin auch auf Fortschritte gestoßen, bei denen ich versucht habe, fwrite() für die Ausgabe mit der Variable int** als src-Adresse zu verwenden.

Eine Lösung bestand darin, zwei Aufrufe von malloc() zu verwenden:

#define HEIGHT 16
#define WIDTH 16

.
.
.
//allocate
int **data = malloc(HEIGHT * sizeof(int **));
int *realdata = malloc(HEIGHT * WIDTH * sizeof(int));

//manually index
for (int i = 0; i < HEIGHT; i++)
    data[i] = &realdata[i * WIDTH];

//populate
int idx = 0;
for (int i = 0; i < HEIGHT; i++)
    for (int j = 0; j < WIDTH; j++)
        data[i][j] = idx++;

//select
int idx = 0;
for (int i = 0; i < HEIGHT; i++)
{
    for (int j = 0; j < WIDTH; j++)
        printf("%i, ", data[i][j]);
    printf("/n");
}

//deallocate
.
.
.

  • Formulierung: das ist Zuordnung Platz für ein 2D-Array oder einfacher “ein echtes 2D-Array zuweisen”. Das Zeiger dazu (a) ist eine lokale Variable im automatischen Speicher, muss also nicht manuell zugewiesen werden.

    – Peter Cordes

    31. März 2021 um 14:38 Uhr

Sie können Ihr Array typdefinieren (für weniger Aufwand) und dann so etwas tun:

#include <stdlib.h>
#define N 10
typedef int A[N][N];
int main () {
  A a; // on the stack
  a[0][0]=1;
  A *b=(A*)malloc (sizeof(A)); // on the heap
  (*b)[0][0]=1;
}

1282440cookie-checkSo weisen Sie einem 2D-Array dynamisch einen zusammenhängenden Speicherblock zu

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy