Probleme bei Programmieraufgabe



  • Gibt es eigentlich eine Seite, auf der man solche Informationen zusammengefasst findet? Also kritische C Befehle?





  • Swordfish schrieb:

    ähm. LESEN!!

    dachschaden schrieb:

    https://security.web.cern.ch/security/recommendations/en/codetools/c.shtml

    Ja das hatte ich schon gesehen, ich kann mir nur nicht vorstellen, dass das alle sind. Ich hatte auch mal gelesen, dass memcpy() genauso höchst gefährlich sei und es ist nicht aufgeführt, daher dachte ich, die Liste ist womöglich nicht vollständig(wurde glaube ich auch aus dem jetzigen Standard entfernt, vielleicht steht es deshalb nicht dabei).



  • C_Newbe schrieb:

    Ich hatte auch mal gelesen, dass memcpy() genauso höchst gefährlich sei und es ist nicht aufgeführt, daher dachte ich, die Liste ist womöglich nicht vollständig(wurde glaube ich auch aus dem jetzigen Standard entfernt, vielleicht steht es deshalb nicht dabei).

    Bei memcpy wird die Länge des Speicherbereichs mit angegeben. Daher ist das kein Problem.
    Wenn die Länge größer ist als der Zielbereich, dann hat der Programmierer Scheiße gebaut.
    Das kann man bei strcpy auch vorher testen.

    Bei gets hast du keine Kontrolle, weil es eine Nutzereingabe ist.



  • DirkB schrieb:

    C_Newbe schrieb:

    Ich hatte auch mal gelesen, dass memcpy() genauso höchst gefährlich sei und es ist nicht aufgeführt, daher dachte ich, die Liste ist womöglich nicht vollständig(wurde glaube ich auch aus dem jetzigen Standard entfernt, vielleicht steht es deshalb nicht dabei).

    Bei memcpy wird die Länge des Speicherbereichs mit angegeben. Daher ist das kein Problem.
    Wenn die Länge größer ist als der Zielbereich, dann hat der Programmierer Scheiße gebaut.
    Das kann man bei strcpy auch vorher testen.

    Bei gets hast du keine Kontrolle, weil es eine Nutzereingabe ist.

    Also ist die Liste auf der CERN Seite so ziemlich vollständig?



  • Hallo, zusammen!

    Wollte damit sagen, dass ich nicht nachvollziehen kann, warum er uns das dann beibringt.

    Ich bin nicht in der Position, ihm das so sagen zu können.
    Auch wenn sein Kenntnisstand wohl laut euren Aussagen mangelhaft ist, weiß ich zum Thema C aber immernoch wesentlich weniger.

    Zum von Wutz geposteten Programm:
    Bisher blicke ich da ehrlich gesagt noch nicht komplett durch.
    Ich hoffe, das ändert sich noch.
    Wie gesagt, ich bin kompletter Anfänger in C, von daher steht für mich da erstmal ein kompletter Haufen von Zahlen und Buchstaben, da muss ich mir wohl noch etwas Zeit nehmen um das Zusammenspiel der einzelnen Funktionen zu verstehen.
    Nur dass ich das nicht falsch verstanden habe:
    Lauffähig ist das von Wutz gepostete Programm ja noch nicht? Nicht, dass die IDE jetzt schon lauffähige Programme mit Fehlern beim Kompilieren anzeigt. 😕


  • Mod

    C_AMATEUR schrieb:

    Wollte damit sagen, dass ich nicht nachvollziehen kann, warum er uns das dann beibringt.

    Das liegt da dran, dass C dem Programmierer sehr viel Freiheit und damit auch sehr viel Verantwortung überträgt. Man kann schnell viel falsch machen, vieles davon auch noch so, dass es zunächst richtig aussieht und der Fehler im Details versteckt ist. Viele Lehrer haben nie richtig C gelernt. Sie sind keine Profi-Programmierer, die sich täglich mit diesen Fallstricken beschäftigen, sondern haben entweder selber von solch oberflächlichen Lehrern gelernt. Oder sie haben nur Erfahrung mit irgendwelchen Lehrsprachen wie Pascal (die sehr viel vergebender für den Anfänger sind, dafür aber andere Nachteile haben) und meinen nun, dass sie auch C lehren könnten, indem sie nur BEGIN...END durch { } ersetzen, ohne sich tiefgehend mit der Sprache zu beschäftigen.

    Lauffähig ist das von Wutz gepostete Programm ja noch nicht? Nicht, dass die IDE jetzt schon lauffähige Programme mit Fehlern beim Kompilieren anzeigt. 😕

    Nein, Wutz hat nur ein paar Schlüsselteile gezeigt, wie es besser ginge. Der Hilfesuchende muss dann mitdenken und den Code verstehen, bevor er ihn ergänzen und somit benutzen kann. Daher werden hier bewusst selten vollständige Lösungen gepostet, weil erfahrungsgemäß viele Leute dann bloß den Code blind übernehmen, ohne sich damit zu beschäftigen.



  • Nein, das Beispiel ist (bewusst) nicht lauffähig.
    Allerdings ist dieses Beispiel sehr einfach gehalten (main+3 Funktionen), das sollte jetzt nicht so schwer verständlich sein, zumal die Programmstruktur sprechend ist.



  • Gast3 schrieb:

    Ich mach das ja nur noch als Hobby und um andere Forenmitglieder aufzuheitern/nerven, aber das kommt mir auf den ersten überfliegenden Blick recht fragwürdig vor:

    wieso?

    http://www.cplusplus.com/reference/cstdio/fclose/

    If the stream is successfully closed, a zero value is returned.
    On failure, EOF is returned.

    Mag ja recht sein, ich hab es aber nie so gesehehen und finde es immernoch etwas fragwürdig. Aber ich bin nun auch nicht der Hellste.



  • Hallo EOP,

    störst du dich an dem Wort EOF (end of file)? Dies ist einfach als -1 definiert, d.h. die Beschreibung hätte man auch so schreiben können:

    If the stream is successfully closed, a zero value (0) is returned.
    On failure, -1 is returned.



  • Th69 schrieb:

    Hallo EOP,

    störst du dich an dem Wort EOF (end of file)? Dies ist einfach als -1 definiert, d.h. die Beschreibung hätte man auch so schreiben können:

    If the stream is successfully closed, a zero value (0) is returned.
    On failure, -1 is returned.

    Der C-Standard ist etwas großzügiger:

    C99-standard schrieb:

    EOF
    which expands to an integer constant expression, with type int and a negative value, that
    is returned by several functions to indicate end-of-file, that is, no more input from a
    stream;

    C99-standard schrieb:

    The fclose function returns zero if the stream was successfully closed, or EOF if any
    errors were detected.



  • Hallo, zusammen!

    Okay, habe ich mir schon gedacht.

    Ich sage das aber mal im übertragenen Sinne:
    Wenn man Integrale rechnen kann, kommt einem das Ein-Mal-Eins auch sehr einfach vor.
    Man kann sich aber auch schon mit dem Ein-Mal-Eins schwer tun...

    Ich verstehe es natürlich voll, dass ihr nicht meine Arbeit machen wollt.
    Deswegen werde ich mich da selber rein hängen.



  • function
    <cstdio>
    fclose

    int fclose ( FILE * stream );

    Close file
    Closes the file associated with the stream and disassociates it.

    All internal buffers associated with the stream are disassociated from it and flushed: the content of any unwritten output buffer is written and the content of any unread input buffer is discarded.

    Even if the call fails, the stream passed as parameter will no longer be associated with the file nor its buffers.

    Parameters

    stream
    Pointer to a FILE object that specifies the stream to be closed.

    Return Value
    If the stream is successfully closed, a zero value is returned.
    On failure, EOF is returned.

    Nach dem fett markierten Teil sollte der return-Wert eigentlich egal sein. Du merkst es spätestens wenn du die Datei neu öffnen willst. Nehme ich an.



  • EOP schrieb:

    function
    <cstdio>
    fclose

    int fclose ( FILE * stream );

    Close file
    Closes the file associated with the stream and disassociates it.

    All internal buffers associated with the stream are disassociated from it and flushed: the content of any unwritten output buffer is written and the content of any unread input buffer is discarded.

    Even if the call fails, the stream passed as parameter will no longer be associated with the file nor its buffers.

    Parameters

    stream
    Pointer to a FILE object that specifies the stream to be closed.

    Return Value
    If the stream is successfully closed, a zero value is returned.
    On failure, EOF is returned.

    Nach dem fett markierten Teil sollte der return-Wert eigentlich egal sein. Du merkst es spätestens wenn du die Datei neu öffnen willst. Nehme ich an.

    Der return-Wert von fclose() ist nicht egal, wenn man erfahren möchte, ob alles wie gewünscht verlaufen ist, insbesondere bei vorangegangenen Schreiboperationen auf die Datei. Der fett markierten Teil besagt nur, dass es keinen Sinn ergibt, nach dem fclose(), egal ob fehlgeschlagen oder nicht, weitere Dateioperationen mit dem Filepointer durchzuführen, ohne die Datei erneut zu öffnen, wobei dieses Öffnen nun möglicherwiese, aber nicht zwingend, zu einem Fehler führt.



  • fclose() schrieb:

    Der return-Wert von fclose() ist nicht egal, wenn man erfahren möchte, ob alles wie gewünscht verlaufen ist, insbesondere bei vorangegangenen Schreiboperationen auf die Datei. Der fett markierten Teil besagt nur, dass es keinen Sinn ergibt, nach dem fclose(), egal ob fehlgeschlagen oder nicht, weitere Dateioperationen mit dem Filepointer durchzuführen, ohne die Datei erneut zu öffnen, wobei dieses Öffnen nun möglicherwiese, aber nicht zwingend, zu einem Fehler führt.

    Wer macht schon Dateioperationen wenn er zuvor die Datei geschlossen bzw. zu schließen versucht hat?


  • Mod

    EOP schrieb:

    Wer macht schon Dateioperationen wenn er zuvor die Datei geschlossen bzw. zu schließen versucht hat?

    Die Idee liegt nahe, zu versuchen, die Datei einfach noch einmal zu schließen.



  • SeppJ schrieb:

    EOP schrieb:

    Wer macht schon Dateioperationen wenn er zuvor die Datei geschlossen bzw. zu schließen versucht hat?

    Die Idee liegt nahe, zu versuchen, die Datei einfach noch einmal zu schließen.

    Haha, ziemlich cool gedacht:

    while (fclose(datei) == EOF)
      printf("\nFehler beim Schliessen der Datei! Wir versuchen es einfach noch einmal.\n");
    


  • Hallo, alle zusammen!

    Erstmal danke für eure bisherige Hilfe, mein Programm läuft inzwischen dank eurer Hilfe. 👍

    Eine Frage hätte ich allerdings noch:
    Ich muss mein Programm mit mehreren anderen Programmen jetzt in einem Menü abrufbar machen.
    Da unser Dozent das so möchte, haben ich jetzt jedes Programm in einer eigenen Datei als Funktion definiert, z.B.:

    Datei "teilprogramm_drucken.c"

    int funct_drucken()
    {
    ...
    }
    

    In einem weiteren Programm wird in einer Main-Funktion dann das Menü dargestellt, die Dateien der Funktionen werden oben per include aufgerufen.
    Die Funktion möchte ich dann an der entsprechenden Stelle des Quelltext vom Menü aufrufen und abspielen lassen.
    Also so:

    Datei "hauptmenue.c"

    ...
    #include "teilprogramm_drucken.c"
    
    ...
    
    int main(void)
    {
    do
    {
    switch...
    case...
    funct_drucken();
    ...
    }while...
    }
    

    Dieser Funktionsaufruf klappt bei einem Testprogramm
    (wie diesem:)

    ...
    #include "teilprogramm_drucken.c"
    ...
    int main(void)
    {
    funct_drucken();
    }
    

    ohne Schleifen wie if, for, while, switch-case und do-while einwandfrei,
    leider aber nicht in diesen Schleifen.

    Das Programm lädt die Funktionen zunächst scheinbar ordnungsgemäß, sie funktionieren bis zur ersten Benutzereingabe.
    Dann gibt aber das Programm irgendwie automatisch die Eingabe.
    D.h. das Programm pausiert nicht, sodass man Zeit für die Eingabe hat, sondern läuft mit irgendeinem Eingabewert weiter.
    Da diese Eingabe nicht der entspricht, welche ich in der Funktion festgelegt habe, bricht die Funktion ab.
    So habe ich das für eine falsche Eingabe festgelegt.

    Könnte mir einer von euch erklären, woran das eventuell liegen könnte und wie ich das fixen kann?
    Oder geht das generell nicht und man muss das irgendwie anders machen?

    Vielen Dank im Voraus für eure Hilfe, es ist toll, dass es dieses Forum gibt. 👍



  • C_AMATEUR schrieb:

    #include "teilprogramm_drucken.c"
    

    Man inkludiert keine .c-Dateien, man kompiliert diese. Das Interface der .c-Dateien packt man in Header-Dateien (.h), die inkludiert man.

    Warum? Nun, wenn man irgendwann Programme mit mehreren Übersetzungseinheiten hat und nie Interface-Dateien erstellt, sondern immer nur die Code-Dateien eingebunden hat, dann bekommt der Linker beim Zusammenführen eine Krise nach der anderen.

    So soll das also aussehen:

    /*foo.h*/
    #if !defined(FOO_H)
    #define FOO_H FOO_H
    
    int foo(void);
    
    #endif /*!defined(FOO_H)*/
    
    /*foo.c*/
    #include "foo.h"
    
    int foo(void)
    {
        /*....*/
    }
    

    Das kompilierst du dann zu foo.obj oder foo.a. Dann kann du in deinem Programm die Funktion foo so aufrufen:

    /*programm.c*/
    #include "foo.h"
    
    int main(void)
    {
        foo();
        return 0;
    }
    

    Dem Linker musst du dann halt noch sagen, dass er foo.obj/foo.a einbinden soll, sonst gibt er dir Fehlermeldungen wegen undefinierten Symbolen (Google nutzen für Linkerdoku).

    C_AMATEUR schrieb:

    Das Programm lädt die Funktionen zunächst scheinbar ordnungsgemäß, sie funktionieren bis zur ersten Benutzereingabe. Dann gibt aber das Programm irgendwie automatisch die Eingabe.

    Code zeigen! Wie lädst du die Eingabedaten?



  • C_AMATEUR schrieb:

    Dann gibt aber das Programm irgendwie automatisch die Eingabe.
    D.h. das Programm pausiert nicht, sodass man Zeit für die Eingabe hat, sondern läuft mit irgendeinem Eingabewert weiter.
    Da diese Eingabe nicht der entspricht, welche ich in der Funktion festgelegt habe, bricht die Funktion ab.
    So habe ich das für eine falsche Eingabe festgelegt.

    Könnte mir einer von euch erklären, woran das eventuell liegen könnte und wie ich das fixen kann?
    Oder geht das generell nicht und man muss das irgendwie anders machen?

    Nur geraten, da du keinen Code zeigst:
    Du liest mit scanf ein und daher ist das '\n' von der Entertaste noch im Eingabestrom.
    Danach machst du mit fgets weiter.

    Du kannst nach dem scanf den Rest der Eingabe (bis zum '\n') überlesen: https://www.c-plusplus.net/forum/p1146014#1146014

    Den Mist mit dem #include "teilprogramm_drucken.c" hat dir ja schon dachschaden erklärt.


Anmelden zum Antworten