Tausch zweier zweidimensionaler Int-Felder durch Zeiger klappt nicht



  • Hallo Forum

    **
    Problembeschreibung:
    Ich versuche die Inhalte zweier 2dim-Int-Felder, die dyn. besorgt werden, zu tauschen. Dies funktioniert jedoch nicht.
    Der Tausch geschieht in der Funktion next_generation().
    Es gibt 4 Ausgaben der Felder: Vor und nach dem next_generation()-Aufruf und
    innerhalb der Funktion nochmal vor u. nach dem Zeigertausch.
    "Innere" Ausgaben zeigen, dass Felder getauscht sind. Verl├Ąsst er die Funktionen ist dies nicht mehr der Fall... warum... ­čśĽ Bitte um Hilfe..
    Kompletter Code und Konsolenausgabe ist unten angeh├Ąngt. Probiert ihn ruhig selbst aus falls n├Âtig.
    **

    Programmbeschreibung:
    +Zwei 2dim-Int-Felder werden durch new_int_matrix() dynamisch reserviert und mit 0 initialisiert.
    +Feld1 wird mit ein paar werten belegt.
    +Beide Felder werden vor next_generation()-Aufruf ausgegeben.
    +next_generation() wird Aufgerufen. Darin passiert folgendes:
    ++Feld2 wird mit ein paar werten belegt.
    ++Beide Felder werden ausgegeben.
    ++Es erfolgt ein Zeigertausch mit Hilfe eines Hilfszeigers. (HIER FEHLER?)
    ++Beide Felder werden ausgegeben.
    +Beide Felder werden nach next_generation()-Aufruf ausgegeben.
    +Die beiden 2dim-Int-Felder werden durch delete_int_matrix() wieder freigegeben.

    HAUPTPROGRAMM:

    #include <iostream>     // Fuer Ausgaben
    #include <cstdlib>      // Fuer rand() und system()
    #include <ctime>        // Fuer srand
    #include <cstdio>
    
    using namespace std;
    
    typedef unsigned int uint;
    
    // HAUPTPROGRAMM
    int main()
    {
        int rows=10, columns=10;    // Zeilen u. Spalten der Matrix
    
        // Zwei Felder anlegen
        int** feld1=0;
        int** feld2=0;
        feld1 = new_int_matrix ( rows, columns );
        feld2 = new_int_matrix ( rows, columns );
    
        // FELD1-BELEGUNG
        feld1[5][5]=1;
        feld1[5][6]=1;
        feld1[6][5]=1;
        feld1[6][6]=1;
    
        system("cls");  // Konsole saubern
    
        // FELDERAUSGABE - Vor Funktionsaufruf next_generation()
        cout << "Felder vor Funktionsaufruf:" << endl;
        for(int i=0;i<rows;i+=1) {
            for(int j=0;j<columns;j+=1) cout << " " << feld1[i][j];
            cout << "  |  ";
            for(int j=0;j<columns;j+=1) cout << " " << feld2[i][j];
            cout << endl;
        }
        cout << endl;
    
        next_generation ( feld1, feld2, columns, rows );
    
        // FELDERAUSGABE - Nach Funktionsaufruf next_generation()
        cout << "Felder nach Funktionsaufruf:" << endl;
        for(int i=0;i<rows;i+=1) {
            for(int j=0;j<columns;j+=1) cout << " " << feld1[i][j];
            cout << "  |  ";
            for(int j=0;j<columns;j+=1) cout << " " << feld2[i][j];
            cout << endl;
        }
        cout << endl;
    
        // Beide Felder freigeben
        delete_int_matrix ( feld1 );
        delete_int_matrix ( feld2 );
        return 0;
    }
    

    FUNKTIONEN:
    Benutzte Funktionen:

    // === FUNCTION ======================================================================
    // Name:        new_int_matrix
    // Description: Reserviert dynamisch eine rows*columns-grosse intMatrix.
    // Parameter:   rows ist die Zeilenanzahl der intMatrix
    //              columns ist die Spaltenanzahl der intMatrix
    // Rueckgabe:   Zeiger auf die intMatrix
    // =====================================================================================
    int** new_int_matrix ( int rows, int columns )
    {
        int i;
        int **m;
        m = new int* [rows]; // Reserviert Zeigerfeld
        *m = new int [rows*columns](); // Reserviert u. Initialisiert Datenfeld
        for ( i=1; i<rows; i+=1 ) // Setzt Zeiger des Zeigerfeldes
        m[i] = m[i-1] + columns;
        return m;
    }
    
    // === FUNCTION ======================================================================
    // Name:        delete_int_matrix
    // Description: Gibt den Speicher fuer die int-Matrix hinter m frei.
    // Parameter:   m ist der Zeiger auf intMatrix
    // Rueckgabe:
    // =====================================================================================
    void delete_int_matrix ( int **m )
    {
        delete[] *m; // delete data array
        delete[] m; // delete pointer array
    }
    
    // === FUNCTION ======================================================================
    // Name:        next_generation
    // Description: Erzeugt Inhalte f├╝r zweites Feld und tauscht diese mit dem ersten Feld
    // Parameter:   hoehe ist die Zeilenanzahl der intMatrix
    //              breite ist die Spaltenanzahl der intMatrix
    // Rueckgabe:   0
    // =====================================================================================
    uint next_generation ( int **feld1, int **feld2, uint breite, uint hoehe ){
    
        // FELD2-BELEGUNG
        feld2[1][1]=2;
        feld2[1][2]=2;
        feld2[2][1]=2;
        feld2[2][2]=2;
    
        // AUSGABE - Vor Zeigertausch
        cout << "(Innerhalb Funktion)Felder vor Zeigertausch:" << endl;
        for(uint i=0;i<hoehe;i+=1) {
            for(uint j=0;j<breite;j+=1) cout << " " << feld1[i][j];
            cout << "  |  ";
            for(uint j=0;j<breite;j+=1) cout << " " << feld2[i][j];
            cout << endl;
        }
        cout << endl;
    
        // Zeigertausch
        int** p_temp=0;
        p_temp=feld1;
        for(uint i=0;i<hoehe+1;i+=1) p_temp[i]=feld1[i];
        feld1=feld2;
        for(uint i=0;i<hoehe+1;i+=1) feld1[i]=feld2[i];
        feld2=p_temp;
        for(uint i=0;i<hoehe+1;i+=1) feld2[i]=p_temp[i];
    
        // AUSGABE - Nach Zeigertausch
        cout << "(Innerhalb Funktion)Felder nach Zeigertausch:" << endl;
        for(uint i=0;i<hoehe;i+=1) {
            for(uint j=0;j<breite;j+=1) cout << " " << feld1[i][j];
            cout << "  |  ";
            for(uint j=0;j<breite;j+=1) cout << " " << feld2[i][j];
            cout << endl;
        }
        cout << endl;
    
        return 0;
    }
    

    KONSOLENAUSGABE:

    Felder vor Funktionsaufruf:
     0 0 0 0 0 0 0 0 0 0  |   0 0 0 0 0 0 0 0 0 0
     0 0 0 0 0 0 0 0 0 0  |   0 0 0 0 0 0 0 0 0 0
     0 0 0 0 0 0 0 0 0 0  |   0 0 0 0 0 0 0 0 0 0
     0 0 0 0 0 0 0 0 0 0  |   0 0 0 0 0 0 0 0 0 0
     0 0 0 0 0 0 0 0 0 0  |   0 0 0 0 0 0 0 0 0 0
     0 0 0 0 0 1 1 0 0 0  |   0 0 0 0 0 0 0 0 0 0
     0 0 0 0 0 1 1 0 0 0  |   0 0 0 0 0 0 0 0 0 0
     0 0 0 0 0 0 0 0 0 0  |   0 0 0 0 0 0 0 0 0 0
     0 0 0 0 0 0 0 0 0 0  |   0 0 0 0 0 0 0 0 0 0
     0 0 0 0 0 0 0 0 0 0  |   0 0 0 0 0 0 0 0 0 0
    
    (Innerhalb Funktion)Felder vor Zeigertausch:
     0 0 0 0 0 0 0 0 0 0  |   0 0 0 0 0 0 0 0 0 0
     0 0 0 0 0 0 0 0 0 0  |   0 2 2 0 0 0 0 0 0 0
     0 0 0 0 0 0 0 0 0 0  |   0 2 2 0 0 0 0 0 0 0
     0 0 0 0 0 0 0 0 0 0  |   0 0 0 0 0 0 0 0 0 0
     0 0 0 0 0 0 0 0 0 0  |   0 0 0 0 0 0 0 0 0 0
     0 0 0 0 0 1 1 0 0 0  |   0 0 0 0 0 0 0 0 0 0
     0 0 0 0 0 1 1 0 0 0  |   0 0 0 0 0 0 0 0 0 0
     0 0 0 0 0 0 0 0 0 0  |   0 0 0 0 0 0 0 0 0 0
     0 0 0 0 0 0 0 0 0 0  |   0 0 0 0 0 0 0 0 0 0
     0 0 0 0 0 0 0 0 0 0  |   0 0 0 0 0 0 0 0 0 0
    
    (Innerhalb Funktion)Felder nach Zeigertausch:
     0 0 0 0 0 0 0 0 0 0  |   0 0 0 0 0 0 0 0 0 0
     0 2 2 0 0 0 0 0 0 0  |   0 0 0 0 0 0 0 0 0 0
     0 2 2 0 0 0 0 0 0 0  |   0 0 0 0 0 0 0 0 0 0
     0 0 0 0 0 0 0 0 0 0  |   0 0 0 0 0 0 0 0 0 0
     0 0 0 0 0 0 0 0 0 0  |   0 0 0 0 0 0 0 0 0 0
     0 0 0 0 0 0 0 0 0 0  |   0 0 0 0 0 1 1 0 0 0
     0 0 0 0 0 0 0 0 0 0  |   0 0 0 0 0 1 1 0 0 0
     0 0 0 0 0 0 0 0 0 0  |   0 0 0 0 0 0 0 0 0 0
     0 0 0 0 0 0 0 0 0 0  |   0 0 0 0 0 0 0 0 0 0
     0 0 0 0 0 0 0 0 0 0  |   0 0 0 0 0 0 0 0 0 0
    
    Felder nach Funktionsaufruf:
     0 0 0 0 0 0 0 0 0 0  |   0 0 0 0 0 0 0 0 0 0
     0 0 0 0 0 0 0 0 0 0  |   0 2 2 0 0 0 0 0 0 0
     0 0 0 0 0 0 0 0 0 0  |   0 2 2 0 0 0 0 0 0 0
     0 0 0 0 0 0 0 0 0 0  |   0 0 0 0 0 0 0 0 0 0
     0 0 0 0 0 0 0 0 0 0  |   0 0 0 0 0 0 0 0 0 0
     0 0 0 0 0 1 1 0 0 0  |   0 0 0 0 0 0 0 0 0 0
     0 0 0 0 0 1 1 0 0 0  |   0 0 0 0 0 0 0 0 0 0
     0 0 0 0 0 0 0 0 0 0  |   0 0 0 0 0 0 0 0 0 0
     0 0 0 0 0 0 0 0 0 0  |   0 0 0 0 0 0 0 0 0 0
     0 0 0 0 0 0 0 0 0 0  |   0 0 0 0 0 0 0 0 0 0
    
    Process returned 0 (0x0)   execution time : 0.106 s
    Press any key to continue.
    


  • Spricht was dagegen, C++ zu benutzen.



  • Hallo,

    ich habe nicht alles nachvollzogen aber der Tausch in next_generation funktioniert so nicht:

    uint next_generation ( int **feld1, int **feld2, uint breite, uint hoehe )
    {
     //...
     p_temp=feld1;
     //...
     feld1=feld2;
     //...
     feld2=p_temp;
    }
    

    Du ├╝bergibst feld1 und feld2 per Value. D.h. die Doppelzeiger feld1 und feld2 in "next_generation" sind ein Kopie von den Zeigern feld1 und feld2 in Deiner "main"-Funktion (nur die Zeiger sind eine Kopie, nicht das worauf sie zeigen.) Wegen der Kopie ist dieser Tausch nur innerhalb der Funktion next_generation sichtbar. Du musst also das, worauf feld1 und feld2 zeigen vertauschen, und das versuchst Du auch:

    uint next_generation ( int **feld1, int **feld2, uint breite, uint hoehe )
    {
     //...
    for(uint i=0;i<hoehe+1;i+=1) [i]=feld1[i];
     //..
    for(uint i=0;i<hoehe+1;i+=1) feld1[i]=feld2[i];
     //..
    for(uint i=0;i<hoehe+1;i+=1) feld2[i]=p_temp[i];
    }
    

    Das sieht zwar umst├Ąndlich aus, k├Ânnte aber funktionieren, wenn p_temp auf freien g├╝ltigen Speicher zeigt. In der Kombination, wie du es geschrieben hast, hat der 2. Teil keine Wirkung denn:

    p_temp=feld1;
    for(uint i=0;i<hoehe+1;i+=1) p_temp[i]=feld1[i];
    

    p_temp ist in der Schleife schon gleich feld1. Also ist temp[i] sowieso schon gleich feld[i]. Genau so ist es auch bei den n├Ąchsten beiden Tauschversuchen.

    EDIT: "Wegen der Kopie ist dieser Tausch nur innerhalb der Funktion next_generation sichtbar." hinzugef├╝gt.



  • Danke f├╝r den Hinweis mit den Zeiger-Kopien DJohn.
    Ich habe mir die beiden Zeiger, die ich ├╝bergebe, vorher ausgeben lassen:

    &feld1: 0x28fedc
    &feld2: 0x28fed8
    feld1:  0x3f0ff0
    feld2:  0x3f1020
    

    Und habe mir diese nochmal innerhalb der Funktion ausgeben lassen:

    &feld1: 0x28fe70
    &feld2: 0x28fe74
    feld1:  0x3f0ff0
    feld2:  0x3f1020
    

    Die Adressen sind unterschiedlich. Also Kopien wie du geschrieben hast.

    Den Code mit dem Zeigertausch:

    // Zeigertausch
        int** p_temp=0;
        p_temp=feld1;
        for(uint i=0;i<hoehe+1;i+=1) p_temp[i]=feld1[i];
        feld1=feld2;
        for(uint i=0;i<hoehe+1;i+=1) feld1[i]=feld2[i];
        feld2=p_temp;
        for(uint i=0;i<hoehe+1;i+=1) feld2[i]=p_temp[i];
    

    habe ich nun ge├Ąndert in:

    // Zeigertausch
        int* p_temp=0;
        for(uint i=0;i<hoehe;i+=1) {
            p_temp     =   feld1[i];
            feld1[i] =   feld2[i];
            feld2[i] =   p_temp;
        }
    

    Er hatte tats├Ąchlich, wegen den Zeigerkopien, nicht richtig getauscht und war auch sonst umst├Ąndlich geschrieben. Das war der entscheidende Tipp. Danke nochmal.

    Die ├╝berarbeitete FUNKTION next_generation():

    // === FUNCTION ======================================================================
    // Name:        next_generation
    // Description: Erzeugt Inhalte f├╝r zweites Feld und tauscht diese mit dem ersten Feld
    // Parameter:   hoehe ist die Zeilenanzahl der intMatrix
    //              breite ist die Spaltenanzahl der intMatrix
    // Rueckgabe:   0
    // =====================================================================================
    uint next_generation ( int **feld1, int **feld2, uint breite, uint hoehe ){
    
        // FELD2-BELEGUNG
        feld2[1][1]=2;
        feld2[1][2]=2;
        feld2[2][1]=2;
        feld2[2][2]=2;
    
        // AUSGABE - Vor Zeigertausch
        cout << "(Innerhalb Funktion)Felder vor Zeigertausch:" << endl;
        for(uint i=0;i<hoehe;i+=1) {
            for(uint j=0;j<breite;j+=1) cout << " " << feld1[i][j];
            cout << "  |  ";
            for(uint j=0;j<breite;j+=1) cout << " " << feld2[i][j];
            cout << endl;
        }
        cout << endl;
    
        // Zeigertausch
        int* p_temp=0;
        for(uint i=0;i<hoehe;i+=1) {
            p_temp     =   feld1[i];
            feld1[i] =   feld2[i];
            feld2[i] =   p_temp;
        }
    
        // AUSGABE - Nach Zeigertausch
        cout << "(Innerhalb Funktion)Felder nach Zeigertausch:" << endl;
        for(uint i=0;i<hoehe;i+=1) {
            for(uint j=0;j<breite;j+=1) cout << " " << feld1[i][j];
            cout << "  |  ";
            for(uint j=0;j<breite;j+=1) cout << " " << feld2[i][j];
            cout << endl;
        }
        cout << endl;
    
        return 0;
    }
    

    und die nun korrekte KONSOLENAUSGABE:

    Felder vor Funktionsaufruf:
     0 0 0 0 0 0 0 0 0 0  |   0 0 0 0 0 0 0 0 0 0
     0 0 0 0 0 0 0 0 0 0  |   0 0 0 0 0 0 0 0 0 0
     0 0 0 0 0 0 0 0 0 0  |   0 0 0 0 0 0 0 0 0 0
     0 0 0 0 0 0 0 0 0 0  |   0 0 0 0 0 0 0 0 0 0
     0 0 0 0 0 0 0 0 0 0  |   0 0 0 0 0 0 0 0 0 0
     0 0 0 0 0 1 1 0 0 0  |   0 0 0 0 0 0 0 0 0 0
     0 0 0 0 0 1 1 0 0 0  |   0 0 0 0 0 0 0 0 0 0
     0 0 0 0 0 0 0 0 0 0  |   0 0 0 0 0 0 0 0 0 0
     0 0 0 0 0 0 0 0 0 0  |   0 0 0 0 0 0 0 0 0 0
     0 0 0 0 0 0 0 0 0 0  |   0 0 0 0 0 0 0 0 0 0
    
    (Innerhalb Funktion)Felder vor Zeigertausch:
     0 0 0 0 0 0 0 0 0 0  |   0 0 0 0 0 0 0 0 0 0
     0 0 0 0 0 0 0 0 0 0  |   0 2 2 0 0 0 0 0 0 0
     0 0 0 0 0 0 0 0 0 0  |   0 2 2 0 0 0 0 0 0 0
     0 0 0 0 0 0 0 0 0 0  |   0 0 0 0 0 0 0 0 0 0
     0 0 0 0 0 0 0 0 0 0  |   0 0 0 0 0 0 0 0 0 0
     0 0 0 0 0 1 1 0 0 0  |   0 0 0 0 0 0 0 0 0 0
     0 0 0 0 0 1 1 0 0 0  |   0 0 0 0 0 0 0 0 0 0
     0 0 0 0 0 0 0 0 0 0  |   0 0 0 0 0 0 0 0 0 0
     0 0 0 0 0 0 0 0 0 0  |   0 0 0 0 0 0 0 0 0 0
     0 0 0 0 0 0 0 0 0 0  |   0 0 0 0 0 0 0 0 0 0
    
    (Innerhalb Funktion)Felder nach Zeigertausch:
     0 0 0 0 0 0 0 0 0 0  |   0 0 0 0 0 0 0 0 0 0
     0 2 2 0 0 0 0 0 0 0  |   0 0 0 0 0 0 0 0 0 0
     0 2 2 0 0 0 0 0 0 0  |   0 0 0 0 0 0 0 0 0 0
     0 0 0 0 0 0 0 0 0 0  |   0 0 0 0 0 0 0 0 0 0
     0 0 0 0 0 0 0 0 0 0  |   0 0 0 0 0 0 0 0 0 0
     0 0 0 0 0 0 0 0 0 0  |   0 0 0 0 0 1 1 0 0 0
     0 0 0 0 0 0 0 0 0 0  |   0 0 0 0 0 1 1 0 0 0
     0 0 0 0 0 0 0 0 0 0  |   0 0 0 0 0 0 0 0 0 0
     0 0 0 0 0 0 0 0 0 0  |   0 0 0 0 0 0 0 0 0 0
     0 0 0 0 0 0 0 0 0 0  |   0 0 0 0 0 0 0 0 0 0
    
    Felder nach Funktionsaufruf:
     0 0 0 0 0 0 0 0 0 0  |   0 0 0 0 0 0 0 0 0 0
     0 2 2 0 0 0 0 0 0 0  |   0 0 0 0 0 0 0 0 0 0
     0 2 2 0 0 0 0 0 0 0  |   0 0 0 0 0 0 0 0 0 0
     0 0 0 0 0 0 0 0 0 0  |   0 0 0 0 0 0 0 0 0 0
     0 0 0 0 0 0 0 0 0 0  |   0 0 0 0 0 0 0 0 0 0
     0 0 0 0 0 0 0 0 0 0  |   0 0 0 0 0 1 1 0 0 0
     0 0 0 0 0 0 0 0 0 0  |   0 0 0 0 0 1 1 0 0 0
     0 0 0 0 0 0 0 0 0 0  |   0 0 0 0 0 0 0 0 0 0
     0 0 0 0 0 0 0 0 0 0  |   0 0 0 0 0 0 0 0 0 0
     0 0 0 0 0 0 0 0 0 0  |   0 0 0 0 0 0 0 0 0 0
    
    Process returned 0 (0x0)   execution time : 0.109 s
    Press any key to continue.
    

    Den ersten Kommentar von spechtr habe ich nicht verstanden.



  • Sch├Ân dass es jetzt f├╝r Dich funktioniert. Die Frage ist halt, warum nutzt Du nicht die M├Âglichkeiten von C++? Stattdessen, sieht Dein Code so aus, als w├╝rdest Du C programmieren und nur printf durch cout und malloc durch new ersetzten. Rohe Zeiger brauchst Du in C++ nur ganz selten. Hier k├Ânntest Du stattdessen z.B. std::vector oder std::array verwenden. F├╝r das Tauschen von 2 Variablen gibt es die fertige Funktion std::swap. Die macht auch nichts anderes als:

    temp=var1;
     var1=var2;
     var2=temp;
    

    nur das im Gegensatz zu Deinem Versuch die Parameter hier per Referenz ├╝bergeben werden, so dass der Tausch auch funktioniert. Dein int** ist eigenlich ein neuer Typ f├╝r eine 2-Dim-Matrix. Dazu hast Du dann die Funktionen new_int_matrix (Konstruktor) und delete_int_matrix (Destruktor). Das k├Ânnte man dann auch gleich in eine eigene Klasse packen.

    EDIT: Rechtschreibung



  • Hi nochmal

    Stimmt alles was du sagst. Warum nicht die Werkezuge nutzen die C++ bietet.

    Das ist eine Aufgabe aus dem Studium gewesen.
    Die beiden Funktionen new_int_matrix und delete_int_matrix waren vorgegeben. Aber gute Idee mit der Klasse!
    Ich vermute weil der Dozent uns den Umgang mit Zeigern n├Ąher bringen will, gibt er uns ├ťbungen, wo wir ein wenig mit rohen Zeigern arbeiten sollen.
    Sp├Ąter in der Praxis werde ich definitiv das verwenden was mir C++ bietet.
    Aber erstmal versuche ich zu verstehen.

    Danke f├╝r die guten Tipps und Infos nochmal! ­čĹŹ


Log in to reply