Anfänger ( Zeiger / Pointer )



  • Warum muss es ausgerechnet char sein? Warum kein std::string?

    Edit: Und warum struct, das Ganze ist viel sinnvoller in einer Klasse untergebracht.



  • So is es als Aufgabe.
    Ich lern das grad und wir sollen jetzt C-Strings lernen -.- ^^

    Oder vllt. kannst du mir einfach grob erklären.. weil ich versteh das noch nich.

    wenn das char array nicht NULL ist... muss man es zuerst löschen und den Zeiger auf NULL setzen.
    Aber in deiner copyneuKunde funktion ist gar kein delete etc. drin.
    Oder macht das iwas anderes von alleine oder... ?!

    Oder das hier:

    void setneuKunde(int knr, float betrag, char *name, neuKunde *k)
    {
    	k->knr = knr;
    	k->betrag = betrag;
    
    	if( k->name != NULL )
    	{
    		delete [] k->name;
    		*k->name = NULL;
    	}
    
    	strcpy(k->name, name);
    }
    

    Funktioniert auch nicht, bestimmt wegen dem Delete!?
    Aber wir sollen den Speicher aufräumen und neu allokieren usw.
    Ich glaube das is hier das Problem.



  • wie oben schon beschrieben dir fehlt eine Abfrage:

    void copyneuKunde(const neuKunde *von, neuKunde *nach) 
    { 
        if( nach->name != NULL ) 
        { 
            delete [] nach->name; 
            nach->name = NULL; 
        }
    
    	if(von->name != NULL)
    	{
    		nach->name = new char[strlen(von->name + 1)]; 
    		strcpy(nach->name, von->name);
    	}
    	else
    	{
    		nach->name = new char[100];
    		nach->name = "test";
    	}
    
        nach->knr = von->knr; 
        nach->betrag = von->betrag; 
    }
    

    Edit: Bei deiner letzten Funktion fehlt wieder das new!



  • Danke für deine Hilfe !!

    Habs jetzt so.
    Funktioniert jetzt eigentlich auch soweit.

    Kann ich irgendwie prüfen, ob der Speicher auf wirklich freigegeben wurde wenn ich mittels deleteneuKunde() einen Kunden lösche?

    void setneuKunde(int knr, float betrag, char *name, neuKunde *k)
    {
    	if(k->name != NULL)
    	{
    		delete [] k->name;
    		k->name = NULL;
    	}
    	k->name = new char[strlen(name)+1];
    	strcpy(k->name,name);
    	k->knr = knr;
    	k->betrag = betrag;
    }
    
    void copyneuKunde(const neuKunde *von, neuKunde *nach)
    {
        if( nach->name != NULL )
        {
            delete [] nach->name;
            nach->name = NULL;
        }
    
        if(von->name != NULL)
        {
            nach->name = new char[strlen(von->name + 1)];
            strcpy(nach->name, von->name);
        }
        else
        {
            nach->name = new char[100];
            nach->name = "test";
        }
    
        nach->knr = von->knr;
        nach->betrag = von->betrag;
    }
    
    void deleteneuKunde(neuKunde *k)
    {
    		k->betrag = 0.0;
    		k->knr = 0;
    		delete [] k->name;
    		*k->name = NULL;
    }
    


  • Schau mal auf Zeile 42, da ist noch ein Fehler. Der Zeiger muss NULL werden und nicht der Wert.



  • Stimmt !!

    Danke, funktioniert so.

    Ich denk mal das funktioniert auch richtig das er den Speicher löscht usw... !?

    Danke dir !! :xmas1:



  • Sofern du void deleteneuKunde(neuKunde *k) und delete k; machst ja, nur delete k wird nicht reichen. Eventuell überlegst du dir noch wie du den Programmabsturz bei setneuKunde() vermeidest, wenn ein char* = NULL übergeben wird.(Tipp auf NULL prüfen.)



  • Ja stimmt, würde ich einfach so machen...
    Und wenn NULL übergeben wird.. dann wird halt gar nichts gemacht.. gibt ja dann nichts zum setten...

    void setneuKunde(int knr, float betrag, char *name, neuKunde *k)
    {
        if( k != NULL )
        {
            k->knr = knr;
            k->betrag = betrag;
            if( k->name != NULL )
            {
                delete [] k->name;
                *k->name = NULL;
            }
            strcpy(k->name, name);
        }
    }
    


  • currency schrieb:

    Und wenn NULL übergeben wird.. dann wird halt gar nichts gemacht.. gibt ja dann nichts zum setten...

    Ist das wirklich sinnvoll? Gibt es Situationen, in denen der Benutzer NULL übergibt, um nichts zu tun?

    Ich habe eher das Gefühl, du willst damit Fehler vermeiden, die durch Nullzeiger-Dereferenzierung entstehen. Tatsächlich erreichst du aber das Gegenteil: Wenn NULL als Parameter zulässig ist und einfach nichts passiert, können sich Logikfehler einschleichen. Denn du merkst nicht unmittelbar, dass ein gewünschter Aufruf keinen Effekt hat. Zudem verleitet diese Semantik dazu, es im Anwendercode mit Nullzeigern ebenfalls nicht so genau zu nehmen.

    Und dabei haben wir die Tatsache gar noch nicht berücksichtigt, dass die vielen If-Abfragen den Code unnötig hässlich machen.

    Deshalb: Gültigkeit des Zeiger als Precondition voraussetzen. Damit du solche Fehler gleich bemerkst, kannst du Assertions einsetzen:

    void setneuKunde(int knr, float betrag, char *name, neuKunde *k)
    {
        assert( k != NULL );
        // Restlicher Code (ohne if) wie bisher
    }
    


  • Übrigens: Der Code ist grauenhaft. Du solltest wissen, dass man C++ nicht so programmiert. Was du machst ist C-Code, der in Klassen eingepackt ist. Und dann ist es noch schlechter C-Code. Nimm das nicht persönlich, aber es gibt nichts Schlimmeres, als sowas schönzureden. 😉

    Damit du mit dieser Aussage auch was anfangen kannst, hier ein paar Verbesserungsvorschläge. Ich verstehe, falls du gewisse Dinge hiervon noch nicht kennst, aber du könntest dir diese für später merken oder wieder einmal zu diesem Thread zurückkehren. Denn es handelt sich um Punkte, die in C++ zu den essentiellen Grundlagen gehören.

    • Verwende Code wieder. Innerhalb copyneuKunde kannst du zum Beispiel deleteneuKunde aufrufen, um den Zielkunden zu überschreiben.
    • Klassen sind unter Anderem gerade dazu da, externe Funktionen zur Implementierung trivialer Funktionalität wie dem Kopieren eines Objekts zu vermeiden. Du wirst sicher noch was von Konstruktor, Kopierkonstruktor, Zuweisungsoperator und Destruktor hören.
    • Grundsätzlich wird in modernem C++ manuelle Speicherverwaltung vermieden, wo es nur geht, und durch Konzepte wie RAII abgelöst. Auch die Zeichenkettenverwaltung mit C-Strings ist inhärent fehleranfälig und unkonfortabel. In C++ gäbe es dafür std::string .
    • Dazu gibts noch kleinere Fehler, die mit dem gerade erwähnten Punkt zusammenhängen. Zum einen hast du bei
    delete [] k->name; 
    *k->name = NULL;
    

    eine Dereferenzierung zu viel, zum anderen darfst du nicht mit

    strcpy(k->name, name);
    

    in einen Nullzeiger kopieren. Und hier

    nach->name = new char[100];
    nach->name = "test";
    

    hast du ein Memory Leak, weil du gleich nach->name überschreibst.

    Was mich hingegen eher erstaunt, ist, dass du bereits Const-Correctness (bei copyneuKunde() ) richtig anwendest. Das beachten viele Leute, die C++ lernen, eher spät.


Anmelden zum Antworten