Übergeben eines 2D-Arrays an eine C++-Funktion

Lesezeit: 12 Minuten

Ubergeben eines 2D Arrays an eine C Funktion
Roger Darwin

Ich habe eine Funktion, die ich als Parameter nehmen möchte, ein 2D-Array variabler Größe.

Bisher habe ich das:

void myFunction(double** myArray){
     myArray[x][y] = 5;
     etc...
}

Und ich habe an anderer Stelle in meinem Code ein Array deklariert:

double anArray[10][10];

Allerdings anrufen myFunction(anArray) gibt mir einen Fehler.

Ich möchte das Array nicht kopieren, wenn ich es übergebe. Alle Änderungen, die in vorgenommen wurden myFunction sollte den Zustand ändern anArray. Wenn ich das richtig verstehe, möchte ich als Argument nur einen Zeiger auf ein 2D-Array übergeben. Die Funktion muss auch Arrays unterschiedlicher Größe akzeptieren. Also zum Beispiel [10][10] und [5][5]. Wie kann ich das machen?

  • kann Parameter 3 nicht von ‘double [10][10]’ verdoppeln **’

    – RogerDarwin

    7. Januar 2012 um 3:43 Uhr

  • Die akzeptierte Antwort zeigt nur 2 Techniken [its (2) and (3) are the same] aber es gibt 4 einzigartige Möglichkeiten, ein 2D-Array an eine Funktion zu übergeben.

    – legends2k

    24. März 2014 um 11:44 Uhr


  • Genau genommen, ja, sie sind keine 2D-Arrays, aber diese Konvention (obwohl sie zu UB führt), ein Array von Zeigern zu haben, die jeweils auf (ein 1D-) Array zeigen, scheint weit verbreitet zu sein 🙁 Ein abgeflachtes 1D-Array von mxn haben Länge, mit Hilfsfunktionen/Klasse, um ein 2D-Array zu emulieren, ist vielleicht besser.

    – legends2k

    12. Juli 2015 um 8:40 Uhr

  • AM EINFACHSTENfunc(int* mat, int r, int c){ for(int i=0; i<r; i++) for(int j=0; j<c; j++) printf("%d ", *(mat+i*c+j)); }. Nenn es wie- int mat[3][5]; func(mat[0], 3, 5);

    – Minhas Kamal

    9. Januar 2019 um 4:24 Uhr


1647287412 81 Ubergeben eines 2D Arrays an eine C Funktion
gut

Es gibt drei Möglichkeiten, ein 2D-Array an eine Funktion zu übergeben:

  1. Der Parameter ist ein 2D-Array

    int array[10][10];
    void passFunc(int a[][10])
    {
        // ...
    }
    passFunc(array);
    
  2. Der Parameter ist ein Array, das Zeiger enthält

    int *array[10];
    for(int i = 0; i < 10; i++)
        array[i] = new int[10];
    void passFunc(int *a[10]) //Array containing pointers
    {
        // ...
    }
    passFunc(array);
    
  3. Der Parameter ist ein Zeiger auf einen Zeiger

    int **array;
    array = new int *[10];
    for(int i = 0; i <10; i++)
        array[i] = new int[10];
    void passFunc(int **a)
    {
        // ...
    }
    passFunc(array);
    

  • @Overflowh Sie können die Elemente von erhalten array mit array[i][j] 🙂

    – shengy

    27. Mai 2013 um 3:15 Uhr

  • Für den 1. Fall kann der Parameter als deklariert werden int (*a)[10].

    – Zacharias

    13. Juni 2013 um 14:38 Uhr

  • Für den 2. Fall kann der Parameter als deklariert werden int **.

    – Zacharias

    14. Juni 2013 um 3:14 Uhr

  • ich würde eine 4 hinzufügen. mit a vector<vector<int>>

    – 463035818_ist_keine_Nummer

    5. Mai 2015 um 14:59 Uhr

  • Fall 2 und 3 sind keine 2D-Arrays, daher ist diese Antwort irreführend. Sieh dir das an.

    – Ludin

    16. Juni 2015 um 8:05 Uhr

Ubergeben eines 2D Arrays an eine C Funktion
Legenden2k

Feste Größe

1. Als Referenz übergeben

template <size_t rows, size_t cols>
void process_2d_array_template(int (&array)[rows][cols])
{
    std::cout << __func__ << std::endl;
    for (size_t i = 0; i < rows; ++i)
    {
        std::cout << i << ": ";
        for (size_t j = 0; j < cols; ++j)
            std::cout << array[i][j] << '\t';
        std::cout << std::endl;
    }
}

In C++ ist es wahrscheinlich am sichersten, das Array als Referenz zu übergeben, ohne die Dimensionsinformationen zu verlieren, da man sich keine Sorgen machen muss, dass der Aufrufer eine falsche Dimension übergibt (Compiler-Flags bei Nichtübereinstimmung). Dies ist jedoch mit dynamischen (Freestore) Arrays nicht möglich; Es funktioniert nur für automatische (normalerweise Stack-lebende) Arrays, dh die Dimensionalität sollte zur Kompilierzeit bekannt sein.

2. Zeiger übergeben

void process_2d_array_pointer(int (*array)[5][10])
{
    std::cout << __func__ << std::endl;
    for (size_t i = 0; i < 5; ++i)
    {
        std::cout << i << ": ";
        for (size_t j = 0; j < 10; ++j)
            std::cout << (*array)[i][j] << '\t';
        std::cout << std::endl;
    }    
}

Das C-Äquivalent der vorherigen Methode übergibt das Array per Zeiger. Dies sollte nicht mit dem Übergeben des verfallenen Zeigertyps des Arrays verwechselt werden (3), das ist die übliche, beliebte Methode, wenn auch weniger sicher als diese, aber flexibler. Wie (1), verwenden Sie diese Methode, wenn alle Dimensionen des Arrays fest und zur Kompilierzeit bekannt sind. Beachten Sie, dass beim Aufruf der Funktion die Adresse des Arrays übergeben werden sollte process_2d_array_pointer(&a) und nicht die Adresse des ersten Elements durch Zerfall process_2d_array_pointer(a).

Variable Größe

Diese werden von C geerbt, sind aber weniger sicher, der Compiler hat keine Möglichkeit zu überprüfen, ob der Aufrufer die erforderlichen Dimensionen übergibt. Die Funktion stützt sich nur darauf, was der Aufrufer als Dimension(en) übergibt. Diese sind flexibler als die oben genannten, da ihnen immer Arrays unterschiedlicher Länge übergeben werden können.

Es sei daran erinnert, dass es in C nicht möglich ist, ein Array direkt an eine Funktion zu übergeben [while in C++ they can be passed as a reference (1)]; (2) übergibt einen Zeiger auf das Array und nicht das Array selbst. Ein Array immer so zu übergeben, wie es ist, wird zu einer Pointer-Copy-Operation, die durch die Natur des Arrays erleichtert wird, in einen Pointer zu zerfallen.

3. Übergeben (Wert) einen Zeiger auf den verfallenen Typ

// int array[][10] is just fancy notation for the same thing
void process_2d_array(int (*array)[10], size_t rows)
{
    std::cout << __func__ << std::endl;
    for (size_t i = 0; i < rows; ++i)
    {
        std::cout << i << ": ";
        for (size_t j = 0; j < 10; ++j)
            std::cout << array[i][j] << '\t';
        std::cout << std::endl;
    }
}

Obwohl int array[][10] erlaubt ist, würde ich es nicht über die obige Syntax empfehlen, da die obige Syntax klar macht, dass der Bezeichner array ist ein einzelner Zeiger auf ein Array von 10 ganzen Zahlen, während diese Syntax sieht aus als wäre es ein 2D-Array, ist aber derselbe Zeiger auf ein Array mit 10 Ganzzahlen. Hier kennen wir die Anzahl der Elemente in einer einzelnen Zeile (dh die Spaltengröße, hier 10), aber die Anzahl der Zeilen ist unbekannt und muss daher als Argument übergeben werden. In diesem Fall gibt es eine gewisse Sicherheit, da der Compiler kennzeichnen kann, wenn ein Zeiger auf ein Array mit einer zweiten Dimension ungleich 10 übergeben wird. Die erste Dimension ist der variierende Teil und kann weggelassen werden. Siehe hier für die Begründung, warum nur die erste Dimension weggelassen werden darf.

4. Zeiger an einen Zeiger übergeben

// int *array[10] is just fancy notation for the same thing
void process_pointer_2_pointer(int **array, size_t rows, size_t cols)
{
    std::cout << __func__ << std::endl;
    for (size_t i = 0; i < rows; ++i)
    {
        std::cout << i << ": ";
        for (size_t j = 0; j < cols; ++j)
            std::cout << array[i][j] << '\t';
        std::cout << std::endl;
    }
}

Auch hier gibt es eine alternative Syntax von int *array[10] was dasselbe ist wie int **array. In dieser Syntax ist die [10] wird ignoriert, da es in einen Zeiger zerfällt, wodurch es wird int **array. Vielleicht ist es nur ein Hinweis für den Aufrufer, dass das übergebene Array mindestens 10 Spalten haben sollte, selbst dann ist eine Zeilenanzahl erforderlich. In jedem Fall markiert der Compiler keine Längen-/Größenverletzungen (er prüft nur, ob der übergebene Typ ein Zeiger auf einen Zeiger ist), daher ist es hier sinnvoll, sowohl die Zeilen- als auch die Spaltenanzahl als Parameter zu erfordern.

Notiz: (4) ist die am wenigsten sichere Option da es kaum typprüfung hat und am unpraktischsten ist. Man kann dieser Funktion kein 2D-Array rechtmäßig übergeben; C-FAQ verurteilt die übliche Problemumgehung zu tun int x[5][10]; process_pointer_2_pointer((int**)&x[0][0], 5, 10); da dies aufgrund von Array-Flattening möglicherweise zu undefiniertem Verhalten führen kann. Die richtige Art, ein Array in dieser Methode zu übergeben, bringt uns zum unbequemen Teil, dh wir brauchen ein zusätzliches (Ersatz-) Array von Zeigern, wobei jedes seiner Elemente auf die entsprechende Zeile des tatsächlichen, zu übergebenden Arrays zeigt; dieses Surrogat wird dann an die Funktion übergeben (siehe unten); All dies, um die gleiche Arbeit wie die oben genannten Methoden zu erledigen, die sicherer, sauberer und vielleicht schneller sind.

Hier ist ein Treiberprogramm zum Testen der oben genannten Funktionen:

#include <iostream>

// copy above functions here

int main()
{
    int a[5][10] = { { } };
    process_2d_array_template(a);
    process_2d_array_pointer(&a);    // <-- notice the unusual usage of addressof (&) operator on an array
    process_2d_array(a, 5);
    // works since a's first dimension decays into a pointer thereby becoming int (*)[10]

    int *b[5];  // surrogate
    for (size_t i = 0; i < 5; ++i)
    {
        b[i] = a[i];
    }
    // another popular way to define b: here the 2D arrays dims may be non-const, runtime var
    // int **b = new int*[5];
    // for (size_t i = 0; i < 5; ++i) b[i] = new int[10];
    process_pointer_2_pointer(b, 5, 10);
    // process_2d_array(b, 5);
    // doesn't work since b's first dimension decays into a pointer thereby becoming int**
}

  • Was ist mit der Übergabe dynamisch zugewiesener Arrays an Funktionen in C++? Im C11-Standard kann dies für statisch und dynamisch zugewiesene Arrays wie fn(int col,int row, int array[col][row]): stackoverflow.com/questions/16004668/… Ich habe die Frage zu diesem Problem gestellt: stackoverflow.com/questions/27457076/…

    – 42n4

    13. Dezember 2014 um 9:16 Uhr


  • @42n4 Fall 4 deckt (auch für C++) das ab. Bei dynamisch zugewiesenen Arrays würde sich nur die Zeile innerhalb der Schleife von ändern b[i] = a[i]; sagen, b[i] = new int[10];. Kann man auch machen b dynamisch zugeteilt int **b = int *[5]; und es wird immer noch so funktionieren, wie es ist.

    – legends2k

    15. Dezember 2014 um 6:42 Uhr

  • Wie funktioniert die Adressierung array[i][j] Arbeite in die Funktion ein 4)? Weil es ptr zu ptr erhalten hat und den Wert der letzten Dimension nicht kennt, was notwendig ist, um eine Verschiebung für eine korrekte Adressierung durchzuführen?

    – Benutzer1234567

    16. Dezember 2014 um 16:27 Uhr

  • array[i][j] ist nur Zeigerarithmetik, dh auf den Wert des Zeigers arraywürde es hinzufügen i und das Ergebnis dereferenzieren als int*zu dem es hinzufügen würde j und dereferenzieren Sie diesen Ort, indem Sie an lesen int. Also, nein, es muss dafür keine Dimension kennen. Aber das ist der springende Punkt! Der Compiler nimmt vertrauensvoll das Wort des Programmierers, und wenn der Programmierer falsch lag, folgt undefiniertes Verhalten. Aus diesem Grund hatte ich erwähnt, dass Fall 4 die am wenigsten sichere Option ist.

    – legends2k

    17. Dezember 2014 um 3:04 Uhr


  • In solchen Fällen kann Ihnen eine Struktur gute Dienste leisten.

    – Xofo

    16. November 2018 um 18:17 Uhr

1647287412 902 Ubergeben eines 2D Arrays an eine C Funktion
Zrax

Als Modifikation des ersten Vorschlags von Shengy können Sie Vorlagen verwenden, um die Funktion dazu zu bringen, eine mehrdimensionale Array-Variable zu akzeptieren (anstatt ein Array von Zeigern zu speichern, die verwaltet und gelöscht werden müssen):

template <size_t size_x, size_t size_y>
void func(double (&arr)[size_x][size_y])
{
    printf("%p\n", &arr);
}

int main()
{
    double a1[10][10];
    double a2[5][5];

    printf("%p\n%p\n\n", &a1, &a2);
    func(a1);
    func(a2);

    return 0;
}

Die print-Anweisungen zeigen, dass die Arrays als Referenz übergeben werden (durch Anzeigen der Variablenadressen).

  • Du solltest benutzen %p zum Drucken eines Zeigers, und selbst dann müssen Sie ihn umwandeln void *anders printf() ruft undefiniertes Verhalten auf. Außerdem sollten Sie nicht die Adresse von (&)-Operator beim Aufruf der Funktionen, da die Funktionen ein Argument vom Typ erwarten double (*)[size_y]während Sie sie derzeit bestehen double (*)[10][10] und double (*)[5][5].

    Benutzer529758

    20. Oktober 2013 um 8:26 Uhr

  • Wenn Sie Templates verwenden, ist es angemessener und besser, beide Dimensionen als Template-Argumente anzugeben, da ein Low-Level-Zeigerzugriff vollständig vermieden werden kann.

    – legends2k

    24. März 2014 um 12:43 Uhr


  • Dies funktioniert nur, wenn die Größe des Arrays zur Kompilierzeit bekannt ist.

    – John Doe

    27. Dezember 2017 um 16:51 Uhr

  • @Georg Code oben als Antwort ist genau das, was ich vorgeschlagen hatte. Es funktioniert in GCC 6.3 – Online-Demo. Haben Sie vergessen, den Parameter zu einer Referenz zu machen?

    – legends2k

    29. November 2018 um 5:39 Uhr

Überrascht, dass dies bisher noch niemand erwähnt hat, aber Sie können einfach alles als Vorlage verwenden, das 2D unterstützt [][] Semantik.

template <typename TwoD>
void myFunction(TwoD& myArray){
     myArray[x][y] = 5;
     etc...
}

// call with
double anArray[10][10];
myFunction(anArray);

Es funktioniert mit jeder “Array-ähnlichen” 2D-Datenstruktur, wie z std::vector<std::vector<T>>oder ein benutzerdefinierter Typ, um die Wiederverwendung von Code zu maximieren.

Sie können eine Funktionsvorlage wie folgt erstellen:

template<int R, int C>
void myFunction(double (&myArray)[R][C])
{
    myArray[x][y] = 5;
    etc...
}

Dann haben Sie beide Dimensionsgrößen über R und C. Für jede Arraygröße wird eine andere Funktion erstellt. Wenn Ihre Funktion also groß ist und Sie sie mit einer Vielzahl unterschiedlicher Arraygrößen aufrufen, kann dies kostspielig sein. Sie könnten es jedoch als Wrapper für eine Funktion wie diese verwenden:

void myFunction(double * arr, int R, int C)
{
    arr[x * C + y] = 5;
    etc...
}

Es behandelt das Array als eindimensional und verwendet Arithmetik, um die Offsets der Indizes herauszufinden. In diesem Fall würden Sie die Vorlage wie folgt definieren:

template<int C, int R>
void myFunction(double (&myArray)[R][C])
{
    myFunction(*myArray, R, C);
}

  • size_t ist der bessere Typ für Array-Indizes als int.

    – Andreas Tomazos

    10. Juli 2013 um 11:42 Uhr

1647287413 741 Ubergeben eines 2D Arrays an eine C Funktion
Sergej Kalinitschenko

anArray[10][10] ist kein Zeiger auf einen Zeiger, sondern ein zusammenhängender Speicherblock, der zum Speichern von 100 Werten vom Typ Double geeignet ist, die der Compiler zu adressieren weiß, weil Sie die Dimensionen angegeben haben. Sie müssen es als Array an eine Funktion übergeben. Sie können die Größe der Anfangsdimension wie folgt weglassen:

void f(double p[][10]) {
}

Dadurch können Sie jedoch keine Arrays mit einer anderen letzten Dimension als zehn übergeben.

Die beste Lösung in C++ ist die Verwendung std::vector<std::vector<double> >: Es ist fast genauso effizient und deutlich komfortabler.

  • size_t ist der bessere Typ für Array-Indizes als int.

    – Andreas Tomazos

    10. Juli 2013 um 11:42 Uhr

1647287413 253 Ubergeben eines 2D Arrays an eine C Funktion
Mahesh

Ein eindimensionales Array zerfällt zu einem Zeigerzeiger, der auf das erste Element im Array zeigt. Während ein 2D-Array zu einem Zeiger zerfällt, der auf die erste Zeile zeigt. Der Funktionsprototyp sollte also sein –

void myFunction(double (*myArray) [10]);

ich würde bevorzugen std::vector über rohe Arrays.

1002960cookie-checkÜbergeben eines 2D-Arrays an eine C++-Funktion

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

Privacy policy