Wie übergebe ich ein 2D-Array (Matrix) in einer Funktion in C?

Lesezeit: 7 Minuten

Benutzeravatar von Shweta
Schweta

Ich muss dies tun, um auch Operationen auf der Matrix fortzusetzen. Bedeutet das, dass es als Referenz übergeben werden muss?

Wird dies ausreichen?

void operate_on_matrix(char matrix[][20]);

Benutzeravatar von Bart van Ingen Schenau
Bart van Ingen-Schenau

C hat nicht wirklich mehrdimensionale Arrays, aber es gibt mehrere Möglichkeiten, sie zu simulieren. Die Art und Weise, wie solche Arrays an eine Funktion übergeben werden, hängt davon ab, wie die mehreren Dimensionen simuliert werden:

1) Verwenden Sie ein Array von Arrays. Dies kann nur verwendet werden, wenn Ihre Array-Grenzen zur Kompilierzeit vollständig bestimmt sind oder wenn Ihr Compiler dies unterstützt VLAs:

#define ROWS 4
#define COLS 5

void func(int array[ROWS][COLS])
{
  int i, j;

  for (i=0; i<ROWS; i++)
  {
    for (j=0; j<COLS; j++)
    {
      array[i][j] = i*j;
    }
  }
}

void func_vla(int rows, int cols, int array[rows][cols])
{
  int i, j;

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

int main()
{
  int x[ROWS][COLS];

  func(x);
  func_vla(ROWS, COLS, x);
}

2) Verwenden Sie ein (dynamisch zugewiesenes) Array von Zeigern auf (dynamisch zugewiesene) Arrays. Dies wird meistens verwendet, wenn die Array-Grenzen erst zur Laufzeit bekannt sind.

void func(int** array, int rows, int cols)
{
  int i, j;

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

int main()
{
  int rows, cols, i;
  int **x;

  /* obtain values for rows & cols */

  /* allocate the array */
  x = malloc(rows * sizeof *x);
  for (i=0; i<rows; i++)
  {
    x[i] = malloc(cols * sizeof *x[i]);
  }

  /* use the array */
  func(x, rows, cols);

  /* deallocate the array */
  for (i=0; i<rows; i++)
  {
    free(x[i]);
  }
  free(x);
}

3) Verwenden Sie ein eindimensionales Array und korrigieren Sie die Indizes. Dies kann sowohl mit statisch zugewiesenen (fester Größe) als auch mit dynamisch zugewiesenen Arrays verwendet werden:

void func(int* array, int rows, int cols)
{
  int i, j;

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

int main()
{
  int rows, cols;
  int *x;

  /* obtain values for rows & cols */

  /* allocate the array */
  x = malloc(rows * cols * sizeof *x);

  /* use the array */
  func(x, rows, cols);

  /* deallocate the array */
  free(x);
}

4) Verwenden Sie ein dynamisch zugewiesenes VLA. Ein Vorteil gegenüber Option 2 besteht darin, dass es eine einzige Speicherzuweisung gibt; Ein weiterer Grund ist, dass weniger Speicher benötigt wird, da das Array von Zeigern nicht erforderlich ist.

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

extern void func_vla(int rows, int cols, int array[rows][cols]);
extern void get_rows_cols(int *rows, int *cols);
extern void dump_array(const char *tag, int rows, int cols, int array[rows][cols]);

void func_vla(int rows, int cols, int array[rows][cols])
{
    for (int i = 0; i < rows; i++)
    {
        for (int j = 0; j < cols; j++)
        {
            array[i][j] = (i + 1) * (j + 1);
        }
    }
}

int main(void)
{
    int rows, cols;

    get_rows_cols(&rows, &cols);

    int (*array)[cols] = malloc(rows * cols * sizeof(array[0][0]));
    /* error check omitted */

    func_vla(rows, cols, array);
    dump_array("After initialization", rows, cols, array);

    free(array);
    return 0;
}

void dump_array(const char *tag, int rows, int cols, int array[rows][cols])
{
    printf("%s (%dx%d):\n", tag, rows, cols);
    for (int i = 0; i < rows; i++)
    {
        for (int j = 0; j < cols; j++)
            printf("%4d", array[i][j]);
        putchar('\n');
    }
}

void get_rows_cols(int *rows, int *cols)
{
    srand(time(0));           // Only acceptable because it is called once
    *rows = 5 + rand() % 10;
    *cols = 3 + rand() % 12;
}

(Sehen srand() — warum nur einmal nennen?.)

  • Bei der ersten oben erwähnten Methode wird der Code nicht kompiliert. „rows“ und „cols“ in den Zeilen 17 und 35 müssen sich in „ROWS“ bzw. „COLS“ ändern.

    – KZ-Codierung

    27. Mai 2015 um 15:35 Uhr

  • void func_vla(int array[rows][cols], int rows, int cols) sollte sein void func_vla(int rows, int cols, int array[rows][cols])

    – David Ranieri

    12. Oktober 2015 um 16:55 Uhr

  • @KZcoding: Die in den Zeilen 17 und 35 verwendete VLA-Notation ist korrekt, wenn der Compiler C99 unterstützt oder wenn er C11 unterstützt und nicht definiert __STDC_NO_VLA__. Wenn der Compiler keine VLAs unterstützt, dann kompiliert er natürlich nicht.

    – Jonathan Leffler

    26. Dezember 2018 um 16:45 Uhr

  • malloc gibt einen void-Zeiger zurück, sind Sie sicher, dass Sie ihn nicht nach Bedarf in int* oder int** umwandeln müssen? Lösung 2

    – CocoCrisp

    5. März 2019 um 19:22 Uhr

  • Casting ist eher eine C++-Konvention, verstanden! Danke @BartvanIngenSchenau

    – CocoCrisp

    5. März 2019 um 20:16 Uhr

Benutzeravatar von Minhas Kamal
Minhas Kamal

Der einfachste Weg, ein 2D-Array mit variabler Länge zu übergeben

Die sauberste Technik für C und C++ ist: Übergeben Sie ein 2D-Array wie ein 1D-Array und verwenden Sie es dann als 2D innerhalb der Funktion.

#include <stdio.h>

void func(int row, int col, int* matrix){
    int i, j;
    for(i=0; i<row; i++){
        for(j=0; j<col; j++){
            printf("%d ", *(matrix + i*col + j)); // or better: printf("%d ", *matrix++);
        }
        printf("\n");
    }
}

int main(){
    int matrix[2][3] = { {0, 1, 2}, {3, 4, 5} };
    func(2, 3, matrix[0]);

    return 0;
}

Unabhängig davon, wie viele Dimensionen ein Array hat, verwaltet C/C++ intern immer ein 1D-Array. Und so können wir jedes mehrdimensionale Array wie dieses übergeben.

  • Nur eine kleine Abfrage: Rufen wir die Funktion like auf func(2, 3, matrix)dann hätten wir es tun sollen void func(int row, int col, int** matrix)?

    – Kartik Chhajed

    7. September 2020 um 13:36 Uhr


  • @KartikChhajed Ihr Code erfordert eine implizite Konvertierung von int*[3] zu int**was für die meisten C/C++-Compiler möglicherweise nicht zulässig ist.

    – Minhas Kamal

    24. Oktober 2020 um 5:55 Uhr


  • @jwpol ist leider keine gute Idee: stackoverflow.com/q/25303647/1606345

    – David Ranieri

    24. Oktober 2020 um 7:55 Uhr

  • @David Ranieri Wenn Sie die Dimension des Arrays kennen, sehe ich keinen Grund, warum Sie ein bestimmtes Element nicht dereferenzieren sollten. Zum Beispielint matrix[2][2]belegt 4 “Zellen” des Speichers, also von *(p) zu *(p+3) (wobei p eine Adresse des ersten Elements ist) innerhalb der Dimension des zugewiesenen Speichers liegen. Dasselbe gilt für diese Antwort. In dem Thread, den Sie gepostet haben, geht es darum, ein Element nach dem letzten im Array zu dereferenzieren, was hier nicht der Fall ist. Die Antwort von @Minhas Kamal ist absolut sicher, vorausgesetzt, Sie überschreiten legitime Grenzen raw und col.

    – jwpol

    24. Oktober 2020 um 15:08 Uhr

  • Auswertung von *(matrix + i*col + j) zum i/j gleich 0/1 ruft UB auf. Der Typ des Objektzeigers von matrix ist int[2]. Daher *(matrix + 2) ist falsch

    – tstanisl

    10. Dezember 2021 um 11:51 Uhr

Ich weiß nicht, was Sie mit “Daten gehen nicht verloren” meinen. So übergeben Sie ein normales 2D-Array an eine Funktion:

void myfunc(int arr[M][N]) { // M is optional, but N is required
  ..
}

int main() {
  int somearr[M][N];
  ...
  myfunc(somearr);
  ...
}

  • Zufälliges Faktoid: Der Grund, warum N erforderlich ist, liegt darin, dass der Computer wissen muss, wie weit der Zeiger für jede “Zeile” inkrementiert werden muss. Eigentlich sind alle Dimensionen außer der ersten notwendig. C speichert Arrays als Speicherblöcke ohne Trennzeichen.

    – Christian Mann

    12. Oktober 2010 um 3:12 Uhr

  • Daten gehen nicht verloren Mittel ohne malloc. Danke für die Hilfe.

    – Schweta

    12. Oktober 2010 um 3:19 Uhr

  • @Christian Mann: Das ist eine gute Tatsache. Ich habe heute zufällig eine ausführliche Erklärung dazu geschrieben 🙂 stackoverflow.com/questions/3906777/…

    – Arun

    12. Oktober 2010 um 5:30 Uhr

  • Es scheint, dass heutzutage jeder Probleme mit mehrdimensionalen Arrays hat. 🙂 Ich habe auch eine ähnliche Erklärung in einer anderen Frage geschrieben: stackoverflow.com/questions/3911244/…

    – Casablanca

    12. Oktober 2010 um 5:34 Uhr

  • @ChristianMann Der Grund, warum die Array-Syntax überhaupt funktioniert, liegt vielmehr darin, dass der Compiler in diesem Fall die Array-Deklaration im Parameter an einen Zeiger auf das erste Element anpasst int (*)[N]. Und deshalb müssen auch alle Dimensionen bis auf die äußerste angegeben werden – das Array zerfällt nur einmal. Das hat absolut nichts mit dem zu tun, was “der Computer wissen muss” – Quatsch. Vergleichen Sie es mit dem 1D-Fall: void func (int [n])die angepasst wird void func (int*) und alle Größeninformationen gehen verloren – “der Computer” erfährt nichts davon und dem Compiler ist es völlig egal.

    – Ludin

    10. April 2017 um 14:46 Uhr

2D-Array:

int sum(int array[][COLS], int rows)
{

}

3D-Array:

int sum(int array[][B][C], int A)
{

}

4D-Array:

int sum(int array[][B][C][D], int A)
{

}

und nD-Array:

int sum(int ar[][B][C][D][E][F].....[N], int A)
{

}

1419530cookie-checkWie übergebe ich ein 2D-Array (Matrix) in einer Funktion in C?

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

Privacy policy