Stringstream und dynamisches Array



  • Hallo, ich habe ein Prolbem mit meinem Code.

    Folgende Ausgangssituation:

    Datei.txt enthält in der ersten Zeile die "Zeilen-" und "Spaltenangabe" einer Matrix. Danach folgt die Matrix die eingelesen werden soll.

    Datei.txt:
    4 2     
    1 2
    3 4
    5 6
    7 8
    

    4 wäre die Zeilenangabe und 2 die Spaltenanzahl.
    Ich "vermute" meinen Fehler beim Reservieren des Speichers, bzw. bei der zuweisung des Wertes an das Array.

    string sBuffer;				// enthält eine Zeile als String
    	istringstream isZahl;		// der Stream enthält den umgewandelten Buffer	
    
    	int iSpalten;		// Anzahl der Spalten
    	int iZeilen;		// Anzahl der Zeilen
    
    	int** dynarray;
    
    	int icnt = 1;
    
     	while(getline(stream, sBuffer))
    	{
    		isZahl.str(sBuffer);			// isZahl ist der wert bis zum nächsten Leerzeichen/Tabulator/Newline
    
    		if(icnt == 1)
    		{
    
    			isZahl >> iZeilen;
    			isZahl >> iSpalten;
    
    			dynarray = new int* [iZeilen];	// Platz für Zeilen reservieren
    
    			// int** -> dyanarray[0]
    			//			dyanarray[1]
    
    			// Nun Speicher fuer die Spalte reservieren
    			for(int i = 0; i < iZeilen; i++)
    					dynarray[i] = new int [iSpalten];			// Speicherplatz für die Spalten reservieren
    
    			// int** -> dyanarray[0] --> dyanarray[0][0] dyanarray[0][1]
    			//			dyanarray[1] --> dyanarray[1][0] dyanarray[1][1]
    		}else
    		{ 
    			// Zur Fehleranalyse erleichtert, Wert immnoch unangetastet 8(
    					isZahl >> dynarray[0][0];
    
    		}
    		icnt++;
    	}
    

    Ich bin mir nicht sicher ob ich den Decompiler nicht richtig bediene aber bei der Anweisung:

    for(int i = 0; i < iZeilen; i++)
    dynarray[i] = new int [iSpalten];
    

    scheint er mir auch mehr Spalten zu reservieren als angegeben.
    Ich hab z.B. eine 4x2 Matrix da reserverit er mir nicht nur matrix[0][0-1] sondern matrix[0-9] oder so, halt eine größere Anzahl an Spalten.

    Also nochmal kurz gesagt, mein Problem ist das in der Else-Bedingung der Stream zwar da ist aber der wert nicht ins Array wandert und es mir ein Rätsel ist warum der Speicher ziemlich großzügig obwohl nicht angegeben erweitert wird.

    Vom Compiler selbst kommt kein Fehler, und der Stream ist auch da, nur der Wert nicht im Array -.-

    EDIT: Hab den ELSE-BLock mal vereinfacht, der Wert in dynarray[0][0] verändert sich nicht.



  • for(int i = 0; i < iZeilen; i++) 
    dynarray[i] = new int* [iSpalten];
    

    Du forderst ja bereits Speicher für die zweite Dimension an, deshalb muss der Zeiger weg (gibt es da keinen Compilerfehler?):

    dynarray[i] = new int [iSpalten];
    


  • das war n Fehler der sich in den Post reingeschumelt hat, :> bei diesem Problem tritt in der Tat ein Compilerfehler auf aber meine momentane Situation ist ohne diesen Tippfehler. du warst flink^^



  • Ich glaube nicht, dass du mit einem Decompiler arbeitest.. 😉
    Wohl eher den Debugger. Schau damit doch nach, was iSpalten für einen Wert hat dort. (Nur in sehr seltenen Fällen stimmt das nicht, was (mein) VC mir da anzeigt, ansonsten auch mal neu starten, sollte aber nicht das Problem sein).



  • ^^ ich streiche Decompiler und ersetze mit Debugger

    selbst wenn ich im Else-Block eine zuweisung gebe,

    isZahl >> dynarray[0][0];
    

    bleibt das Array unangetastet und der Inhalt ist der gleiche wie zur Zeit der Speicherreservierung.

    Die Spaltenanzahl liegt lt. Überwachungsfenster bei 599 also die Spaltenanzahl stimmt, nur die Spalten gehen bei mir von 0-599 -.- Obwohl iSpalte und Zeile den korrekten Wert liefern.

    Kann ich mir im Überwachungsfenster den Inhalt des "isZahl"-Streams anzeigen lassen ?



  • Keydo schrieb:

    Kann ich mir im Überwachungsfenster den Inhalt des "isZahl"-Streams anzeigen lassen ?

    Das sollte eigentlich gehen, schau bei dessen Membern. Ansonsten machst du eben eine Ausgabe:

    std::cout << isZahl.str() << std::endl;
    

    Es ist relativ wahrscheinlich, dass der Stream fehlerhaft ist, wenn das Array nicht berührt wird durch den operator >> .



  • Also die Ausgabe läuft wie erwartet, und der Inhalt vom Stream ist auch richtig,
    Ich hab mit stream.fail() geprüft und mit dem Debugger die zeilenweise Ausgabe vom stream auf der Console.

    hmm komisch, sicherlich ist es nur etwas triviales -.-



  • Das ist echt merkwürdig... Versuch mal, mit dem Stream und op>> in eine andere, gerade zuvor deklarierte Variable zu schreiben und überprüf diese. Falls die Variable immer noch nicht den richtigen Wert hat, liegt es definitiv am Stream.

    Wilde Zeiger und sonstige undefinierte Dinge hast du nirgends?



  • int iTest = 0;
    isZahl >> iTest;
    cout << iTest << isZahl.str();
    

    also iTest bleibt 0 *komisch*, aber isZahl.str() gibt mir den Wert des Buffers aus (also den Zeileninhalt).

    Das macht mir n bissel angst :>



  • Hm... vermutlich ist stream-intern etwas kaputt. Was passiert, wenn du dem Stream per str() einen neuen String zuweist und dasselbe nochmals versuchst?

    Ich geh dann mal ins Bett, gute Nacht 😉



  • N8i Nexus,

    selbst n neudefinierten string hat er nicht genommen -.-

    UPDATE: oh ich glaube ich habs, krass -.- wenn ich den Stream vor jedem getline. mit Clear() lösche scheint es zu funktionieren.



  • Hast du tatsächlich bis spät in die Nacht an dem rumprobiert? 😃

    Mit stringstream::clear() setzt du nur die Fehlerflags zurück, was heisst, dass irgendwo etwas schiefgelaufen ist. Du solltest dich vielleicht schon darum kümmern, denn Ignorieren von Fehlern ist nicht immer das Wahre...



  • Hallo, ich wollte ungern deswegen einen neuen Thread aufmachen und versuch es hier als Anhang.

    Ich hab nun nach der While-Schleife veruscht den Speicher des Arrays wieder freizugeben. Dies klappt bis zu einem bestimmten Punkt dann erfolgt eine Fehlermeldung, das der Heap kaputt sei.

    // Speicherplatz wieder freigeben
    	// in umgekehrter Reihenfolge
    
    	// Spalten der I-ten Zeile
    	for(int i = 0; i < iZeilen; i++)
    	{
    		delete dynarray[i];
    	}
    	delete [] dynarray;   // <-- nach dieser Anweisung sagt er mir "HEAP Corrupton ERROR"
    

    Wordurch wird das verursacht? Wie kann ich das vermeiden oder umgehen? Habe ich etwas übersehen?



  • Du hast ja ein zweidimensionales Array, behandelst es aber bei der Freigabe wie ein eindimensionales.

    Richtig wäre:

    for(int i = 0; i < iZeilen; ++i)
    {
        for (int j = 0; j < iSpalten; ++j)
        {
            delete dynarray[i][j];  // 2. Dimension löschen
        }
        delete[] dynarray[i];       // 1. Dimension löschen
    }
    delete[] dynarray;              // 0. Dimension löschen
    


  • jo, ich hab die n8 dran gehockt und gelesen und gelesen ^^

    ich hab mal den Code etwas gekürtzt um die Fehlerstellen besser zu finden.

    #include <iostream>
    #include <fstream>
    #include <sstream>
    #include <string>
    using namespace std;
    
    int main(int argc, char** argv)
    {
    
    	// Datei zum Lesen öffnen
    	ifstream stream("eingabe.txt");
    	if( stream.is_open() != true )
    	{
    	cout << "Fehler beim Datei nicht öffnen!\n" << endl;
    	};
    
    	string sBuffer;
    	istringstream isZahl;
    
    	int iSpalten = 0;		// Anzahl der Spalten
    	int iZeilen = 0;		// Anzahl der Zeilen
    
    	bool isMatrixRead = false;
    	int** dynarray = NULL;
    
    	int icnt = 1;
    
     	while(getline(stream, sBuffer))
    	{
    		isZahl.str(sBuffer);
    
    		if(icnt == 1)
    		{
    
    			isZahl >> iZeilen;
    			isZahl >> iSpalten;
    
    			dynarray = new int* [iSpalten];	// Platz für Zeilen reservieren
    
    			// int** -> dyanarray[0]
    			//			dyanarray[1]
    
    			// Nun Speicher fuer die Spalte reservieren
    			for(int i = 0; i < iZeilen; i++)
    					dynarray[i] = new int [iSpalten];			// Speicherplatz für die Spalten reservieren
    
    			// int** -> dyanarray[0] --> dyanarray[0][0] dyanarray[0][1]
    			//			dyanarray[1] --> dyanarray[1][0] dyanarray[1][1]
    
    		}else if (!isMatrixRead)
    		{
    			for(int i = icnt-2; (i < icnt-1 && i < iZeilen);i++ )
    			{
    				for(int k = 0; k < iSpalten; k++)
    				{
    					isZahl >> dynarray[i][k];
    				}
    			}
    			if(icnt-2 == iZeilen)
    				isMatrixRead = true;
    
    		}
    		//isZahl.clear();
    		icnt++;
    	}
    	// Speicherplatz wieder freigeben
    	// in umgekerhter Reihenfolge
    
    /*	
    	for(int i = 0; i < iZeilen; i++)
    	{
    		for(int j = 0; j < iSpalten; j++)
    		{
    			delete dynarray[i][j];
    		}
    		delete[] dynarray[i];
    	}
    	delete [] dynarray;
    */
    return 0;
    }
    

    Die Anweisung "delete dynarray[i][j]" mag er nicht da Objekte die keine Zeiger sind nicht gelöscht werden können.



  • Sorry, ich hatte deine Speicheranforderung falsch im Kopf.

    Schau mal im Code:

    dynarray = new int* [iSpalten]; // Dimension iSpalten
    // ...
    for(int i = 0; i < iZeilen; i++) 
        dynarray[i] = new int [iSpalten]; // auch Dimension iSpalten
    

    Ich weiss nicht, wie du das 2D-Array organisierst, aber eine der beiden Dimensionen muss die Zeilen- und die andere die Spaltenanzahl sein.

    Was den Stream betrifft, seh ich gerade nichts. Geh mit einem Debugger schrittweise durch und überprüf die Fehlerflags, dann siehst du auch, wo der Fehler auftritt.

    Beim FileStream könntest du auch if(!stream) schreiben.


  • Administrator

    Der Fehler mit dem Stream ist wohl sehr trivial.
    Teste mal ob eof() true zurück gibt. Ich bin mir ziemlich sicher, dass er das tut. Du liest Werte aus und der Stream kommt ans Ende und setzt dann das Flag EOF, was ein Fehler ist und man kann aus dem Stream nichts weiteres mehr auslesen.
    Falls wirklich das EOF Flag gesetzt ist, dann ist der Aufruf von clear() gar nicht so verkehrt 😉

    Grüssli



  • Also wie das 2D-Array aufgebaut werden sollte, hab ich mir folgendes szenario angeschaut:

    Bild:
    http://www.hs-augsburg.de/~sandman/c_von_a_bis_z/bilder/16_10.gif

    Bezüglich des EOF.Flags werd ich gleich nochmal guggn.



  • Das EOF-Flag szenario:

    Nachdem er die ersten beide Werte aus dem Stream in die Variablen kopiert hat, setzt er das EOF-Flag. Das EOF-Flag bleibt gesetzt bis eine Clear-Anweisung kommt.

    Das hat aber auch nur Auswirkung beim Auslesen des Streams -.- der Inhalt des Streams wird angepasst.

    Nun bleibt nur noch die spannende Frage wieso nun mein kleines Array rum zickt.

    wird vlt. wieder eine lange N8 ^^


  • Administrator

    Noch kurz Zeit gehabt, dein zweites Problem anzuschauen:

    int main()
    {
        // Beispiel-Erstellung:
        int** pArray = new int*[5];
    
        for(int i = 0; i < 5; ++i)
        { pArray[i] = new int[10]; }
    
        // Beispiel-Zerstörung:
        for(int i = 0; i < 5; ++i)
        { delete[] pArray[i]; } // Hier war glaub ich der Fehler. Ein delete[] wird benötigt und nicht ein simples delete.
    
        delete[] pArray;
    }
    

    Ich glaube damit sollten alle Probleme behoben sein, oder?
    Anstatt C-Arrays könntest du auch std::vector nehmen, dann würden solche delete Probleme erst gar nicht auftauchen :p

    Grüssli


Anmelden zum Antworten