# C++ HEAP Corruption detected



## Puepue (27. Dezember 2010)

Hallo zusammen, 
habe ein Problem bei einem Schulprojekt..
Ich habe eine Klasse geschrieben, die einen Poitner mit einem Wort enthält (bspw. "Hallo") - wenn ich den angeforderten Speicher  im Destructor mit delete[] freigeben will, diesen doofen Heap Corruption error (kommt ja eigentlich nur, wenn man nicht-allokierten Speicher freigeben will, oder?
Screenshot + Projekt anbei

Dankööö


----------



## bingo88 (27. Dezember 2010)

nee, das kann auch passieren, wenn du wo drüber pinselst. Ich suche gerade mal im Code nach möglichen Problemstellen...


----------



## Puepue (27. Dezember 2010)

Super, danke!
FYI: Der Fehler tritt auch auf, wenn ich das Programm direkt nach der Satzeingabe mit Esc beende - also keine der Menüpunkte ausführe


----------



## bingo88 (27. Dezember 2010)

Also erstmal hab ich nen Speicherleck gefunden (in der memManager-Funktion):


```
char * oldString = this->pString;
```
Du merkst dir da zwar den alten String zum Kopieren, gibst den allozierten Speicher aber nach der Kopiererei nicht frei.

Mein erster Verdacht:

```
for(i=0;i<((size * zuKopierendeBloecke) + this->getTextlaenge());i++)
        {
            /*cout << "size: " << size << endl;
            cout << "zuKopierendeBloecke: " << zuKopierendeBloecke << endl;
            cout << "this->blockgroesse: " << this->blockgroesse << endl;
            cout << "vorhandeneBloecke: " << vorhandeneBloecke << endl;
            cout << "this->getTextlaenge(): " << this->getTextlaenge() << endl;
            cout << "i: " << i << endl;*/
            pString[i] = oldString[i]; // <- oldString ist kleiner als pString, Überlauf?
        }
```

Der erste Aufruf der memMgmt-Funktion liefert bei mir auch hier 0 chars (Blockgröße 8)! 

```
this->pString = new char[(size * zuKopierendeBloecke) + this->getTextlaenge()]; // size = 1 * zuKopierendeBlöcke = 0 + Textlen = 0 ergibt 0!
```


----------



## Puepue (27. Dezember 2010)

Hmm diese doofe Funktion.. war an der Stelle schon x-mal.. das schaue ich mir mal an... vermutlich reicht da ja eine Abfrage, dass da mind. 1 raus kommen muss, kann das sein?


----------



## bingo88 (27. Dezember 2010)

So, habe es glaube ich gefunden:

```
// Ans Ende eine binaere Null setzen
        pString[i+1] = '\0';
```
Im ersten Durchgang wird bei mir ein Array der Größe 0 erzeugt (Siehe vorherigen Post), hier wird aber mindestens an Position 1 geschrieben => außerhalb des allozierten Bereichs.


----------



## Puepue (27. Dezember 2010)

Hmmm das macht natürlich Sinn, ich bin mir nur nicht sicher, wie ich das umgehen soll - wenn ich das hier mache (habe jetzt immer ein + 1 ans ende gehangen), stürzt das Programm in der 1. For-Schleife ab ( denke mal, weil es dann kein oldString_ gibt, weil oldString ist ja leer..


		Code:
	

char * oldString = this->pString; //merken
        cout << "oldString gemerkt" << endl;

        int tmpGroesse = (size * zuKopierendeBloecke) + this->getTextlaenge() + 1;

        //this->pString = new char[this->getTextlaenge() + size + 1];
        
        this->pString = new char[tmpGroesse];

        //cout << "Speichert in Groesse " << size * this->blockgroesse << " allokiert" << endl; 
        cout << "Speicher in Groesse " << tmpGroesse << " allokiert" << endl; 

        
        cout << "Durlaufe For-Schleife " << tmpGroesse << " mal ..";
        int i = 0;
        for(i = 0; i < tmpGroesse; i++) {
            /*cout << "size: " << size << endl;
            cout << "zuKopierendeBloecke: " << zuKopierendeBloecke << endl;
            cout << "this->blockgroesse: " << this->blockgroesse << endl;
            cout << "vorhandeneBloecke: " << vorhandeneBloecke << endl;
            cout << "this->getTextlaenge(): " << this->getTextlaenge() << endl;
            cout << "i: " << i << endl;*/
            pString[i] = oldString[i];
        }
        cout << "..done" << endl;

        // Ans Ende eine binaere Null setzen
        cout << ".. i: " << i << endl;
        pString[i+1] = '\0';

_


----------



## Puepue (27. Dezember 2010)

Wenn ich das +1 weglasse, und einfach so abfrage:

```
if (i > 0) {
            pString[i+1] = '\0';
        }
```

stürzt das Programm zwar nicht ab, aber es kommt wieder Heap corruption dabei raus


----------



## bingo88 (27. Dezember 2010)

Länge von pString != Länge von ostring in der Schleife. Du läufst vermutlich zu weit. Du darfst nur Länge(ostring) elemente kopieren, also die Länge des alten Arrays kennen/herausfinden.


----------



## Puepue (28. Dezember 2010)

hmm.. ist vermutlich einfach nur schon zu spät .. aber wie mach ich das am besten bei

```
char * oldString = this->pString; //merken
int strlenOld = strlen(oldString);
```

schmiert das Programm einfach so ab und bei dem hier auch:

```
int strlenOld = strlen(this->pString);
char * oldString = this->pString; //merken
```


----------



## bingo88 (28. Dezember 2010)

ich habe auch die Vermutung, dass du pString im Konstruktor nicht auf NULL initialisiert hast bzw. in der memManager-Funktion nicht darauf prüfst. Ich bin ja mit dem Debugger im Einzelschrittmodus mal durch die Funktion gegangen und der Zeiger war nicht NULL - obwohl noch keine Daten drinnen stehen können -> strlen greift auf Speicher zu, der deinem Programm nicht gehört.


----------



## Fragile Heart (28. Dezember 2010)

Ich versuche jetzt seid einer guten halben Stunden deinen Code zu verstehen und komme da einfach nicht weiter.  

Du erzeugst am anfang einen leer String, also quasi nur eine abschließende 0 und hängst in dieser "memManager" Funktion jedes mal eine weitere 0 ans Ende .... warum?

Edit:
Jetzt verstehe ich das! Allllsssssoooooo, dein Problem ensteht, wie Bingo schon sagte, in der Zeile in der du das Abschlußzeichen setzt. Die Lösung an dieser Stelle ist aber nicht ganz so einfach, da du leider keinerlei Code hast, der Prüft ob hier ein null Pointer vorhanden ist! Du wirst dir die gesamte memManager Funktion noch einmal vornehmen müssen. Vielleicht ist es an dieser Stelle ein guter Ansatz wenn du, in dieser Funktion auch nur das machst, was der Name vermuten liese ... nur den Speicherverwalten.


----------



## bingo88 (28. Dezember 2010)

Ja, in der Funktion wird vermutlich das Problem liegen. Ist das Programm eigentlich zu einer Aufgabe oder hast du dir das selbst überlegt?


----------



## Puepue (28. Dezember 2010)

War wohl wirklich zu spät 
Habs jetzt alles in allem so gemacht:


```
// memManager
void TString::memManager (int size)
{
    if (this->getTextlaenge() < 0) {        // man weiß ja nie... 
        if (size < 0) {
            this->setTextlaenge(0);
        } 
        if (size >= 0) {
            this->setTextlaenge(size-1);
        }
    }
    int lenOld = 0;
    lenOld = this->getTextlaenge();

    int benoetigteBloecke = (size/this->blockgroesse);

    if (size % this->blockgroesse > 0) {        // Wenn Rest
        benoetigteBloecke ++;            
    }

    int vorhandeneBloecke = getBlockZahl();

    // Wenn weniger Blocke vorhanden, als benoetigt => vorhandene Bloecke, sonst benoetigte Bloecke
    int zuKopierendeBloecke = (vorhandeneBloecke < benoetigteBloecke) ? vorhandeneBloecke : benoetigteBloecke;

    if (benoetigteBloecke != vorhandeneBloecke) {
        cout << "benoetigteBloecke != vorhandeneBloecke";
        char * oldString = this->pString; //merken
        cout << "oldString gemerkt" << endl;

        int tmpGroesse = (size * zuKopierendeBloecke) + this->getTextlaenge();

        //this->pString = new char[this->getTextlaenge() + size + 1];
        
        this->pString = new char[tmpGroesse];

        //cout << "Speichert in Groesse " << size * this->blockgroesse << " allokiert" << endl; 
        cout << "Speicher in Groesse " << tmpGroesse << " allokiert" << endl; 

        cout << "Durlaufe For-Schleife " << lenOld << " mal ..";
        int i = 0;
        for(i = 0; i < lenOld; i++) {
            /*cout << "size: " << size << endl;
            cout << "zuKopierendeBloecke: " << zuKopierendeBloecke << endl;
            cout << "this->blockgroesse: " << this->blockgroesse << endl;
            cout << "vorhandeneBloecke: " << vorhandeneBloecke << endl;
            cout << "this->getTextlaenge(): " << this->getTextlaenge() << endl;
            cout << "i: " << i << endl;*/
            pString[i] = oldString[i];
        }
        cout << "..done" << endl;

        // Ans Ende eine binaere Null setzen
        cout << ".. i: " << i << endl;
        if (i > 0) {
            pString[i+1] = '\0';
        }
        

        cout << "Binaere Null gesetzt" << endl;

        /*cout << "Setze Blockzahl auf " << benoetigteBloecke << endl;
        setBlockZahl(benoetigteBloecke);*/
        cout << "Setze Blockzahl auf " << this->getBlockZahl() << " plus " << benoetigteBloecke << endl;
        setBlockZahl(this->getBlockZahl() + benoetigteBloecke);
    }

    this->setTextlaenge(this->getTextlaenge() + (size-1));

}
```


----------



## Puepue (28. Dezember 2010)

Hab aber mal ne andere Frage.. du schreibst immer alloziert .. ich bin aber der festen Überzeugung allo*k*iert gelernt zu haben - ist das das gleiche?


----------



## Puepue (28. Dezember 2010)

Oh sehe gerade, dass da vor mir ein paar Posts waren (böser Cache) 
Das Programm ist eine Schulaufgabe (würde niemals freiwillig wsowas in c++ programmieren, bin in php zuhause da erspar ich mir das ) - dabei sind alle Funktionen vorgegeben - auch der memmanager - aber so klappt es jetzt, danke für den Tipp mit dem Merken der alten Länge


----------



## Fragile Heart (28. Dezember 2010)

Schaust du hier.  allokieren ? Wiktionary


----------



## bingo88 (28. Dezember 2010)

Hmm.. geht wohl beides iwie


----------

