new int-Array-Zugriffsproblem



  • Hallo,
    unten stehender Code funktioniert nicht.

    Der Compiler von MSVC++ 6.0 sagt nichts. Wenn ich den Debugger laufen lasse, hält er in der Zeile an, die ich kommentiert habe.

    Die Meldung:

    Unbehandelte Ausnahme in doering2.exe: 0xC000000: Access Violation.
    

    Es folgt ein Fenster "Quellcode suchen", in dem steht:

    Geben Sie den Pfad für STRLEN.ASM an
    

    Voreingestellt ist der Projektpfad mit anschließendem "\intel".

    Ich habe meinen Computer durchsucht, die Datei aber nicht gefunden.

    Ich weiß nicht, was ich falsch gemacht habe. Google konnte mir auch nicht helfen.

    Das einzige, das ich herausgefunden habe, ist, dass es funktioniert, wenn ich den Zeiger und nicht den Inhalt abrufe (was mir aber ziemlich wenig bringt, da ich den Inhalt brauche).

    Der Fehler ist kommentiert!

    Nun der Code:

    Zuerst die Header-Datei (wegen den Kommentaren):
    parse.h

    /*
    
      Autor:			Michael Etscheid
      Erstellt am:		24.01.2004
      Letzte Aenderung:	31.01.2004
      Kompilierbar mit:	Microsoft Visual C++ 6.0 Professional Edition
    
      Kurzbeschreibung: Wer kennt sie nicht? Die Aufgaben, bei denen die Rechenzeichen einzusetzen
      sind. Ein Mensch stoesst da schnell auf seine Grenzen. Deshalb wurde dieses Programm entwickelt.
      Es geht nacheinander alle moeglichen Rechenzeichen-Kombinationen durch, beachtet die Regel
      "Punkt vor Strich" und stoppt, wenn bei einer Division keine ganze Zahl herauskommt.
    
    */
    
    #ifndef PARSE_H
    #define PARSE_H
    
    #include <string>
    using namespace std;
    
    typedef string mist;
    
    unsigned int CountWhitespaces(string);	// Zaehlt die Leerzeichen (also, wie viele Rechenoperato-
    										// ren einzusetzen sind)
    
    int transform(string);					// wandelt die Strings zwischen den Leerzeichen in Zahlen
    										// um
    
    void initialize_part(int *, string);	// initialisiert alle int *part mit den vom User eingege-
    										// benen Zahlen
    
    void initialize_op(int *, unsigned int);// initialisiert alle Operatoren mit dem Startwert 1 (+)
    
    void accelerate(int *, unsigned int);	// erhoeht den letzten Operator um 1. wenn dieser den Wert
    										// 5 erreicht, wird er auf 1 zurueckgesetzt und der zweit-
    										// letzte um 1 erhoeht. Dies wird so lange wiederholt, bis
    										// es nicht mehr zutrifft
    
    inline mist add(int *, int *);			// hier werden zwei Teile addiert oder eine Fehlermeldung
    										// zurueckgegeben, wenn eine Bereichsueberschreitung auf-
    										// tritt
    
    inline mist sub(int *, int *);			// hier werden zwei Teile subtrahiert oder eine Fehlermel-
    										// dung zurueckgegeben, wenn eine Bereichsueberschreitung
    										// auftritt
    
    inline mist mul(int *, int *);			// hier werden zwei Teile multipliziert oder eine Fehler-
    										// meldung zurueckgegeben, wenn eine Bereichsueberschrei-
    										// tung auftritt
    
    inline mist divide(int *, int *);		// hier werden zwei Teile dividiert oder eine Fehlermel-
    										// dung zurueckgegeben, wenn bei der Division keine ganze
    										// Zahl herauskommt (dies wird durch eine Modulo-Division
    										// ueberprueft)
    
    int calc(int *, int *, int);			// Hier wird eine von parse() gegebene Aufgabe analysiert,
    										// es wird auf Punkt vor Strich geachtet und einzelne
    										// Teile an add()m sub(), mul() und div() uebergeben
    
    void parse(string, string);				// Hier wird die Benutzereingabe analysiert, zerteilt und
    										// jede einzelne moegliche Kombination von Rechenoperato-
    										// ren an calc() weitergegeben.
    
    #endif
    

    parse.cpp

    #include "parse.h"
    #include <cmath>	// pot()
    #include <sstream>	// stringstream
    #include <iostream>	// cout
    #include <string>	// string
    using namespace std;
    
    typedef string mist;
    
    typedef mist (*CalcOP)(int *, int *);
    CalcOP calc_op[4]={add,sub,mul,divide};
    
    unsigned int CountWhitespaces(string aufgabe)
    {
    	unsigned int counter=0;
    	int finde=aufgabe.find(" ", 0);
    	while(finde!=-1)
    	{
    		counter+=1;
    		finde=aufgabe.find(" ", finde+1);
    	}
    	return counter;
    }
    
    int transform(string a)
    {
    	int b;
    	stringstream S;
    	S<<a;
    	S>>b;
    	return b;
    }
    
    void initialize_part(int *part, string aufgabe)
    {
    	int finde=-1;
    	int alt=-1;
    	do
    	{
    		finde=aufgabe.find(" ", finde+1);
    		*part=transform(aufgabe.substr(alt+1, finde==-1 ? aufgabe.length()-alt-1 : finde-alt-1));
    		part++;
    		alt=finde;
    	}
    	while(finde!=-1);
    }
    
    void initialize_op(int *op, unsigned number)
    {
    	for(int i=0; i<number; ++i)
    		op[i]=0;
    }
    
    void accelerate(int *op, unsigned int number)
    {
    	op[number-1]+=1;
    	unsigned int i=1;
    	while(op[number-i]==4)
    	{
    		op[number-i]=0;
    		--i;
    		op[number-i]+=1;
    	}
    }
    
    inline mist add(int *a, int *b)
    {
    	if((*a)+(*b) > 2147483648)
    		return "Zahl zu gross!";
    
    	(*b)+=(*a);
    	return 0;
    }
    
    inline mist sub(int *a, int *b)
    {
    	if((*a)-(*b) < -2147483649)
    		return "Zahl zu klein!";
    
    	(*b)=(*a)-(*b);
    	return 0;
    }
    
    inline mist mul(int *a, int *b)
    {
    	if((*a)*(*b) > 2147483648)
    		return "Zahl zu gross!";
    
    	(*b)*=(*a);
    	return 0;
    }
    
    inline mist divide(int *a, int *b)
    {
    	if((*a)%(*b)!=0)
    		return "Division mit Rest";
    
    	(*b)=(*a)/(*b);
    	return 0;
    }
    
    int calc(int *part, int *op, int number)
    {
    		for(int i=0; i<number-1; ++i)
    		{
    			if(op[i]>1)    // hier tritt der Fehler auf!
    			{
    				cout << calc_op[op[i]](&part[i], &part[i+1]) << flush;
    				part[i]=0;
    				op[i]=1;
    			}
    		}
    		for(i=0; i<number; ++i)
    			cout << calc_op[op[i]](&part[i], &part[i+1]) << flush;
    
    		return part[number];
    }
    
    void parse(string aufgabe, string sresult)
    {
    	int result=transform(sresult);
    	unsigned int whites=CountWhitespaces(aufgabe);
    	int *op=new int[whites];
    	int *part=new int[whites+1];
    	initialize_op(op, whites);
    	initialize_part(part, aufgabe);
    	for(int i=0; i<pow(whites, 4); ++i)
    	{
    		accelerate(op, whites);
    		calc(part, op, whites);
    		for(int j=0; j<whites; ++j)
    			cout << part[j] << op[j] << flush;
    		cout << part[whites] << endl;
    	}
    	delete [] op;
    	delete [] part;
    }
    

    Ich danke für jeden Ratschlag.



  • Schau doch einfach mal im StackTrace "Call Stack" die Funktionsaufrufe an, dann weisst du zumindest mal, WO er abkackt. Du musst den Fehler schon eingrenzen, sonst kann man nur raten.
    btw, das ((*a)*(*b) > 2147483648 funktioniert so ganz sicher nicht. Du musst abfragen, ob das Ergebnis negativ geworden ist.



  • Wie guck ich im Stack Trace?

    Und zu deinem BTW: Es könnte doch mit static_cast<__int64> funktionieren, denn deins macht auch nicht, was es soll, weil negative Werte erlaubt sind.



  • Ich weiß nicht genau, was du meinst. Wenn du Assembler haben willst, bitte sehr:

    [EDIT] Assembler macht den Thread nur unnötig lang [/EDIT]



  • Zum ersten: Ein Debugger führt einen Stack Trace so dass du nachschauen kannst, welche Funktion welche aufgerufen hat, so dass du feststellen kannst, welche Funktion bei dir strlen aufruft (wo es offensichtlich kracht).
    Ich weiss jetzt nur nicht, wie man das bei VC++ 6 nachschaut aber es geht sicher. Das sieht bei mir in etwa so aus:

    ntdll.dll
    drawGame()
    mainLoop()
    WinMain()
    kernel32.dll

    Daraus wird erkennbar, dass z.B. WinMain() mainLoop() aufgerufen hat.

    Zum zweiten: Das casten ist langsam, dann kannst du gleich mit __int64 rechnen. Du musst doch nur die Vorzeichen prüfen. Wenn du zwei positive Zahlen multiplizierst, darf nichts negatives rauskommen.



  • Dann mus ich drei mal das Vorzeichen überprüfen. Ob das schneller geht, sei mal dahingestellt...



  • das stimmt vielleicht, aber wenn du in __int64 rechnest und 2mal hin und her castest, ist das bestimmt auch nicht schneller und dann kannst du gleich alles in __int64 machen und dir dein int sparen.
    Rechne dir halt mal aus, was der größtmögliche Wert sein könnte, mit dem du klar kommen musst.
    Ich wollte ja eigentlich eh nur sagen, dass deine Prüfung so nicht geht. 🙂



  • Optimizer schrieb:

    das stimmt vielleicht, aber wenn du in __int64 rechnest und 2mal hin und her castest,

    Ein Mal!

    Ich werde morgen oder so mal testen, was schneller geht. Hoffentlich antwortet auch einer auf meine Call Stack-Frage.



  • Mir fällt mal grad so auf: Ich hab das Problem schon eingegrenzt!

    Das hab ich nicht bemerkt, weil ich zu verbissen nach dem Call Stack gesucht habe.

    Ich hab den Fehler sogar schon oben kommentiert:

    CME386 schrieb:

    if(op[i]>1)    // hier tritt der Fehler auf!
    


  • Ersetze

    for(int i=0; i<number-1; ++i)
    

    durch

    for(int i=0; i<number-1; i++)
    

    .
    Bei deinem Statement wird die Schleifenvariable sofort inkrementiert, und nicht erst nach Durchlaufen der Schleife.



  • Dr. Schnuggles schrieb:

    Bei deinem Statement wird die Schleifenvariable sofort inkrementiert, und nicht erst nach Durchlaufen der Schleife.

    Bloedsinn



  • @Dr. Schneggles: Nicht nur das es Blödsinn ist: Der Fehler tritt schon beim ersten Schleifendurchlauf auf.

    Hier hab ich jetzt mal den Call Stack kopiert:

    Direkt vor der Zeile, in der der Fehler auftritt:

    calc(int * 0x00491bd0, int * 0x00491f90, int 2) line 117
    parse(std::basic_string<char,std::char_traits<char>,std::allocator<char> > {0x00491fd1 "1 2 3"}, std::basic_string<char,std::char_traits<char>,std::allocator<char> > {0x00490131 "6"}) line 142 + 17 bytes
    main() line 16 + 83 bytes
    mainCRTStartup() line 206 + 25 bytes
    KERNEL32! 77e614c7()
    

    Nach dem Fehler:

    strlen() line 78
    std::char_traits<char>::length(const char * 0x00000000) line 192 + 33 bytes
    std::basic_string<char,std::char_traits<char>,std::allocator<char> >::assign(const char * 0x00000000) line 152 + 38 bytes
    std::basic_string<char,std::char_traits<char>,std::allocator<char> >::basic_string<char,std::char_traits<char>,std::allocator<char> >(const char * 0x00000000, const std::allocator<char> & {...}) line 65 + 61 bytes
    add(int * 0x00491bd0, int * 0x00491bd4) line 79 + 14 bytes
    calc(int * 0x00491bd0, int * 0x00491f90, int 2) line 125 + 48 bytes
    parse(std::basic_string<char,std::char_traits<char>,std::allocator<char> > {0x00491fd1 "1 2 3"}, std::basic_string<char,std::char_traits<char>,std::allocator<char> > {0x00490131 "6"}) line 142 + 17 bytes
    main() line 16 + 83 bytes
    mainCRTStartup() line 206 + 25 bytes
    KERNEL32! 77e614c7()
    


  • Ich muss mich bei euch entschuldigen. Ich hab nämlich die falsche Zeile als fehlerhafte angegeben.

    Dadurch, dass die Bedingung beim ersten Funktionsaufruf nie erfüllt ist, ich aber den Haltepunkt in den Block nach dem if gesetzt habe, ist direkt die Fehlermeldung gekommen.

    Sie ist eigentlich in folgender Zeile:

    cout << calc_op[op[i]](&part[i], &part[i+1]) << flush;
    


  • Ich habs:

    Mein "return 0" hat er nicht geschluckt. Ich hab es durch 'return ""' ersetzt. Jetzt krieg ich zwar einen anderen Runtime-Error, aber den werde ich wohl alleine schaffen.

    Trotzdem Danke für deine Hilfe, Optimizer.



  • Das return 0; in deinen Berechnungsfunktionen ist das Problem. Es wird der std::string(const char*)-Konstruktor aufgerufen. Der versucht, die Länge des "Strings" festzustellen, und ruft strlen mit einem Nullzeiger auf.



  • @MFK: Danke, dass du auch vorbeigeschaut hast.

    @Optimizer: Das Vorzeichenproblem hab ich jetzt so gelöst:

    int i=0;
    	if((*a)<0)
    		i+=1;
    	if((*b)<0)
    		i+=1;
    	if((*a)+(*b)<0)
    		i+=1;
    	if(i%2)
    		return "Zahl zu gross!";
    
    int i=0;
    if(*a<0) i+=1;
    if(*b<0) i+=1;
    int j=0;
    if(*a<0) j+=1;
    if(*a-*b<0) j+=1;
    if(i%2 || *a>*b)
    {
        if(j%2) return "Zahl zu klein!";
    }
    else
    {
        if(j%2==0) return "Zahl zu klein!";
    }
    


  • Ähm ja, das ist auch ne Lösung. 😉
    Die würde ich aber fast besser kommentieren. 😃


Anmelden zum Antworten