Unbehandelter Ausnahmefehler, Null Pointer Exception



  • Hallo Zusammen,

    waehrend der Ausfuehrung mein MFC-Projekt bricht der Debugger mit "Unhandled exception at ... Access violation reading location.." ab. Die problematische Methode ist:

    void DemProdListDlg::fetchTableList(CString db_name){
    
    	CString* local_ptr;
    	int i= 0 ;
    
    	local_ptr = native_doc->getTables(db_name);
    
    	while(!local_ptr->IsEmpty()){
                    _cprintf("fetchTableList: string i:%d , ptr:%p, value:%s\r\n",
    			i, local_ptr, *local_ptr);
    
    		local_ptr++;
    		i++ ;
    	}
    		_cprintf("while of fetchTableList is ended\r\n");
    }
    

    dabei sieht die Signatur der Methode getTables so aus:

    CString* Cdb_guiDoc::getTables(CString db_name);
    

    getTables macht eine db-Abfrage und fuellt die CString array(all_tables) mit
    den Ergebnissen. Sie liefert einen Zeiger vom Typ CString zurueck. Die Ausgabe in der Konsole folgt wie:

    konsole schrieb:

    Delivered number of Results:2
    getTables: populating all_tables i:0, ptr:00369E2C value:product
    getTables: populating all_tables i:1, ptr:00369E30 value:werkzeug

    fetchTableList: string i:0 str_ptr:00369E2C value:product
    fetchTableList: string i:1 str_ptr:00369E30 value:werkzeug

    Das Problem liegt wohl an der Erhoehung des local_ptr Zeigers. Die while schleife erheoht den Zeiger obwohl es dem Programm nicht erlaubt ist, den Speicher zu lesen.

    Erste Frage: Kann ich die Ausnahmebehandlung-Kontrolle unter VStudio abschalten(Ich weiss, dass es keine gute Loesung ist!)?

    Zweite Frage: Wie kann ich ne Ausnahmebehandlung machen? Sowie ich bei meiner Recherche festgestellt habe, es gibt wohl keine NullPointerException oder ArrayOutOfBoundsException, die ich `catch`en kann.

    Danke im voraus,


  • Mod

    Was liefert nun getTables genau? CString*?

    Und wie allokierst Du den?



  • 1.)
    Wenn Du ein Pointer auf ein Array zurückgibts (getTables) musst Du auch zurückgeben wie viele Elemente das Array umfasst.

    2.) getTables könnte auch einen 0 Pointer zurückgeben. Prüfe das!

    if (local_ptr)
    {
       while(!local_ptr->IsEmpty())
       {
          _cprintf("fetchTableList: string i:%d , ptr:%p, value:%s\r\n", i, local_ptr, *local_ptr);
          local_ptr++;
          i++ ;
       }
    }
    

    Erste Frage: Kann ich die Ausnahmebehandlung-Kontrolle unter VStudio abschalten(Ich weiss, dass es keine gute Loesung ist!)?

    Für C++ Exceptions ja. Allerdings ist die Acces Violation eine SEH Exception, die können nicht abgeschaltet werden. Zudem "bringt" das nichts, da die Acces Violation ein ernsthaftes Problem darstellt!

    Zweite Frage: Wie kann ich ne Ausnahmebehandlung machen? Sowie ich bei meiner Recherche festgestellt habe, es gibt wohl keine NullPointerException oder ArrayOutOfBoundsException, die ich `catch`en kann.

    Nein, wenn Du Pointer Arithmetik verwendest (++local_ptr, etc.) dann bist Du verantwortlich, dass nicht über die Array Grenzen hinweg einen Zugriff erfolgt (Punkt 1.).

    Gruss Simon



  • Hallo Martin,

    Martin Richter schrieb:

    Was liefert nun getTables genau? CString*?

    Ja, getTables liefert ein CString* (siehe die Funktionssignatur in meiner ersten Posting).

    Martin Richter schrieb:

    Und wie allokierst Du den?

    mit:

    CString* Cdb_guiDoc::getTables(CString db_name){
    ..
    MYSQL* res = mysql_list_tables(db_handle);
    int element_anzahl = mysql_num_row(res) ;
    CString* all_tables = new CString[element_anzahl] ;
    ...
    }
    

    Gruss,



  • Hallo Simon,

    simon.gysi schrieb:

    1.)Wenn Du ein Pointer auf ein Array zurückgibts (getTables) musst Du auch zurückgeben wie viele Elemente das Array umfasst.
    ...
    Nein, wenn Du Pointer Arithmetik verwendest (++local_ptr, etc.) dann bist Du verantwortlich, dass nicht über die Array Grenzen hinweg einen Zugriff erfolgt (Punkt 1.).

    Dies verstehe ich nicht genau. Durch

    CString* all_tables = new CString[element_anzahl] ;
    

    habe ich dem Compiler mitgeteilt, wieviel Speicher insgesamt ich fuer diesen Pointer vorgesehen habe. Eine Inkrementierung ausserhalb der Grenzen muesste nicht moeglich sein.. Das System sollte automatisch dem Pointer eine NULL pointer zuweisen.

    simon.gysi schrieb:

    2.) getTables könnte auch einen 0 Pointer zurückgeben. Prüfe das!

    Du hast recht. In der Tat, meine erste Version von der Schleife war ja:

    while(local_ptr){...}
    

    Danke fuer die Antworten was Exceptions betrifft..
    Gruss,



  • habe ich dem Compiler mitgeteilt, wieviel Speicher insgesamt ich fuer diesen Pointer vorgesehen habe. Eine Inkrementierung ausserhalb der Grenzen muesste nicht moeglich sein.. Das System sollte automatisch dem Pointer eine NULL pointer zuweisen.

    Das ist falsch! Desshalb musst Du auch sowas in der folgenden Art machen:

    CString* Cdb_guiDoc::getTables(CString db_name, int& numOfTables){
    //...
    MYSQL* res = mysql_list_tables(db_handle);
    numOfTables = mysql_num_row(res) ;
    CString* all_tables = new CString[numOfTables] ;
    //...
    return all_tables;
    }
    

    Und dann iterierst Du mit einer for- Schleife über die Tables.

    Edit: Ich hoffe dieser Ausschnitt dient nur der Veranschaulichung. Prüfe Pointer bevor du sie benutzt!



  • Warum Benutzt Du nicht CStringArray, was für solche Fälle gedacht ist und gibst eine Referenz zurück, so brauchst Du nicht mit Zeigern rum zu spielen und und hast auch die Anzahl der Elemente des Array in der Rückgabe mit Berücksichtigt.

    Nur mal so als Tipp, denn CString selbst als Array Anzuordnen und dann noch einen Zeiger zurückzugeben ist gefährlich.

    Gruß Matthias



  • simon.gysi schrieb:

    Und dann iterierst Du mit einer for- Schleife über die Tables.

    Edit: Ich hoffe dieser Ausschnitt dient nur der Veranschaulichung. Prüfe Pointer bevor du sie benutzt!

    ok. Uebergabe der Referenzen(int &numOfTables) funktioniert. Pointerpruefung mache
    ich immer, danke fuer den Hinweis trotzdem.

    Gruss,



  • Hallo Matthias,

    CTecS schrieb:

    Warum Benutzt Du nicht CStringArray, was für solche Fälle gedacht ist und gibst eine Referenz zurück, so brauchst Du nicht mit Zeigern rum zu spielen und und hast auch die Anzahl der Elemente des Array in der Rückgabe mit Berücksichtigt.

    Nur aus dem Grund, dass ich die Anwesenheit solch angepasster Klasse nicht wusste :} . Ich habe gerade CObArray Klasse bei msdn gelesen. Die Klasse sieht maechtig aus, kann ich gut gebrauchen.

    CTecS schrieb:

    Nur mal so als Tipp, denn CString selbst als Array Anzuordnen und dann noch einen Zeiger zurückzugeben ist gefährlich.

    Was ist so gefaehrlich den [] operator und Referenzen mit CString Klasse zu benutzen? Bezeichnest du die Pointeraritmetik als gefaehrlich? Hast du da einen Link zum Vergleich zwischen CString Arrays und CStringArray(Ich bin nicht fuendig geworden...).

    Gruss,



  • Hast du da einen Link zum Vergleich zwischen CString Arrays und CStringArray(Ich bin nicht fuendig geworden...).

    Was willst Du denn da vergleichen?

    Was ist so gefaehrlich den [] operator und Referenzen mit CString Klasse zu benutzen?

    Nichts. Du musst halt wissen wie.

    Bezeichnest du die Pointeraritmetik als gefaehrlich?

    Tendenziell passieren mit der Pointeraritmetik und generell mit "rohen" Pointer mehr Fehler als ohne. Aber wie gesagt, wer weiss was er tut, der hat nichts zu befürchten.. 🙂

    Simon



  • Was willst Du denn da vergleichen?

    Ich glaube, die CString Klasse Vector Template verwendet. In Vector template
    sind einige Methoden implementiert, die auch bereits in CStringArray Klasse
    vorhanden sind(setElementAt(int i), getElementAt(int i) usw.). Es war fuer mich
    die Frage, was fuer extra Methoden in CStringArray zur Verfuegung gestellt
    werden, so dass man eine bewusste Entscheidung zwischen CString[] und CStringArray trifft.

    Was ist so gefaehrlich den [] operator und Referenzen mit CString Klasse zu benutzen?

    Nichts. Du musst halt wissen wie.

    wunderbar, kein Problem.

    Gruss,


Anmelden zum Antworten