Komische Zeichen bei der Ausgabe



  • Hey, ich bräuchte kurz Hilfe. Bei mir wird nach paar Wörter in der Ausgabe aufeinmal komische Zeichen ausgegeben. Also ich kann mir vorstellen das es an einer Array-Überschreitung liegt, aber weiß es nicht ganz wie ich es lösen soll.

    Hier ist mein Programm:
    (Wichtiger Teil: Zeile 35-40)

    #include <stdio.h>
    #include <string.h>
    
    int main() {
        char name[10][20];
        char buffer[20];
        char note[10];
    
        FILE *nameDB = fopen("namen.txt", "r");
        FILE *fp = fopen("noten.txt", "w+");
    
        if(fopen("noten.txt", "r") != NULL) {
            if(remove("noten.txt") != 0) {
                printf("File wurde erfolgreich gel\x94scht!\n");
            }
        } else {
            printf("Eine neue Datei wurde erstellt!\n");
        }
    
        for(int i = 0; i < 10; i++) {
            fgets(name[i], 11, nameDB);
            printf("%s", name[i]);
        }
    
        for(int i = 0; i < 10; i++) {
            name[i][strlen(name[i])-1] = '\0';
        }
    
        for(int i = 0; i < 10; i++) {
            printf("Noten f\x81r %s: ", name[i]);
            fflush(stdin);
            scanf("%c", &note[i]);
        }
    
        for(int i = 0; i < 10; i++) {
            char number = note[i];
            strcat(name[i], "\x3A\x20");
            name[i][strlen(name[i])] = note[i];
            strcat(name[i], "\n\0");
        }
    
        for(int i = 0; i < 9; i++) {
            for(int j = 0; j < strlen(name[i]); j++) {
                buffer[j] = name[i][j];
            }
            printf("%s", buffer);
            fputs(buffer, fp);
            memset(buffer, 0, 20);
        }
    
        fclose(nameDB);
        fclose(fp);
        return 0;
    }
    

    Hier ist die Ausgabe:

    Adrian: 1
    Elena: 2
    Karlo: 3
    Tim: 4
    Sonja: 5
    Bastion: 4CSwÿ■a
    Achilles: 3MwÑÞ\♥┤§╗Kathi
    : 2└↓@
    D■aKathi
    : 2└↓@
    Patroclus: 1t■   h aHector
    : 2]▒w
    ■a
    

    Ich freue mich auf alle Antworten, Tipps und Vorschläge.
    Lg Bruti


  • Mod

    @MrBrutDev sagte in Komische Zeichen bei der Ausgabe:

    for(int i = 0; i < 10; i++) {
        fgets(name[i], 11, nameDB);
        printf("%s", name[i]);
    }
    
    for(int i = 0; i < 10; i++) {
        name[i][strlen(name[i])-1] = '\0';
    }
    

    Was soll das werden? fgets(name[i], 10, nameDB); und gut ist. fgets hängt schon 0 an (sonst würde strlen schließlich nicht gehen) und die Längenangabe von fgets bezieht sich darauf, wie viele Zeichen es maximal schreiben darf, was bei dir 10 sein muss.

     fflush(stdin);
    

    Undefiniertes Verhalten. Was willst du erreichen? Vielleicht willst du nur scanf(" %c", &note[i]); (beachte das Leerzeichen!), um Whitespaces zu verwerfen? Warum sind Noten überhaupt char? Klingt eher so, als sollten es Zeichenketten oder Zahlen sein.

    name[i][strlen(name[i])] = note[i];
    

    Herzlichen Glückwunsch, damit hast du das abschließende Nullzeichen überschrieben. Sämtliche Stringaktionen danach werden Unsinn machen, beispielsweise das strcat in der Zeile danach.

        for(int i = 0; i < 9; i++) {
            for(int j = 0; j < strlen(name[i]); j++) {
                buffer[j] = name[i][j];
            }
            printf("%s", buffer);
            fputs(buffer, fp);
            memset(buffer, 0, 20);
        }
    

    Ich habe das Gefühl, hier gäbe es etwas zu beanstanden, aber ich habe nicht die geringste Ahnung, was du überhaupt erreichen willst.

    Insgesamt ist so ziemlich jede Stringaktion falsch. Ich kann nicht konkret auf dein Problem zeigen, weil es zu viele Fehler gibt, aber so eine Ausgabe ist typischerweise das Resultat von solchen Fehlern. Du musst noch einmal gründlich angucken, wie Strings in C funktionieren. Ein String ist bloß ein ganz dummes char-Array, mit der Konvention, dass es mit einem Nullzeichen endet. Diese Konvention einzuhalten liegt in der Verantwortung des Programmierers. Die Stringfunktionen aus der Standardbibliothek machen das alle korrekt, da kannst du dich drauf verlassen, aber sie müssen sich andersherum auch darauf verlassen können, dass die Konvention gilt. Beispielsweise kennt strlen nicht irgendwie magisch die Stringlänge (wovon du auszugehen scheinst), es zählt ganz stumpf Zeichen bis es ein Nullzeichen findet. Deshalb sind so Konstrukte wie for(int j = 0; j < strlen(name[i]); j++) auch zu vermeiden, denn da werden bei jedem einzelnen Schleifendurchlauf alle Zeichen gezählt, um die Stringlänge zu ermitteln, was ziemlich schnell ziemlich viele Zählungen werden können.

    Ich kann in einem Forenbeitrag leider keine vollständige, didaktische Erklärung von Strings in C geben.



  • Ich verstehe auch schon die Logik beim Dateiöffnen bezüglich noten.txt am Anfang nicht:

        FILE *nameDB = fopen("namen.txt", "r");
        FILE *fp = fopen("noten.txt", "w+");
    
        if(fopen("noten.txt", "r") != NULL) {
            if(remove("noten.txt") != 0) {
                printf("File wurde erfolgreich gel\x94scht!\n");
            }
        } else {
            printf("Eine neue Datei wurde erstellt!\n");
        }
    

    Erst öffnest du die Datei im Modus w+, d.h. erstellen bzw. leer machen, wenn sie schon existiert. Danach versuchst du sie nochmal zu öffnen, lässt aber das Dateihandle ins Nirvana verschwinden. Und remove liefert 0 bei Erfolg (siehe https://en.cppreference.com/w/c/io/remove), d.h. dein printf-Text passt auch nicht. Was sollen die Zeilen 4-10 (im Zitat) überhaupt? Was willst du machen?

    Du hast mehrfach die 10 im Programm stehen, manchmal auch eine 11 oder eine 9. Benutze benannte Konstanten, damit du weißt, wofür die Zahl steht - und damit du diese Zahl leichter ändern kannst! Ist es nicht merkwürdig, dass du 9, 10 und 11 im Code hast?

    Vielleicht solltest du erstmal einfacher anfangen? Lass den gesamten Datei-Krempel weg und beschränke dich darauf, eine Liste von Namen und Noten einzulesen und auszugeben. Du kannst die Liste ja auch im Programm schon mit 1 oder 2 Einträgen vorinitialisieren.



  • @MrBrutDev sagte in Komische Zeichen bei der Ausgabe:

    strcat(name[i], "\x3A\x20");

    Warum Hexcode für normale Zeichen, die auf jeder Tastatur zu finden sind?

    Das ganz Stringgeraffel kann man auch gleich bei der Ausgabe erledigen:
    printf(fp, "%10s: %d\n", name[i], note[i]); // Wenn note[] ein int-Array ist



  • Erstmal: Danke für die vielen Antworten und Tipps! Nach einiger Zeit habe ich gemerkt, dass ich wirklich sehr viel Mist gebaut habe. Jetzt habe ich es etwas umstruckturiert und geht jetzt reibungslos. Kein Plan was da los war, war wahrscheinlich Brain-Dead xD

    Naja hier ist nun mein Final-Code:

    #include <stdio.h>
    #include <string.h>
    
    #define MAX 10
    
    int main() {
        char name[MAX][20];
        char buffer[20];
        int note[MAX];
    
        FILE *nameDB = fopen("namen.txt", "r");
        FILE *fp = fopen("noten.txt", "w+");
    
        if(nameDB == NULL) {
            printf("Datei namen.txt nicht gefunden\n");
            return 1;
        }
    
        for(int i = 0; i < MAX; i++) {
            fgets(name[i], MAX, nameDB);
        }
    
        for(int i = 0; i < MAX; i++) {
            name[i][strlen(name[i])-1] = '\0';
        }
    
        for(int i = 0; i < MAX; i++) {
            printf("Noten f\x81r %s: ", name[i]);
            scanf("%d", &note[i]);
        }
    
        for(int i = 0; i < MAX; i++) {
            fprintf(fp, "%s: %d\n", name[i], note[i]);
        }
    
        fclose(nameDB);
        fclose(fp);
        return 0;
    }
    

    Sollte noch was Verbesserungswürdig sein, sehr gerne her damit : )



  • @MrBrutDev In Zeile 20 ist das MAX falsch.

    Da gehört die maximale Stringlänge hin - bei dir die 20.
    (Eine zweite Konstante wäre aber sinnvoller)

    Der Bezeichner MAX wird aber meist für Makros verwendet, die die größere von zwei Zahlen zurück gibt.


  • Mod

    @MrBrutDev sagte in Komische Zeichen bei der Ausgabe:

        fgets(name[i], MAX, nameDB);
    

    Deine Länge ist 20, nicht MAX. MAX ist deine Maximalzahl Schüler. Sei nicht sparsam bei Bezeichnern! Hättest du das MAX_NUM_PUPILS und MAX_PUPIL_NAME_LENGTH genannt, wäre das nicht passiert. Das gilt auch für viele andere Bezeichner in deinem Programm. Auch wenn du sie hier nicht verwechselt hast, sind sie doch gefährlich verwechselbar und machen es schwer zu lesen. Beispiel fp für Filepointer? Wenn du mehrere Dateien gleichzeitig offen hast? Wie soll ein Leser da wissen, welcher Handler zu welcher Datei gehört, ohne ständig zu gucken? Zumal fp das erste Mal 20 Zeilen nach seiner Definition benutzt wird. Wie wäre es mit grades_out_file?

    @MrBrutDev sagte in Komische Zeichen bei der Ausgabe:

        printf("Noten f\x81r %s: ", name[i]);
    

    Schreib einfach mal printf("Noten für %s: ", name[i]);. Wird bestimmt funktionieren und ist ungleich lesbarer.

    Ansonsten: Wesentlich besser 👍


Log in to reply