Anfänger Problem - Zeiger
-
Hey...
ich bin noch ein Anfänger und hoffe ihr könnt mir helfen.
Ich habe eine einfache Kundenklasse. Der Vor und Nachname müssen leider Chararrays sein (Aufgabe) und dann noch eine Kundennummer.Es funktioniert alles perfekt. Die Setter und die Ausgabe.
Danach mache ich das "delete k" und printe k nochmal aus. (Klar geht nicht - aber er müsste dann "Kundendaten ungültig" ausgeben.
Tut er aber nicht. Es kommt zu einer Unbehandelten Ausnahme bei 0x5c5bd51.... Zugriffsverletzung beim Lesen an Position 0xfeeefeeeHabe mit dem Debugger beim 2. Print reingeschaut und gesehen, das die Kundennummer irgendein Wert hat (4277075694) und vor und nachname "0xfeeefeee <schlechtes Ptr>
Warum? Im Destruktor mache ich doch alles auf 0 und NULL... ?!
Bitte um hilfe -.-
// KUNDE.CPP Kunde::Kunde(char *vname, char *nname, int knr) { setVorname(vname); setNachname(nname); setKundennummer(knr); } Kunde::Kunde(const Kunde &k) { kundennummer = k.kundennummer; setVorname(k.vorname); setNachname(k.nachname); } Kunde::~Kunde() { cout << "Destruktor -- Kunde wird entfernt." << endl; delete [] vorname; vorname = NULL; delete [] nachname; nachname = NULL; nachname = 0; kundennummer = 0; } void Kunde::setKundennummer(int knr) { kundennummer = knr; } void Kunde::setVorname(char *vname) { if( vname != NULL ) { if( vorname != NULL ) { delete [] vorname; vorname = NULL; } vorname = new char[strlen(vname)+1]; strcpy(vorname, vname); } } void Kunde::setNachname(char *nname) { if( nname != NULL ) { if( nachname != NULL ) { delete [] nachname; nachname = NULL; } nachname = new char[strlen(nname)+1]; strcpy(nachname, nname); } } void Kunde::print() { if( vorname != NULL && nachname != NULL ) { cout << "Kundeninformationen: " << endl; cout << "Vorname: " << vorname << endl; cout << "Nachname: " << nachname << endl; cout << "Kundennummer: " << kundennummer << endl; } else { cout << "Kundendaten ungueltig!" << endl; } }// MAIN Kunde *k = new Kunde(); k->setKundennummer(1); k->setNachname("kk nachname"); k->setVorname("kk vorname"); k->print(); delete k; k->print();// KUNDE.H class Kunde { public: Kunde() : kundennummer(0), vorname(NULL), nachname(NULL) {}; Kunde(char *vname, char *nname, int knr); Kunde(const Kunde &k); ~Kunde(); void setKundennummer(int knr); void setVorname(char *vname); void setNachname(char *nname); void print(); private: unsigned int kundennummer; char *vorname; char *nachname; };
-
Du darfst auf ein gelöschtes Objekt nicht mehr zugreifen. Nachdem du delete aufrufst, wird der Destruktor deines Objekts aufgerufen und dein Objekt zerstört, sowie der Speicher freigegeben. Alles, was du danach versuchst, mit dem "Objekt" zu machen erzeugt undefiniertes Verhalten.
-
Aber ich setzte extra den Zeiger nochmal auf NULL.
Kann ich ihn dann bzw. darf ich ihn dann trotzdem nicht mehr ansprechen?
UND
Gerade sehe ich das mein CopyKonstruktor auch nicht funktioniert. Selbes Problem....... verstehe ich nicht..
-
Kunde* k = new Kunde; delete k; // Ab hier darfst du mit k nichts mehr machen! k->something(); // Peng!
-
shwN schrieb:
Aber ich setzte extra den Zeiger nochmal auf NULL.
Kann ich ihn dann bzw. darf ich ihn dann trotzdem nicht mehr ansprechen?
UND
Gerade sehe ich das mein CopyKonstruktor auch nicht funktioniert. Selbes Problem....... verstehe ich nicht..
A) Ja darfst Du. Es erzeugt aber ein undefiniertes verhalten. Fazit: Nicht machen!
Das gleiche !grüüüße
----------------------------------Vereinfachtes problem:
int* i=0; *i=1; //uuups
-
Ich vermute, dass
delete k;in deinem Fall nicht nur den Speicher freigibt, sondern ihn vorher auch mit einem einfach erkennbaren Muster überschreibt (0xfeeefeee), um undefiniertes Verhalten dieser Art möglichst sofort aufzudecken. MSVC, von dem ich aufgrund der Meldung des Debuggers vermute, dass du ihn benutzt, macht so was im Debug-Modus.
-
Danke für eure Antworten.
Aber wieso erzeugt dieser Code das selbe...
// Main Kunde *kk = new Kunde("kk vorname", "kk nachname", 2); kk->print();
-
void Kunde::setVorname(char *vname) { if( vname != NULL ) { if( vorname != NULL ) { delete [] vorname; vorname = NULL; } vorname = new char[strlen(vname)+1]; strcpy(vorname, vname); } }Das ist der Setter wo er rausspringt.
Habe beim debuggen gesehen das vorname nicht NULL ist sondern dieser komische Wert. Und dann beim delete fliegt er natürlich raus.Das hier ist aber so gemeint... if vorname != NULL... wenn z.B. schon MustermannMax drinsteht etc. dann erst löschen und dann neu anlegen...
???
Bitte um hilfe...
Und danke für hilfe ^^
-
Weil du im Ctor deiner variablen nicht initialisierst,...
//Kunde.h class Kunde { public: Kunde() ; Kunde(char *vname, char *nname, int knr); Kunde(const Kunde &k); ~Kunde(); void setKundennummer(int knr); void setVorname(char *vname); void setNachname(char *nname); void print(); private: unsigned int kundennummer; char *vorname; char *nachname; };//kunde.cpp Kunde::Kunde(): kundennummer(0), vorname(NULL), nachname(NULL) {}; Kunde::Kunde(char *vname, char *nname, int knr): kundennummer(0), vorname(NULL), nachname(NULL) { setVorname(vname); setNachname(nname); setKundennummer(knr); } Kunde::Kunde(const Kunde &k): kundennummer(0), vorname(NULL), nachname(NULL) { kundennummer = k.kundennummer; setVorname(k.vorname); setNachname(k.nachname); }grüüüße
-
Gewöhnt euch an, 0 (oder in C++0x nullptr) zu verwenden. Das hier ist C++, nicht C.
-
JAAAAAAAAAAAAAAAAAAAAAA
danke.. ^^
das war es echt... ich wär da nie drauf gekommen..
-
MSDN schrieb:
nullptr is only valid when compiling with /clr (Common Language Runtime Compilation).
Ich behaupte mal jetzt nicht NULL ist 0, dafür bekomme ich bestimmt
einen auf den deckel.Aber ich vermute mal, dass es mir eigentlich völlig schnuppe sein kann,...
..gerade weil alle zeiger auf dem gleichen system die gleiche breite haben....//bei der gleichen addressbreite wird beides gleich behandelt #define NULL 0 __int64 *pi64=NULL; __int32 *pi32=NULL; __int64 *pi64_2=0; __int32 *pi32_2=0; //hier dann nicht mehr, aber die interpretation von null über den //zuweisungsoperator einer constanten wird der richtige typ vom compiler gewählt __int64 i64=NULL; __int32 i32=NULL; __int64 i64_2=0; __int32 i32_2=0;das kann man hier schon sehen:
//bei der gleichen addressbreite wird beides gleich behandelt #define NULL 0 __int64 *pi64=NULL; 0041158D mov dword ptr [ebp-14h],0 __int32 *pi32=NULL; 00411594 mov dword ptr [ebp-20h],0 __int64 *pi64_2=0; 0041159B mov dword ptr [ebp-2Ch],0 __int32 *pi32_2=0; 004115A2 mov dword ptr [ebp-38h],0 //hier dann nicht mehr, aber die interpretation von null über den //zuweisungsoperator einer constanten wird der richtige typ vom compiler gewählt __int64 i64=NULL; 004115A9 mov dword ptr [ebp-48h],0 004115B0 mov dword ptr [ebp-44h],0 __int32 i32=NULL; 004115B7 mov dword ptr [ebp-54h],0 __int64 i64_2=0; 004115BE mov dword ptr [ebp-64h],0 004115C5 mov dword ptr [ebp-60h],0 __int32 i32_2=0; 004115CC mov dword ptr [ebp-70h],0grüüüße
-
- nullptr ist ein Schlüsselwort in C++0x und hat genau den Zweck, kann aber keinem int, char, etc zugewiesen werden, ist also nicht castbar nach nicht-pointer Typen.
Beispiel:
void f(int); void f(int*); int main() { f(nullptr); // OK f(0); // Welche Funktion aufrufen? f(NULL); // - || - }- NULL ist unleserlich.
- nullptr ist ein Schlüsselwort in C++0x und hat genau den Zweck, kann aber keinem int, char, etc zugewiesen werden, ist also nicht castbar nach nicht-pointer Typen.
-
Hi Pi E+014,
A) nutzt man einen MSVC Compiler, so ist nullptr nur mit dem flag /clr verfügbar
(Ich progge nativ...)
0 wird in deinem beispiel als ein int interpretiert, und nicht als 0 zeigerC)
nullptr heißt " null pointer" , also "nullptr indicates that an object handle,
interior pointer, or native pointer type does not point to an object"
und damit wird foo(int)* aufgerufen, ein äquivalent zu foo((int)0)*.Dadurch wird n bisschen was erleichtert und nullptr ist ja denn auch gehighlighted.
Da gebe ich Dir recht.D) naja,.. das NULL unleserlich ist...

grüüüße
-
zeusosc schrieb:
0 wird in deinem beispiel als ein int interpretiert, und nicht als 0 zeigerDas Beispiel war falsch, sorry.
Richtig:void f(long); void f(int*); ... f(NULL); f(0); f(nullptr);zeusosc schrieb:
C)
nullptr heißt " null pointer" , also "nullptr indicates that an object handle,
interior pointer, or native pointer type does not point to an object"
und damit wird foo(int)* aufgerufen, ein äquivalent zu foo((int)0)*.Habe nie was anderes behauptet.
zeusosc schrieb:
D) naja,.. das NULL unleserlich ist...

Wie ich schon irgendwo geschrieben hab, NULL ist aus C und bleibt am besten dort.
-
314159265358979 schrieb:
Das Beispiel war falsch, sorry.
Richtig:void f(long); void f(int*); ... f(NULL); f(0); f(nullptr);Jo gutes beispiel.
grüüüüße

-
314159265358979 schrieb:
- NULL ist unleserlich.
So ein Quatsch. NULL ist für Zeiger natürlich leserlicher als 0.
-
_matze schrieb:
314159265358979 schrieb:
- NULL ist unleserlich.
So ein Quatsch. NULL ist für Zeiger natürlich leserlicher als 0.
NULL muss vor allem nicht 0 sein und das ist in C++ ein wichtiger Unterschied. Deshalb sollte man 0 nehmen, wenn man 0 meint.
-
shwN schrieb:
Hey...
ich bin noch ein Anfänger und hoffe ihr könnt mir helfen.
Ich habe eine einfache Kundenklasse. Der Vor und Nachname müssen leider Chararrays sein (Aufgabe) und dann noch eine Kundennummer.
...// KUNDE.CPP Kunde::Kunde(char *vname, char *nname, int knr) { setVorname(vname); setNachname(nname); setKundennummer(knr); } Kunde::Kunde(const Kunde &k) { kundennummer = k.kundennummer; setVorname(k.vorname); setNachname(k.nachname); } Kunde::~Kunde() { cout << "Destruktor -- Kunde wird entfernt." << endl; delete [] vorname; vorname = NULL; delete [] nachname; nachname = NULL; nachname = 0; kundennummer = 0; } void Kunde::setKundennummer(int knr) { kundennummer = knr; } void Kunde::setVorname(char *vname) { if( vname != NULL ) { if( vorname != NULL ) { delete [] vorname; vorname = NULL; } vorname = new char[strlen(vname)+1]; strcpy(vorname, vname); } } void Kunde::setNachname(char *nname) { if( nname != NULL ) { if( nachname != NULL ) { delete [] nachname; nachname = NULL; } nachname = new char[strlen(nname)+1]; strcpy(nachname, nname); } } void Kunde::print() { if( vorname != NULL && nachname != NULL ) { cout << "Kundeninformationen: " << endl; cout << "Vorname: " << vorname << endl; cout << "Nachname: " << nachname << endl; cout << "Kundennummer: " << kundennummer << endl; } else { cout << "Kundendaten ungueltig!" << endl; } }// KUNDE.H class Kunde { public: Kunde() : kundennummer(0), vorname(NULL), nachname(NULL) {}; Kunde(char *vname, char *nname, int knr); Kunde(const Kunde &k); ~Kunde(); void setKundennummer(int knr); void setVorname(char *vname); void setNachname(char *nname); void print(); private: unsigned int kundennummer; char *vorname; char *nachname; };Bist Du Dir sicher, dass die Klasse so aussehen soll? Ich kann's nämlich nicht ganz glauben. Die einzige Erklärung, es so zu machen, wäre höchstens zu Lehrzwecken als Negativbeispiel ... mit dem Ziel der Wertschätzung von std::string. Wenn nämlich char* sich nicht so verhält, wie Du es gerne hättest, dann macht es mehr Sinn einen eigenen Typen für diese Datenelemente zu konstruieren (std::string) statt die Kopiersemantik in der Klasse Kunde anzupassen.
Steht in der Aufgabenstellung nur "char Array" oder auch was davon, dass Du Zeiger speichern sollst und den Speicher dynamisch allozieren sollst? Alternativ könnte man nämlich Arrays mit fixer Länge als Datenelemente verwenden. Das ist zumindest ein populärer Ansatz; denn so (mit char*) musst Du Deiner Klasse entsprechende Operationen selbst definieren (den Zuweisungsoperator hast Du übrigens vergessen).
kk
-
zeusosc schrieb:
..gerade weil alle zeiger auf dem gleichen system die gleiche breite haben....
Eine solche Garantie macht der C++ Standard nicht, auch nicht, wenn man sich auf "Objekt-Zeiger" beschränkt und Member-Pointer sowie Funktionszeiger außen vor lässt. Es soll Maschinen geben, bei denen 1=sizeof(int*)<sizeof(char*) gilt.
zeusosc schrieb:
//bei der gleichen addressbreite wird beides gleich behandelt #define NULL 0 __int64 *pi64=NULL; __int32 *pi32=NULL; __int64 *pi64_2=0; __int32 *pi32_2=0; //hier dann nicht mehr, aber die interpretation von null über den //zuweisungsoperator einer constanten wird der richtige typ vom compiler gewählt __int64 i64=NULL; __int32 i32=NULL; __int64 i64_2=0; __int32 i32_2=0;
btw: Hier gibt es keine Zuweisungen. Das sind Initialisierungen. Der Unterschied: Bei einer Zuweisung gibt es das Ziel-Objekt schon vorher.zeusosc schrieb:
das kann man hier schon sehen:
...Ich verstehe nicht Deine Obsession bzgl Implementierungsdetails des Compilers von Microsoft.
kk