EAccessViolation beim lesen von Daten und schließen der Anwendung



  • Einen schönen guten Tag an alle. Ich schreibe ein Programm zum Lesen und Schreiben von Daten. Wenn ich nun mit dem Programm Daten geschrieben habe und es wieder Schließe bekomme ich eine EAccessViolation. Beim einlesen der Daten das gleiche. Nur das ich da bereits beim 2ten Einlesen eine Fehlermeldung bekomme. Ich befürchte ich gebe irgendeinen Speicher nicht frei aber welchen?

    hier der Quellcode:

    int filesize(int te )
    {
    	struct stat datei_infos;
    	char* pcDatei = "festelaenge.bin";
    
    	if ( 0 != stat( pcDatei, &datei_infos ) ) return 0;
    	else return datei_infos.st_size;
    }
    //---------------------------------------------------------------------------
    void __fastcall TForm1::Button1Click(TObject *Sender)
    {
     fstream fileout;
    
    //Die Datei wird zum schreiben geöffnet (ios::out)
    //Die Datei ist eine Binärdatei (ios::binary)
    //neu Daten werden an das ende der Datei geschrieben. (ios::app)
    //int *crypt =
    fileout.open("festelaenge.bin", ios::out|ios::binary|ios::app);
    	char   *buffer1 = new char[40];
    			buffer1 = Edit1->Text.c_str();
    
    	if (Edit1->Text.Length()<40) {
    		for (int i=Edit1->Text.Length() ; i <= 40; i++) {
    		buffer1[i]= char(0);
    		}
    	}
    
    	fileout.write(buffer1,40*sizeof(char));
    
    	char   *buffer2 = new char(40);
    			buffer2 = Edit2->Text.c_str();
    
    	if (Edit2->Text.Length()<40) {
    		for (int i=Edit2->Text.Length() ; i <= 40; i++) {
    		buffer2[i]= char(0);
    		}
    	}
    	fileout.write(buffer2,40*sizeof(char));
    
    	int buffer3 = StrToInt(Edit3->Text);
    
    	fileout.write( (char*)&buffer3,sizeof(int));
    fileout.close();
    delete buffer1;
    delete buffer2;
    }
    //---------------------------------------------------------------------------
    void __fastcall TForm1::Button2Click(TObject *Sender)
    {
    using namespace std;
    fstream FileBin;
    	int nn 	= filesize(1);
    	int f 	= 40;
    	int g 	=  4;
    		nn  = (nn / ((2*f)+g))+1;
    	int an;
    	int bn;
    	int cn;
    
    char *Feldname		= new char(40);
    char *Feldtype		= new char(40);
    int  Feldlaenge;
    FileBin.open("festelaenge.bin", ios::in|ios::binary);
    for (int n = 1; n <= nn-1; n++) {
    	an = ((( 2 * f + g)*(n-1)));
    	FileBin.seekg(an, ios::beg);
    	FileBin.read(Feldname,40);
    	StringGrid1->Cells[1][n]=(an);
    	StringGrid1->Cells[2][n]=Feldname;
    	bn = ((( 2 * f + g)*(n-1))+(f));
    	FileBin.seekg(bn, ios::beg);
    	FileBin.read(Feldtype,40);
    	StringGrid1->Cells[3][n]=(bn);
    	StringGrid1->Cells[4][n]=Feldtype;
    	cn = ((( 2 * f + g)*(n-1))+(2*f));
    	FileBin.seekg(cn, ios::beg);
    	FileBin.read( (char*)&Feldlaenge, sizeof(int));
    	StringGrid1->Cells[5][n]=(cn);
    	StringGrid1->Cells[6][n]=IntToStr(Feldlaenge);
     }
    FileBin.close();
    delete Feldname;
    //delete Feldtype; <-- Wenn ich diese Zeile activ habe wirft er direkt eine                 EAccessViolation was ich nicht ganz verstehe da ich ja den Speicher wieder Freigeben muss.
    }
    

    Ich bin Kurz vorm verzweifeln und finde den verdammten Fehler nicht. Ach ja beim lesen entsteht der Fehler sobald ich die Datei nochmals öffnen will.



  • Hallo,

    Ich habe mir jetzt nicht alles angeschaut, mir fällt aber auf Anhieb das hier auf

    char   *buffer1 = new char[40]; //Speicher für 40 chars reservieren
                buffer1 = Edit1->Text.c_str(); // Zeiger wieder überschreiben (Speicherleck!)
    

    Hiermit erzeugst du schonmal ein Speicherleck. Außerdem gibt c_str() ein const char* zurück welches einen Zeiger auf den internen Speicher eines AnsiStrings ist. Den darfst du niemals beschreiben!
    Du kannst hier für buffer1 und buffer2 gleich AnsiStrings nehmen.

    fileout.open("festelaenge.bin", ios::out|ios::binary|ios::app);
        fileout.write(Edit1->Text.c_str(),40*sizeof(char));
        fileout.write(Edit1->Text.c_str(),40*sizeof(char));
        int buffer3 = StrToInt(Edit3->Text);
        fileout.write( (const char*)&buffer3,sizeof(int));
    fileout.close();
    }
    

    Dann das hier

    char *Feldname        = new char(40);
    

    Feldname ist ein Zeiger auf ein einzelnes char (kein Array) welches den Wert 40 enthält.
    besser

    char *Feldname        = new char[40];
    

    Weiter habe ich erstmal nicht nachgeschaut.



  • char[40] hat nur Platz für 39 Zeichen, ein Byte wird für die Null-Terminierung "verbraucht".



  • Ok das mit den eckigen Klammern war es, naja mit den Zeigern das blicke ich noch nicht ganz ich habe es zwar inhaltlich verstanden aber naja wann was wie sein muss verwechsele ich manchmal. Bin noch neu in C++.
    Was deine Anregung mit c_str() angeht wäre das doch nur eine Verkürzung des Quelltextes aber damit kann ich ja kein char(0) mehr anhängen siehe die for schleife. Welche ja nur den String verlängert so das er beim speichern immer 40 Zeichen hat.

    War es nicht bei char Arrays so dass es bei 0 beginnt? wenn ich mit Haltepunkten arbeite und mir die Werte des Arrays ansehe dann ist der erste Buchstabe in [0] und nicht in [1]. Demzufolge wäre es dann doch 41 Zeichen die in dem Array stehen können und Somit Das null terminierte die 41. Ist das richtig so?



  • Hallo

    Ein Array x[40] hat 40 Elemente die von 0 bis 39 durchnummeriert sind. Und bei C-Strings ist per Definition das letzte Zeichen ein 0. Das bedeutet das
    char[40] genau 39 gültige Zeichen aufnehmen kann, weil das 40. für 0 gebraucht wird.

    bis bald
    akari



  • Ganz schön verwirrend nagut dann muss ich also 41 machen danke.



  • S.Fiege schrieb:

    Was deine Anregung mit c_str() angeht wäre das doch nur eine Verkürzung des Quelltextes aber damit kann ich ja kein char(0) mehr anhängen siehe die for schleife. Welche ja nur den String verlängert so das er beim speichern immer 40 Zeichen hat.

    Du brauchst doch bei deiner Art des Einlesens überhaupt keine 0 vor dem Rausschreiben anhängen da du ohnehin genau 40 Zeichen einliest. Beim Einlesen mußt du natürlich als 41s Zeichen eine 0 anhängen.
    Außerdem ist mein Code nicht nur eine Verkürzung, sondern auch eine Berichtigung, da du ja 1. ein Speicherleck erzeugst, 2. in den geschützten Speicher eines Ansistrings schreiben willst und 3. dies in deinem Fall sogar auf einen temporären AnsiString machst (Text von TEdit ist eine Eigenschaft, keine Variable). Wenn du schon unbedingt dort einen Puffer verwenden willst, mußt du schon mit strncpy kopieren.


Anmelden zum Antworten