Forum: PC-Programmierung Run-Time Check Failure #2 - Stack around the variable 'anzahl_dummy' was corrupted.


von Kilian K. (kellermaaan)


Lesenswert?

Hallo alle zusammen,

ich bräuchte Hilfe bei meinem Code!
Momentan sollen wir einen Vokabeltrainer in C++ programmieren. Soweit 
funktioniert auch alles aber zwischendurch bekomme ich halt diese 
Fehlermeldung "Run-Time Check Failure #2 - Stack around the variable 
'anzahl_dummy' was corrupted."

Hier mal die Funktion dazu:
1
struct Anzahl Schnittstelle::get_anzahl(void)
2
{
3
  //Zwischenspeicher deklarieren
4
  Anzahl anzahl_dummy;
5
6
  //Struktur init
7
  anzahl_dummy._anzahl_gesamt = 0;
8
  anzahl_dummy._anzahl_noch_zu_lernen = 0;
9
10
  //Datei zum lesen öffnen
11
  vokabeltrainer.open_my_datei(DATNAME, MODUS_LESEN);
12
13
  //Wenn es einen Fehler gab diesen abfragen
14
  if (!vokabeltrainer.erfolgskontrolle())
15
  {
16
    _fehler = 1;
17
18
    //Datei wieder schließen
19
    vokabeltrainer.close_my_datei();
20
21
    //Fehler abfragen
22
    if (!vokabeltrainer.erfolgskontrolle())
23
    {
24
      _fehler = 1;
25
    }
26
  }
27
  else
28
  {
29
    //Dateigröße erfassen
30
    vokabeltrainer.get_dateigroesse();
31
32
    //die Anzahl der Vokablen holen
33
    anzahl_dummy = vokabeltrainer.get_anzahl();
34
35
    //Datei wieder schließen
36
    vokabeltrainer.close_my_datei();
37
38
    //Fehler abfragen
39
    if (!vokabeltrainer.erfolgskontrolle())
40
    {
41
      _fehler = 1;
42
    }
43
  }
44
45
  //Anzahl wird zurückgegeben
46
  return anzahl_dummy;
47
}

Allerdings tritt dieser Fehler nicht immer auf. Mein Programm hat 3 
Auswahlmöglichkeiten. Ich kann eine neue Vokabel in eine Datei 
schreiben, dann eine Vokabel in der Datei ändern, und dann gibt es noch 
einen Lern-Modus. Wenn ich das Programm starte und direkt eine Vokabel 
ändern möchte funktioniert alles und Fehler tritt nicht auf. Wenn ich 
aber erst eine Vokabel hinzufüge und dann eine ändern möchte bekomme ich 
diese Fehlermeldung... Ich bin mal mit dem Debugger durch gegangen aber 
mir fällt nichts besonderes auf! Und wenn ich erst eine Vokabel neu 
hinzufüge wird diese Methode auch nicht aufgerufen, deshalb verstehe ich 
es nicht...

Ich hoffe deshalb, dass mir hier einer helfen kann und wäre demjenigen 
sehr dankbar!

Gruß Kilian

von Rolf M. (rmagnus)


Lesenswert?

Vermutlich liegt der Fehler wo anders. Zum Beispiel könnte ein String zu 
klein sein für das, was er aufnehmen soll. Dann werden Variablen 
dahinter mit falschen Daten überschrieben. Wenn z.B. 
vokabeltrainer.get_anzahl den Stack auf diese Weise beschädigt, kann 
sich das auch auf die genannte Variable auswirken.
Du hast nichts über dein System geschrieben, aber wenn du z.B. unter 
Linux arbeitest, kannst du mit valgrind nachschauen, wo die Ursache des 
Problems liegt.

von Kilian K. (kellermaaan)


Lesenswert?

Danke erstmal für deine Antwort!

Also ich arbeite mit Win8.1 und  Visual Studio 13. Ich wüsste jetzt aber 
auch nicht was meinen Speicher zerschießen sollte... Wenn ich ja vorher 
nichts in die Datei schreibe funktioniert es ja.

von Peter II (Gast)


Lesenswert?

Kilian K. schrieb:
> Wenn ich ja vorher
> nichts in die Datei schreibe funktioniert es ja.

dann kann es ja die Routine sein, die in die Datei schreibt.

Aber ohne den kompletten Quellcode können wir hier kaum helfen.

von Kilian K. (kellermaaan)


Angehängte Dateien:

Lesenswert?

Hab hier mal die 3 cpp Dateien angehängt. Hoffe das reicht. Vielleicht 
könnt ihr was erkennen oder finden!

von Hans Ulli K. (Gast)


Lesenswert?

Es gibt da ein genial einfaches Debugging Tool und es ist sogar in dem 
Compiler eingebaut.

-> printf()

SCNR

von Bodo (Gast)


Lesenswert?

Um die main zu durchforsten braucht man ja so etwas:

http://i.auto-bild.de/ir_img/1/0/6/3/5/0/4/Cat-6090-543x373-9ea533117d4013c1.jpg

von Bodo (Gast)


Lesenswert?

Außerdem fehlt da einiges, z.B. Header. Zippe doch einfach das Projekt 
(die Debug- und Release-Verzeichnisse sowie die sdf-Datei (*) vorher 
löschen) und lade es hoch.

(*) Wird beim Laden des Projekts automatisch wieder erzeugt.

von Kilian K. (kellermaaan)


Angehängte Dateien:

Lesenswert?

So hier mal das gezippte Projekt.

: Bearbeitet durch User
von Hans Ulli K. (Gast)


Lesenswert?

Was hält dich davon ab in main.cpp die Funktion main() nicht zu 
unterteilen ???

> //Funktion zum ändern der Vokabel
> void Schnittstelle::Vokabeln_aendern(int nummer, char* deutsch, char* englisch, 
int richtige)
> {
>  //Eingabe prüfen, ob die Vokabeln nur Strings sind
>  if (!check_isstring(deutsch))
>  {
>    _fehler = 1;
>  }
>  if (!check_isstring(englisch))
>  {
>    _fehler = 1;
>  }
>
>  //wenn alles Inordnung ist werden die Vokabeln getauscht
>  if (_fehler == 0)
>  {

Ist _fehler Global ??, dann ist das ein Fehler !!
Was fehlt hier noch ???
Deine Funktion kann den Fehler als return Wert liefern

Bei den anderen Funktionen ist es genau so.
> //Funktion zum erfassen und holen der Anzahl
> struct Anzahl Schnittstelle::get_anzahl(void)
> {
>  //Zwischenspeicher deklarieren
>  Anzahl anzahl_dummy;
>     ...
>
>  //Anzahl wird zurückgegeben
>  return anzahl_dummy;
> }

Was gibst du hier zurück ??
Gab es hier einen Compilerfehler/Warnung, wenn ja warum ??
Für eine Anzahl kann auch int/long usw. benutzt werden ...

> //Funktion, falls es einen Fehler gab, diesen dann zurückzugeben
> int Schnittstelle::get_fehler(void)
> {
>  //Rückgabe des Fehlers
>  return _fehler;
> }
>
> //Funktion zum reseten der Fehlervaraiblen
> void Schnittstelle::reset_fehler()
> {
>  _fehler = 0;
> }

Potentiell mit Fehler behaftet

Und noch eine Bitte :
Brauchst du wirklich den Unterschrich am Anfang von Variablennamen, nur 
um zu wissen welche global und welche lokal sind  ??

von Kilian K. (kellermaaan)


Lesenswert?

Hans Ulli Kroll schrieb:
> Ist _fehler Global ??, dann ist das ein Fehler !!
> Was fehlt hier noch ???
> Deine Funktion kann den Fehler als return Wert liefern

Hier gebe ich dir recht, das könnte man besser machen...

Hans Ulli Kroll schrieb:
> Was gibst du hier zurück ??
> Gab es hier einen Compilerfehler/Warnung, wenn ja warum ??
> Für eine Anzahl kann auch int/long usw. benutzt werden ...

Hier muss ich ja eine Struktur zurückgeben, da ich zwei Werte brauche 
und da mit Pointern zu arbeiten habe ich mir gespart.

Hans Ulli Kroll schrieb:
> Und noch eine Bitte :
> Brauchst du wirklich den Unterschrich am Anfang von Variablennamen, nur
> um zu wissen welche global und welche lokal sind  ??

Da halte ich mich nur an die Vorschriften von meinem Prof + Mitarbeiter!

von Peter II (Gast)


Lesenswert?

Der fehler ist hier:

_my_datei.read((char*)(_my_vokabeln), sizeof(struct Vokabeln));

aus irgendeinem Grund ist _my_vokabeln nicht initialisiert. Sie zeigt 
ins nichts. Damit überschreibst du wild Speicher.

Der Code ist sehr unübersichtlich und schwer zu verstehen.

von Bodo (Gast)


Lesenswert?

Kilian K. schrieb:
>> Brauchst du wirklich den Unterschrich am Anfang von Variablennamen, nur
>> um zu wissen welche global und welche lokal sind  ??
>
> Da halte ich mich nur an die Vorschriften von meinem Prof + Mitarbeiter!

Namen, die mit einem Unterstrich und einem kleinen Buchstaben beginnen, 
sind zwar außerhalb des globalen Namensraums "erlaubt", aber es ist 
Usus, so etwas zu vermeiden (da es nur eine kleine Ausnahme ist). Aber 
wenn dein Prof. es so will, mache es trotzdem.

von Yalu X. (yalu) (Moderator)


Lesenswert?

Kilian K. schrieb:
> Hans Ulli Kroll schrieb:
>> Was gibst du hier zurück ??
>> ...
>
> Hier muss ich ja eine Struktur zurückgeben, da ich zwei Werte brauche
> und da mit Pointern zu arbeiten habe ich mir gespart.

Du gibst aber am Ende von zufalls_Vokabel garnichts zurück, nicht
einmal einen Pointer. Damit ist der Rückgabewert undefiniert, und der
Aufrufer wundert sich, was da für ein Quatsch kommt ;-)

Ich würde dir empfehlen, beim Compiler einen hohen Warning-Level
einzuschalten. Dann wirst du sehen, dass da noch viel mehr im Argen
liegt. Bspw. sind auch die Aufrufe von strcpy_s fehlerhaft.

von Peter II (Gast)


Lesenswert?

So hier das genaue Problem:

Schnittstelle::in_Datei(char* deutsch, char* englisch)
   ...
   Vokabeln temp;
   ...
   vokabeltrainer.set_my_vokabeln(temp);

   ->    _my_vokabeln = &temp;


damit zeigt _my_vokabeln  auf eine lokale Stackvariable, die ist dann 
später aber nicht mehr vorhanden und es knallt.

Den code muss man leider komplett neu schreiben, das ist kaum etwas zu 
retten.

von Hans Ulli K. (Gast)


Lesenswert?

Kilian K. schrieb:
> Hans Ulli Kroll schrieb:
>> Und noch eine Bitte :
>> Brauchst du wirklich den Unterschrich am Anfang von Variablennamen, nur
>> um zu wissen welche global und welche lokal sind  ??
>
> Da halte ich mich nur an die Vorschriften von meinem Prof + Mitarbeiter!

Dazu sage ich nichts ...
das ist der falsche Ansatz, weil es sollten nur notwendig Variablen als 
global benutzt werden.
Was passiert denn, wenn jemand ein Modul von deinem Code nimmt und es 
nicht weiss ??
Es kann ja mal vorkommen das beide den selben Namen und Type haben.

Auch die Namen sollten so kurz und einprägsam wie möglich sein.

Was ist besser ??

int zaehler_wort_index;
int i;

Und zu dr Struktur
> Hans Ulli Kroll schrieb:
>> Was gibst du hier zurück ??
>> Gab es hier einen Compilerfehler/Warnung, wenn ja warum ??
>> Für eine Anzahl kann auch int/long usw. benutzt werden ...
>
> Hier muss ich ja eine Struktur zurückgeben, da ich zwei Werte brauche
> und da mit Pointern zu arbeiten habe ich mir gespart.


> //Funktion zum erfassen und holen der Anzahl
>struct Anzahl Schnittstelle::get_anzahl(void)
>{
> //Zwischenspeicher deklarieren
> Anzahl anzahl_dummy;

dann mach das dort mit einem 'new'

Oder hole dir die Anzahl per Parameter zurück, z.B.
void Schnittstelle::get_anzahl(struct Anzahl *param)

von Yalu X. (yalu) (Moderator)


Lesenswert?

Hans Ulli Kroll schrieb:
> das ist der falsche Ansatz, weil es sollten nur notwendig Variablen als
> global benutzt werden.

Wo siehst du hier globale Variablen? Die mit den Unterstrichen sind
Membervariablen, also nur "halbglobal".

von Hans Ulli K. (Gast)


Lesenswert?

Das wäre auch möglich.

ich habe ja nicht die *.h Datei(n)
Und die zip Datei sehe ich mir aktuell nicht an ...

von Kilian K. (kellermaaan)


Lesenswert?

Tut mir leid wenn das Programm schlecht geschrieben ist aber bin ja noch 
am lernen!

Dank eurer Hilfe hab ich es trotzdem hinbekommen!!! Danke nochmal.

von Hans Ulli K. (Gast)


Lesenswert?

Kilian K. schrieb:
> Tut mir leid wenn das Programm schlecht geschrieben ist aber bin ja noch
> am lernen!
>
> Dank eurer Hilfe hab ich es trotzdem hinbekommen!!! Danke nochmal.

For the record :

Ich habe nicht dich kritisiert und/oder deine Ausbilder sondern nur was 
ich an Code gesehen habe.
Und dabei habe ich nicht alles gelesen, ich kann es auch gar nicht 
lesen.

Mein pattern matching ist auf den CodingStyle vom Linux Kernel 
optimiert.
Das war auch früher so, als ich mal studiert habe. Als ich mal den 
Hilfbremser für die Einführung in C gemacht habe ...

Und wenn hier über den Sinn oder Unsinn von goto in C diskutiert wird, 
da halte ich mich raus.
Ich benutze goto selber, aus bestimmten Gründen

-> lesbarkeit, locking usw.

Den Rest von mir findet man auf lkml, linux-arm usw.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.