Array of structure



  • database zeigt auf 0x1603010

    Das ist fast der Wert, der anschließend als Error herhält:

    *** Error in 'main': free(): invalid next size (fast): 0x0000000001603010 ***



  • Es kann auch sein, dass du den Infoblock vom Speicherbereich (oder vom Nächsten) überschreibst,
    da du die Arraygrenzen nicht einhälst.



  • Aber würde das nicht bedeuten, wenn ich das Array, sagen wir mal, auf 20 schraube, das es dann definitiv bei einer Zeichenzahl von 6 funktionieren müsste?

    Edit: wenn ich den free-Abschnitt und return EXIT_SUCCESS ersetze mit return 0 funktioniert das Programm.

    Edit2: allerdings ist 'num' am Ende entweder, dass alle Examen bestanden sind oder kein Examen. Tippe ich ein bestandenes und ein nicht bestandenes ein, sagt er, alle hätten bestanden.



  • Tergo schrieb:

    Aber würde das nicht bedeuten, wenn ich das Array, sagen wir mal, auf 20 schraube, das es dann definitiv bei einer Zeichenzahl von 6 funktionieren müsste?

    Es geht um den Speicher mit malloc.

    Wenn ein Array 3 Elemente hat, dann geht der Index von 0 bis 2.

    Bei

    int n = 3
    int *data = malloc(n*sizeof(int));
    

    Dann darfst du auf data[n] (data[3]) nicht zugreifen, da es außerhalb des Speicherbereichs liegt.

    Schau mal, welchen Index du beim printf ausgibst und welchen du beim scanf hast.
    Welche Werte haben bei dir i und n?

    Tergo schrieb:

    Edit: wenn ich den free-Abschnitt und return EXIT_SUCCESS ersetze mit return 0 funktioniert das Programm.

    Das kaschiert nur den Fehler. Er ist trotzdem noch vorhanden.
    Das ist so, als ob du die Motorwarnleuchte am Auto zuklebst, damit du das blinken nicht siehst.



  • Das heißt, ich habe den Index in der for-Schleife falsch angegeben?
    Dann müsste der von i=0 bis i<n gehen, richtig?

    Somit würde jetzt hier auch nicht mehr database[n]... gescannt werden, sondern database[i]..., was mir jetzt erst aufgefallen ist.

    Edit: jetzt tritt der riesige Fehler nicht mehr auf!

    Edit2: allerdings wird nun das Abfragen der Matriculation Number übersprungen.



  • Tergo schrieb:

    Das heißt, ich habe den Index in der for-Schleife falsch angegeben?
    Dann müsste der von i=0 bis i<n gehen, richtig?

    Somit würde jetzt hier auch nicht mehr database[n]... gescannt werden, sondern database[i]..., was mir jetzt erst aufgefallen ist.

    Edit: jetzt tritt der riesige Fehler nicht mehr auf!

    Ich glaube du hast bisher alles falsch gemacht, was man in C falsch machen kann. 😃



  • Tergo schrieb:

    Edit2: allerdings wird nun das Abfragen der Matriculation Number übersprungen.

    Schau dir mal den Formatstring von scanf an: https://en.wikipedia.org/wiki/Scanf_format_string



  • Ja, da muss ich dir zustimmen 😃
    Habe jetzt die Loops jeweils angepasst und siehe da, das Programm funktioniert. Allerdings erst, wenn ich für die Matr und ExamID nicht %c, sondern %s frage. Bei %c wird Matr einfach übersprungen, bei %s nicht.

    Ich muss doch sowieso %s benutzen, schließlich sind doch Matr und ExamID Strings?

    Edit: Das Programm:

    #include <stdio.h>
    #include <stdlib.h>
    #define MAXMATRNUM   6  
    #define MAXEXAMIDNUM    6
    
    struct list
    {                                  
        char Matr[MAXMATRNUM+1];
        char ExamID[MAXEXAMIDNUM+1];
        float mark;
    };
    
    int main()
    {
        int n,i,num=0;
        printf("Please enter the number of exams:\n");
        scanf("%d", &n);
        struct list *database;
        database = malloc (n * sizeof(struct list));
        if (database == 0)
            return EXIT_FAILURE;
    
        for(i=0; i<n; i++)
        {
            printf("Please enter the Matriculation Number %d\n",i+1);
            scanf("%s",&*database[i].Matr);
            printf("Please enter the Exam-ID %d\n",i+1);
            scanf("%s",&*database[i].ExamID);
            printf("Please enter the Mark %d\n",i+1);
            scanf("%f",&database[i].mark);
        }
    
        for(i=0; i<n; i++)
        {
        if(database[i].mark<=4.0 && database[i].mark>=0.7)
        {
          num++;
        }
        }
        printf("The number of passed exams is: %d\n", num);
    
        free (database);
        return EXIT_SUCCESS;
    }
    


  • DirkB schrieb:

    %c bei scanf mit einem char-Array ist selten sinnvoll.

    Das war auf Seite 2.

    Mit %c liest man genau ein Zeichen ein. Das ist unter Umständen schon das '\n' von der Entertaste.



  • Okay, das sehe ich ein..

    Also ist das Programm nun vollständig.
    Ich danke euch vielmals für eure tatkräftige Unterstützung, ich werde mir eure Ratschläge definitiv zu Herzen nehmen und werde versuchen, bei der nächsten Aufgabe solche dummen Fehler wie falsche Loop-Angaben direkt zu vermeiden. 😞



  • Tergo schrieb:

    Ich muss doch sowieso %s benutzen, schließlich sind doch Matr und ExamID Strings?

    Ja, aber du musst noch die Länge einschränken.

    Und weil Matr und ExamID Strings sind, kann man Ausdrücke wie

    &*database[i].Matr
    

    auch noch ein bisschen verständlicher hinschreiben. 😉



  • Ich dachte die Länge wäre hier bereits durch

    #define MAXMATRNUM 6
    #define MAXEXAMIDNUM 6

    bzw.

    char Matr[MAXMATRNUM+1];
    char ExamID[MAXEXAMIDNUM+1];

    beschränkt.

    Und wie kann ich das umschreiben?



  • Tergo schrieb:

    Ich dachte die Länge wäre hier bereits durch

    #define MAXMATRNUM 6
    #define MAXEXAMIDNUM 6

    bzw.

    char Matr[MAXMATRNUM+1];
    char ExamID[MAXEXAMIDNUM+1];

    beschränkt.

    Das ist scanf aber ziemlich egal. 🙂
    Probier es aus.



  • Meinst du so?

    #include <stdio.h>
    #include <stdlib.h>
    #define MAXMATRNUM   6  
    #define MAXEXAMIDNUM    6
    
    struct list
    {                                  
        char Matr[MAXMATRNUM+1];
        char ExamID[MAXEXAMIDNUM+1];
        float mark;
    };
    
    int main()
    {
        int n,i,num=0;
        printf("Please enter the number of exams:\n");
        scanf("%d", &n);
        struct list *database;
        database = malloc (n * sizeof(struct list));
        if (database == 0)
            return EXIT_FAILURE;
    
        for(i=0; i<n; i++)
        {
            printf("Please enter the Matriculation Number %d\n",i+1);
            scanf("%7s",&*database[i].Matr);
            printf("Please enter the Exam-ID %d\n",i+1);
            scanf("%7s",&*database[i].ExamID);
            printf("Please enter the Mark %d\n",i+1);
            scanf("%f",&database[i].mark);
        }
    
        for(i=0; i<n; i++)
        {
        if(database[i].mark<=4.0 && database[i].mark>=0.7)
        {
          num++;
        }
        }
        printf("The number of passed exams is: %d\n", num);
    
        free (database);
        return EXIT_SUCCESS;
    }
    


  • Tergo schrieb:

    Meinst du so?

    Das ist schon mal ein Anfang. Jetzt musst du nur noch nachforschen, ob scanf nicht auch noch eine 0 anfügt (String-Ende), oder sogar noch ein CR (unter Windows womöglich CR und LF) mit in deinen String kopiert.

    Schreibt scanf mit "%7s" wirklich nur 7, oder sogar 8, 9 oder 10 Zeichen?
    Das musst du jetzt noch rausfinden.



  • #include <stdio.h>
    #include <stdlib.h>
    #define MAXMATRNUM   6  
    #define MAXEXAMIDNUM    6
    
    struct list
    {                                  
        char Matr[MAXMATRNUM+1];
        char ExamID[MAXEXAMIDNUM+1];
        float mark;
    };
    
    int main()
    {
        int n,i,num=0;
        printf("Please enter the number of exams:\n");
        scanf("%d", &n);
        struct list *database;
        database = malloc (n * sizeof(struct list));
        if (database == 0)
            return EXIT_FAILURE;
    
        for(i=0; i<n; i++)
        {
            printf("Please enter the Matriculation Number %d\n",i+1);
            scanf("%7s",&*database[i].Matr);
            printf("%s",database[i].Matr);
            printf("Please enter the Exam-ID %d\n",i+1);
            scanf("%7s",&*database[i].ExamID);
            printf("Please enter the Mark %d\n",i+1);
            scanf("%f",&database[i].mark);
        }
    
        for(i=0; i<n; i++)
        {
        if(database[i].mark<=4.0 && database[i].mark>=0.7)
        {
          num++;
        }
        }
        printf("The number of passed exams is: %d\n", num);
    
        free (database);
        return EXIT_SUCCESS;
    }
    

    Habe versucht, den Wert direkt danach auszuprinten. Wenn ich 6 Ziffern eingebe, kommen 6 Ziffern wieder heraus.

    Edit: habe außerdem entdeckt, dass die Berechnung der bestandenen Examen falsch ist, wenn ich z.B. 2x 0.7 und einmal 4.0 eingebe. Laut Programm hätte nur ein Examen bestanden 😕 Edit: 0.7 ist das Problem.

    Edit2: wenn ich mehr als 7 Stellen eingebe, nimmt scanf die Stellen nicht mehr auf. Es werden nur 7 Stellen vergeben. Also sind wir mit %7s doch gut dabei, oder?



  • Tergo schrieb:

    Edit2: wenn ich mehr als 7 Stellen eingebe, nimmt scanf die Stellen nicht mehr auf. Es werden nur 7 Stellen vergeben. Also sind wir mit %7s doch gut dabei, oder?

    7 sichtbare Zeichen. Wie kriegst du aber raus, ob das letzte Zeichen nicht doch eine 0 ist und somit 8 zeichen geschrieben werden?



  • Darauf folgte DIREKT die nächste Frage (also nach der ExamID), da war kein Platz zwischen. Ich schätze das zählt nicht, oder? 😃
    Wie kann ich das denn noch untersuchen?

    So vielleicht?

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #define MAXMATRNUM   6  
    #define MAXEXAMIDNUM    6
    
    struct list
    {                                  
        char Matr[MAXMATRNUM+1];
        char ExamID[MAXEXAMIDNUM+1];
        float mark;
    };
    
    int main()
    {
        int n,i,num=0;
        printf("Please enter the number of exams:\n");
        scanf("%d", &n);
        struct list *database;
        database = malloc (n * sizeof(struct list));
        if (database == 0)
            return EXIT_FAILURE;
    
        for(i=0; i<n; i++)
        {
            printf("Please enter the Matriculation Number %d\n",i+1);
            scanf("%7s",&*database[i].Matr);
            printf("%u", strlen(database[i].Matr));
            printf("Please enter the Exam-ID %d\n",i+1);
            scanf("%7s",&*database[i].ExamID);
            printf("Please enter the Mark %d\n",i+1);
            scanf("%f",&database[i].mark);
        }
    
        for(i=0; i<n; i++)
        {
        if(database[i].mark>=0.7 && database[i].mark<=4.0)
        {
          num++;
        }
        }
        printf("The number of passed exams is: %d\n", num);
    
        free (database);
        return EXIT_SUCCESS;
    }
    

    strlen spuckt weiterhin 7 Zeichen aus, egal wieviele ich eintippe. Ein gutes Zeichen, richtig? 😃

    Edit: zur letzten Test-for-Schleife: wenn ich >=0.6 eingebe, wird das Examen auch gezählt, wenn ich 0.6 eingebe. Wenn ich allerdings >=0.7 eingebe, wird 0.7 nicht mehr gezählt. Was läuft denn da schief? 😕
    Seltsamerweise wird das Examen auch gezählt, wenn ich einfach >0.6 eingebe. Für 0.7 gilt das allerdings auch wieder nicht. Wo ist denn da der Unterschied?



  • Du kannst bei scanf auch angeben, dass da 1000 Zeichen platz haben. Wenn der Zielbereich kleiner ist, wird gnadenlos über die Grenze hinaus geschrieben.

    Die Längenbegrenzung bei %s von scanf gilt für die Anzahl der eingebenen Zeichen. Für die Endekennung '\0' muss aber noch Platz bleiben. Die wird immer angehängt.

    strlen sucht nur nach dieser '\0', darum kannst du davon nicht auf den Platz schließen.

    Für diese '\0' ist übrigens die +1 im der Definition der char-Arrays (Zeile 11 & 12)



  • Aber wo kann ich denn den Zielbereich einstellen? Das müsste doch im malloc funktionieren, hier sitzt doch der Speicher. Da hier aber n*size aufgestellt wird, ist doch genügend Platz, oder nicht?


Anmelden zum Antworten