Array initialisieren



  • Btw: Mach graph1 global, das ist am wenigsten Stress.



  • Sehr gut! 😉 Lange schon nicht mehr so gelacht! 😃 Den kannte ich noch gar nicht 🙂



  • ich hab graph1 momentan in der aufrufende main Funktion deklariert. Die Methoden (FUnktionen) kommen bei mir hier ja aus einer Klasse!



  • Brignts was wenn ich die Deklaration von graph1 in den Konstruktor schiebe?



  • vip@r schrieb:

    Eine Initialisierung der Form

    graph1[9][9]
    

    funktioniert aber so. Warum geht das so mit Pointern nicht?

    ** bedeutet nicht 2d-Array. Viele Leute denken fälschlicherweise, hinter ** steckt immer ein **, das ist Unsinn. ** ==> Zeiger auf Zeiger, nicht mehr und nicht weniger.

    vip@r schrieb:

    Dann hab ich noch eine Funktion

    void bfs(**graph1)
    

    deklariert, die das int-Array erhalten soll. Wie bewerkstellige ich das am Besten?

    Nutze einfach array-to-pointer-decay: int-Array ==> int*

    Wie du siehst, ist das gar nicht so einfach und stark fehleranfällig. Wieso machst du dir das Leben dann nicht mit std::array, std::tr1::array oder std::vector einfacher?



  • out schrieb:

    vip@r schrieb:

    Eine Initialisierung der Form

    graph1[9][9]
    

    funktioniert aber so. Warum geht das so mit Pointern nicht?

    ** bedeutet nicht 2d-Array. Viele Leute denken fälschlicherweise, hinter ** steckt immer ein **, das ist Unsinn.

    ...steckt immer ein 2d-Array...
    😃



  • vip@r schrieb:

    Die Methoden (FUnktionen) kommen bei mir hier ja aus einer Klasse!

    Klasse! Ja, dann mach doch eine Klasse draus.

    struct Graph {
      adj[9][9];
    };
    
    void bfs(Graph& graph);
    
    Graph graph1 = {{{0,1,1,0,0,0,1,0,0},
                            {0,0,0,1,0,0,0,0,0},
                            {1,0,0,1,1,0,0,0,0},
                            {0,0,0,0,0,0,1,0,0},
                            {1,0,0,0,0,1,0,0,1},
                            {0,0,1,1,1,0,0,1,0},
                            {0,0,0,0,0,0,0,1,0},
                            {0,0,0,1,0,0,0,0,1},
                            {0,0,0,0,0,1,0,0,0}}};
    
    bfs(graph1);
    


  • mit vorgefertigten Bibliotheken möchte ich an dieser STelle nicht arbeiten.

    Ich hab mich nun dafür entschieden, dass ich mit der Initialisierung graph1[9][9] arbeite. Jetzt hab ich aber ein weiteres Problem: Ich hab mich nun auch dafür entschieden, dass array, also graph1 im Konstruktor deklarieren zu lassen.

    Das sieht nun so aus:

    class graphAlgo
    {
    private:
    	int graph1[9][9];
    	int graph2[9][9];
    
    	void bfs(int **graph1);	//Breitensuche
    	void dfs(int **graph2);	//Tiefensuche
    
    public:
    	graphAlgo();
    	~graphAlgo();
    
    	void breitensuche();	//Breitensuche
    	void tiefensuche();	//Tiefensuche
    
    };
    
    //Konstruktor
    graphAlgo::graphAlgo()
    {
    	//deklaration des gerichteten und ungewichteten Graphen
    		graph1[9][9] = {{0,1,1,0,0,0,1,0,0},
    						{0,0,0,1,0,0,0,0,0},
    						{1,0,0,1,1,0,0,0,0},
    						{0,0,0,0,0,0,1,0,0},
    						{1,0,0,0,0,1,0,0,1},
    						{0,0,1,1,1,0,0,1,0},
    						{0,0,0,0,0,0,0,1,0},
    						{0,0,0,1,0,0,0,0,1},
    						{0,0,0,0,0,1,0,0,0}};
    
    	//deklaration des gerichteten und gewichteten Graphen
    	graph2[9][9] = {{0,1,2,0,0,0,5,0,0},
    						{0,0,0,6,0,0,0,0,0},
    						{2,0,0,5,4,0,0,0,0},
    						{0,0,0,0,0,0,2,0,0},
    						{3,0,0,0,0,2,0,0,4},
    						{0,0,1,7,2,0,0,2,0},
    						{0,0,0,0,0,0,0,1,0},
    						{0,0,0,3,0,0,0,0,5},
    						{0,0,0,0,0,3,0,0,0}};
    }
    

    Ich kann aber hier jetzt nicht auf die private Variablen graph1 und graph2 zugreifen. Muss ich diese dann publich setzen? Was muss ich machen, damit ich diese Variablen dennoch unter private deklarieren kann?



  • Zur Erklärung, warum das mit int **graph nicht so funktioniert, wie du es dir denkst:

    Typsystem 102: Arrays (und der Zusammenhang mit Zeigern)

    Ein Array ist ein Aggregattyp, der aus einer festen Anzahl von Objekten eines anderen Typs besteht. Diese Teilobjekte liegen im Speicher direkt hintereinander, ihre Gesamtheit ist das Array, und die Einzelobjekte sind über einen Index ansprechbar:

    int arr[4] = { 3, 1, 4, 1 };
    
    führt zu:
    
    | <------- arr--- ----> |
    +-----+-----+-----+-----+
    |  3  |  1  |  4  |  1  |
    +-----+-----+-----+-----+
       ^     ^     ^     ^
       |     |     |     |
     arr[0]  |     |     |
           arr[1]  |     |
                 arr[2]  |
                       arr[3]
    

    Zwei- und mehrdimensionale Arrays sind Arrays von Arrays, also:

    int arr[3][2] = { { 3, 1 }, { 4, 1 }, { 5, 9 } };
    
    führt zu:
    
      | <------------- arr -------------> |
      |   arr[0]  |   arr[1]  |   arr[2]  |
      +-----+-----+-----+-----+-----+-----+
      |  3  |  1  |  4  |  1  |  5  |  9  |
      +-----+-----+-----+-----+-----+-----+
         ^     ^     ^     ^     ^     ^
         |     |     |     |     |     |
    arr[0][0]| |     |     |     |     |
          arr[0][1]  |     |     |     |
                arr[1][0]  |     |     |
                      arr[1][1]  |     |
                            arr[2][0]  |
                                  arr[2][1]
    

    In diesem Fall sind arr[0], arr[1] und arr[2] jeweils vom Typ int[2]. So ist

    // param ist eine Referenz auf ein int-Array der Länge 2
    void foo(int (&param)[2]) {
    }
    
    int main() {
      int arr[3][2] = { { 3, 1 }, { 4, 1 }, { 5, 9 } };
      foo(arr[0]);
    }
    

    völlig in Ordnung. std::end(arr[0]) etc. werden ebenfalls funktionieren.

    Als Besonderheit zerfallen Arrays in der Verwendung in einen Zeiger auf den Typ, den es beinhaltet. So kann ich

    int arr[4] = { 3, 1, 4, 1 };
    int *ptr = arr;
    
    assert(*(ptr + 2) == 4);
    

    schreiben, oder

    int arr[3][2] = { { 3, 1 }, { 4, 1 }, { 5, 9 } };
    int (*ptr)[2] = arr;
    
    assert((*(ptr + 2))[0] == 5 && (*(ptr + 2))[1] == 9);
    

    Dieser Zerfall geschieht übrigens auch bei

    arr[2]
    

    , welches als

    (*(arr + 2))
    

    ausgewertet wird.

    Gleichwohl ist ein Array etwas anderes als ein Zeiger, und ein Array von Arrays etwas anderes als ein Array von Zeigern. In C (und schlechtem C++) sieht man manchmal Code der Art

    int **arr;
    
    arr = malloc(sizeof(int*) * x); // bzw. das selbe mit new[]
    for(int i = 0; i < x; ++x) {
      arr[i] = malloc(sizeof(int) * y);
    }
    
    arr[0][1] = foo();
    
    // Später Aufräumen nicht vergessen, und Exceptionsicherheit...also besser
    // mit std::vector<std::vector<foo> >, wenn es denn unbedingt sein muss.
    

    Dies sieht im Speicher dann etwa so aus:

    arr           [0] [1] [2] [3]
    +---+         +---+---+---+---+
    |   |-------->|   |   |   |   |
    +---+         +---+---+---+---+
                    |   |   |   |    +---+---+---+
                    |   |   |   +--->| 3 | 1 | 4 |
                    |   |   |        +---+---+---+
                    |   |   |
                    |   |   |        +---+---+---+
                    |   |   +------->| 1 | 5 | 9 |
                    |   |            +---+---+---+
                    |   |
                    |   |            +---+---+---+
                    |   +----------->| 2 | 6 | 5 |
                    |                +---+---+---+
                    |
                    |                +---+---+---+
                    +--------------->| 3 | 5 | 8 |
                                     +---+---+---+
    

    Hierbei ist arr vom Typ int**, und arr[0], arr[1] etc. sind int* (nicht int[3]!). Es handelt sich um ein gänzlich anderes (und komplexeres) Biest als ein einfaches zweidimensionales Array, und deshalb kann man einen Zeiger auf Zeiger nicht initialisieren wie ein mehrdimensionales Array.



  • vip@r schrieb:

    mit vorgefertigten Bibliotheken möchte ich an dieser STelle nicht arbeiten.

    Tust du ja auch nicht. Das ist Teil der c++ Standardbibliothek. Was nutzt du denn zur Bildschirmausgabe? Garantiert std::cout. Und wenn du das nicht nutzt, wirst du die WinAPI nutzen müssen oder etwas vergleichbares. Du kommst um Bibliotheken nicht herum; erfinde das Rad nicht unnötig neu.
    Und std::vector ist was tolles. Dynamisch wachsende Arrays, die soviel Speicher haben, wie du brauchst. Kein Gefriemel (?) mehr mit new[] oder new.

    Das sieht nun so aus:

    ...
    

    Ich kann aber hier jetzt nicht auf die private Variablen graph1 und graph2 zugreifen. Muss ich diese dann publich setzen? Was muss ich machen, damit ich diese Variablen dennoch unter private deklarieren kann?

    Doch kannst du.
    In allen Memberfunktionen kannst du auf private Variablen zugreifen.
    Und deine Aufteilung bfs(int**) und breitensuche ist auch relativ sinnfrei. Nutze gleich breitensuche und arbeite dort direkt mit dem Member.


Anmelden zum Antworten