Problemsammlung zum Knobeln? <-> Nettes kleines Anfängerproblem...



  • Da man als Anfänger am besten aus Fehlern lernt und uns allen immer wieder üble Fehler passieren, welche, seien sie auch noch so klein, ganz üble Auswirkungen haben können.

    Da ich heute mal wieder so einen Fehler gemacht habe und ich (bin auch Anfänger) einige Zeit damit beschäftigt war, die Ursache zu finden, hab ich mir gedacht, das hier im Forum unter Umständen ein Thread mit einer kleinen Problemsammlung für Anfänger ganz nützlich wäre.

    Ich stelle mir das so vor:

    -> Ihr macht beim Programmieren einen Fehler, den ihr sehr lange suchen musstet, und bei dem nicht auf den ersten Blick klar war, was denn nun falsch war (nicht Banalitäten wie Semikolon vergessen).
    -> Versucht den Fehler auf ein kurzes Beispiel zu reduzieren.
    -> Postet es hier als Knobelaufgabe!

    [EDIT: "Problem" entfernt (HAHA! Problem lag an anderer Stelle als gedacht, wie peinlich ... 🙄 )]

    [ACHTUNG: Hier werden KEINE Probleme gepostet, deren Lösungen ihr selbst noch nicht gefunden habt.]



  • In deinem Beispiel fehlt eine wichtige Angabe.
    Wie ist buffer deklariert?
    Ist buffer ausreichend groß?

    Und bitte nutze doch C/C++-Tags, dass lässt sich sich einfach angenehmer mit Syntax-Highlighting lesen.



  • Ja richtig. Das wäre wichtig, aber das Problem ist ähm, nunja, Fehlerhaft, die Lösung, welche ich gefunden hatte, löste das Problem aus einem ganz anderen Grund als zuerst angenommen... Daher entfernt. Richtige Probleme willkommen... 🙂



  • dann poste doch dein Problem vielleicht können wir dir helfen dieses zu lösen 😉



  • Haha, neh, das Problem ist gelöst, aber eben anders als ich gedacht habe. Habe nun die richtige Lösung gefunden. 🙂

    Das Problem ist so banal dass ich es hier unmöglich posten könnte... 🙂



  • so, jetzt aber mal ein richtiges Problem:

    vector_t *fnGetVector(vector_t *pVList, int iVectI)
    {
    	vector_t *pVector;
    	for (pVector = pVList; pVector != NULL; pVector = pVector->pNext);
    	{
    		if (pVector->iVectI == iVectI)
    			return pVector;
    	} // for
    	return NULL;
    } // fnGetVector
    

    Der Fehler dürfte schnell gefunden sein. Interessant ist aber, dass er, völlig unabhängig davon, wie pVList (eine dynamische Liste) definiert ist (vorausgesetzt sie ist nicht zyklisch), immer eine "Segmentation Fault" provoziert.



  • Vielleicht steh ich nur auf dem Schlauch aber ich finde den Fehler nicht. Könntest du ihn mal genauer erklären?



  • Hehe, jaja es sind immer die ganz kleinen, dummen Fehler, die einem Kopfzerbrechen bereiten. Wer den Fehler nicht findet soll sich Zeile 4 genauer ansehen und sich fragen, welche Auswirkungen diese Zeile auf die folgenden Zeilen hat.

    ------------------------------------------------------------

    Lösung:

    for (pVector = pVList; pVector != NULL; pVector = pVector->pNext);
    

    Hier ist am Ende ein Semikolon zu viel. Dies führt dazu, dass die dynamische Liste durchlaufen wird, ohne das etwas gemacht wird. Zum Ende hat pVector den Wert NULL (Abbruchbedingung).

    Interessant ist nun, dass nun aber der Code in Zeile 6 ausgeführt wird, welcher (pVector hat den Wert NULL) eine Segmentation Fault hervorruft.



  • isam2k wrote: "-> Ihr macht beim Programmieren einen Fehler, den ihr sehr lange suchen musstet, und bei dem nicht auf den ersten Blick klar war, was denn nun falsch war (nicht Banalitäten wie Semikolon vergessen)."

    isam2k wrote: Lösung : "Hier ist am Ende ein Semikolon zu viel."

    AIG

    ALLES IST GUT 🙂



  • *facepalm* Bin ich so blöd.
    Aber das sind wirklich Fehler bei denen man lange grübelt bis man sie findet (Der Debugger hilft da viel)



  • isam2k schrieb:

    Hier ist am Ende ein Semikolon zu viel.

    Ich könnte wetten, dass es vorhin noch nicht da war 😉

    Habe es auch total übersehen...


  • Mod

    linux_c89 schrieb:

    *facepalm* Bin ich so blöd.
    Aber das sind wirklich Fehler bei denen man lange grübelt bis man sie findet (Der Debugger hilft da viel)

    Oder auch ein Compiler. Es gibt da so etwas wie Warnungen...



  • Mein Compiler gab keine Warnung. ist aber auch vc6



  • Naja bei sowas warnt der Compiler aber nicht. Also zumindest das hier geht ohne Warnung

    int main()
    {
    	int i=5;
    	while(i) ;
    		i--;
    	return 0;
    }
    

    Mit aufruf

    gcc -Wall test.c
    

    ich meine so eine Konstruktion kann doch Absicht sein, wieso sollte er warnen? Ich denke da an sowas

    int main()
    {
            int i=0;
            while(i--);
                    /*was auch immer */
            return 0;
    }
    

    Ein Compiler der mich vor sowas warnt kommt in die Tonne (und die Einrückung beim Kommentar würde ich natürlich nicht machen, hier gehts nur um Analogie zum 1. Beispiel)



  • Ich bin mal verzweifelt warum eine Funktion nicht richtig funktioniert hat. Ich habe Code umgestellt und so weiter... Irgendwann hatte ich die Lösung: Ich hab einfach vergessen die Funktion aufzurufen...



  • Blind ... schrieb:

    isam2k schrieb:

    Hier ist am Ende ein Semikolon zu viel.

    Ich könnte wetten, dass es vorhin noch nicht da war 😉

    Habe es auch total übersehen...

    daaas semikolon war da 🙂

    @niggelchen: ja ich weiss, hab auch gezögert, aber als ich den fehler zum ersten mal bemerkte dacht ich einfach: "ja schön, ein semikolon zu viel", um dann aber drauf zu kommen warum hier jedesmal eine segmentation fault ausgegeben wurde musst ich noch lange grübeln (anfänger halt).
    aufgrund der struktur des codes hat es mich sehr verwundert, dass ohne warnung einfach bei zeile 6 weitergemacht wird.
    hab schlussendlich 2 stunden damit verbracht in meinem code nach einer stelle zu suchen, an der ich das attribut pNext nicht richtig mit NULL oder einer existierenden struktur definiert hatte.



  • Wobei NULL bei dir ein normaler Fall ist und damit eigentlich vom Programm behandelt werden sollte. Sonst wäre folgende Abbruchbedingung richtig gewesen. Ob du nun ein Segfault oder Deadlock bekommst, ist ja egal 😉 . Du müsstest in jedem Fall vorher sicher stellen, dass auch die Bedingung erfüllt ist. Und dann wäre auch dein Semikolon wieder richtig am Platz. Sicherer und deswegen geben einige Compiler auch eine Warnung aus, ist es aber ein Anweisungsblock zu schreiben. Auch wenn du nur eine oder keine Zeile danach hast. So vermeidest du es auch die Klammern zu vergessen, wenn du noch weitere Anweisungen hinzufügen willst. Dass ist dann so ein Punkt, wo auch Makros gerne mal ihrem Ruf gerecht werden und richtig schön ins Auge gehen können.

    vector_t *fnGetVector(vector_t *pVList, int iVectI)
    {
        vector_t *pVector;
        for (pVector = pVList; pVector->iVectI != iVectI; pVector = pVector->pNext) {}
        return pVector;
    } // fnGetVector
    


  • ass ist dann so ein Punkt, wo auch Makros gerne mal ihrem Ruf gerecht werden und richtig schön ins Auge gehen können.

    Hier sind natürlich nur schlecht programmierte makros gemeint, eigentlich ist es gängige Praxis jedes Makro mit mehr als einem Befehl mit einem do{ }while(0); zu umschließen
    Ob man jetzt bei nur einem Befehl die geschweiften Klammern macht oder weglässt ist Geschmacksfrage, da sind schon erbitterte Religionskriege drum geführt worden (ich bevorzuge z.B. das Weglassen, weil ichs dann schöner zu lesen finde. Die Autoeinrückung meines Editors(vim) hilft da auch Fehler zu erkennen



  • Gibt es einen Grund warum man do{}while(0) schreibt? Man könnte doch genauso gut if(!0){} schreiben? Ich selber nutze sogar nur geschweifte Klammern. Hat eine dieser Varianten Vorteile/Nachteile? Oder ist das gar so festgelegt, wie eine for-Schleife mit leerer Bedingung, die einzig wahre Endlosschleife sein soll?



  • Man kann eine Endlosschleife auf verschiedene Weisen kreieren.

    Am häufigsten ist wohl:
    `for ( ;; )

    {

    }`

    Oder:
    `

    while (1)

    {

    }`

    Und nur mit if (...) {] kannst du keine Schleife realisieren.


Anmelden zum Antworten