Array of structure



  • Hör auf hier rumzunerven, melde dich erst wieder, wenn du Code hast, der compilierbar und ohne Warnungen ist.



  • Tergo schrieb:

    Edit: ich verstehe schon, wieso Database als Pointer deklariert wurde, allerdings mache ich offenbar kurz darauf etwas falsch: ich scanne die Eingaben in database rein und sage dort, dass es sich dabei um ein Array handelt. Tut es aber nicht.

    Das ist egal. Einen Pointer kann man wie ein Array ansprechen.

    int *pointer = ...;
    *(pointer+a) = b; // ist das selbe ...
    pointer[a] = b;    // ... wie das
    

    🙂



  • Das heißt, bis dorthin sollte es eigentlich fehlerfrei laufen?
    Der Compiler spuckt nämlich tatsächlich keine Fehler mehr aus, die sich auf die main-Funktion beziehen. In der passedTest-Funktion hingegen wird's schwieriger, aber da ist es ja klar, der Code ist dort auch noch nicht fertig.
    Habe ja die Struktur jetzt in die passed-Test-Funktion gegeben und möchte jetzt gerne die float-Werte abrufen und diese gegentesten. Die passed-Test-Funktion würde dann nun so aussehen:

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


  • Der Auruf und die Deklaration von passedTest sind Müll.

    database in main ist ein Zeiger und so sollte der auch an die Funktion weiter gegeben werden.
    Dann muss die Funktion aber auch einen Zeiger erwarten.
    Und du musst der Funktion auch noch die Anzahl der Elemente im Array mitgeben. Als extra Parameter.

    Deine scanf in der Schleife sind immer noch falsch.

    Und dein else continue ist sehr sinnfrei.



  • DirkB schrieb:

    Der Auruf und die Deklaration von passedTest sind Müll.

    database in main ist ein Zeiger und so sollte der auch an die Funktion weiter gegeben werden.
    Dann muss die Funktion aber auch einen Zeiger erwarten.
    Und du musst der Funktion auch noch die Anzahl der Elemente im Array mitgeben. Als extra Parameter.

    Deine scanf in der Schleife sind immer noch falsch.

    Und dein else continue ist sehr sinnfrei.

    In der main: "for(n=0; n<i; n++)", - n und i hat er wohl vertauscht, denn n enthält die Anzahl der Datensätze und i ist bis dahin uninitialisiert.

    Und "mark" in der Struct hat Array-Klammern. Das ist sicher auch nicht gewollt. 😃



  • Habe jetzt nochmal einige Anmerkungen von euch berücksichtigt und diese hier hinterlegt 🙂

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

    Erhalte jetzt so gut wie keine Fehlermeldungen mehr, die letzten beiden beziehen sich auf Zeile 18 und 50. Dass Zeile 50 falsch ist sehe ich ein, bei Zeile 18 grübel ich weiterhin...



  • Was bedeutet denn Zeile 18?
    Warum hast du Zeile 18 denn geändert?
    Und wie lautet die Fehlermeldung genau?

    Nochmal: Der Parameter der Funktion passedTest ist vom falschen Typ.
    Du kannst da database als Array der struct definieren, oder als Pointer auf die struct.
    Aber nicht als struct selber.

    Welchen Wert hat n in Zeile 48.

    Du musst bei Fehlern immer mit dem Ersten in der Liste anfangen. Die Nachfolgenden können Folgefehler sein.

    Beim Programmieren musst du wissen, was jedes einzelne Zeichen bedeutet.
    Hier und da mal ein paar *, & und [] einbauen, führt nicht zum Ziel.



  • Das bedeutet, dass die Funktionen nur den Pointer Database benötigen, um die Struktur zu handlen? Nur, wenn ich den Prototyp der Funktion mit *database deklariere, ist database ja hier noch gar nicht vorgemerkt worden?

    Habe n nun als globale Variable deklariert, damit müsste der doch von der main auch in die passed-Test Funktion übernommen werden, oder?

    Edit: Erhalte auch für scanf-Funktion in der Schleife bei mark den Fehler, dass ich doch dort float benutzen solle. Allerdings ist %f doch float 😕



  • Tergo schrieb:

    Das bedeutet, dass die Funktionen nur den Pointer Database benötigen, um die Struktur zu handlen?

    Ja.
    Obwohl, die Größe wäre auch wichtig.

    Tergo schrieb:

    Nur, wenn ich den Prototyp der Funktion mit *database deklariere, ist database ja hier noch gar nicht vorgemerkt worden?

    Dann deklariere die Funktion doch nach der struct. 🙄

    Tergo schrieb:

    Habe n nun als globale Variable deklariert, damit müsste der doch von der main auch in die passed-Test Funktion übernommen werden, oder?

    Mach das rückgaängig!
    Warum spedierst du der Funktion nicht einfach einen zweiten Parameter?
    In den ersten Versuch vor drei Seiten, hattest du sogar drei. Du weißt also, das dass geht.



  • Tergo schrieb:

    Edit: Erhalte auch für scanf-Funktion in der Schleife bei mark den Fehler, dass ich doch dort float benutzen solle. Allerdings ist %f doch float 😕

    Auch da hast du solange mit extra Zeichen rumgespielt, bis es kaputt war.

    &*database[n].mark ist ein float, wenn auch sehr umständlich. Aber das will scanf ja auch nicht haben. scanf möchte eine Adresse (hier auf float) haben.



  • Wird die Größe nicht über Malloc bestimmt?

    Die Funktion ist jetzt nach der Struct deklariert.

    Die Funktion hat jetzt einen zweiten Parameter.

    Dass Scanf eine Adresse will, funktioniert doch mit '&', dachte ich? & gibt immer die Adresse aus, so war meine Annahme.. (oder &database[n].mark ?)

    Hier der aktuelle Stand:

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


  • Tergo schrieb:

    Wird die Größe nicht über Malloc bestimmt?

    Du kannst die Größe aber anhand des Zeigers nicht mehr ermitteln. Darum musst du sie dir extra merken und immer mitführen.

    Tergo schrieb:

    Die Funktion ist jetzt nach der Struct deklariert.

    OK.
    Aber warum ist dataset jetzt global?

    Tergo schrieb:

    Die Funktion hat jetzt einen zweiten Parameter.

    Lüge.

    Tergo schrieb:

    Dass Scanf eine Adresse will, funktioniert doch mit '&', dachte ich? & gibt immer die Adresse aus, so war meine Annahme.. (oder &database[n].mark ?)

    Was macht der * an der Stelle und wie ist es mit Arrays und Zeigern?

    Jetzt nicht verwechseln. Beim scanf hast du einen einfachen Tap, von dem du die Adresse willst: database[n].mark ist ein float. Da kannst du mit dem Adressoperator arbeiten.
    Bei passedTest möchtest du das ganze Array angeben.

    Ob du den Zeiger mit dem * derefernzierst oder mit den Arrayklammern, ist egal.
    Aber beides auf einmal zusammen macht man Doppelzeigern. Den hast du nicht.

    Tergo schrieb:

    Hier der aktuelle Stand:

    Die Änderungen darin sind andere als oben beschrieben und teilweise ein weiterer Rückschritt. 😞



  • Folgender Vorschlag:

    ich verzichte auf die Funktion, diese wird ja auch nicht in der Aufgabe verlangt und beziehe den Test der bestandenen Examen einfach in die main-Funktion mit ein. Das sähe dann so aus (ohne Fehlermeldungen):

    #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=1; i<=n; i++)
        {
            printf("Please enter the Matriculation Number %d\n",i);
            scanf("%c",&*database[n].Matr);
            printf("Please enter the Exam-ID %d\n",i);
            scanf("%c",&*database[n].ExamID);
            printf("Please enter the Mark %d\n",i);
            scanf("%f",&database[n].mark);
        }
        for(i=1; i<=n; i++)
        {
        if(database[n].mark<=4.0 && database[n].mark>=0.7)
        {
          num++;
        }
        }
        printf("The number of passed exams is: %d\n", num);
    
        free (database);
        return EXIT_SUCCESS;
    }
    

    Das Programm führt korrekt aus, fragt nach sämtlichen Werten, jedoch: kurz vor der Auswertung, wieviele Examen bestanden haben erhalte ich eine riesige Meldung:

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

    gefolgt von jeder Menge Informationen bezüglich des Speichers.

    Es muss also etwas mit der free Funktion nicht stimmen..

    Edit: jetzt das Ganze etwas aufgeräumter.



  • Tergo schrieb:

    Es muss also etwas mit der free Funktion nicht stimmen..

    Wenn die nicht ok ist, dann wärst du nicht der Erste, der der das merkt.

    Das Problem liegt bei dir!

    Lass dir mal den Wert von database nach dem malloc und vor dem free ausgeben und vergleiche die Angaben:

    printf("database zeigt auf %p\n": database);
    

    Oder nutze den Debugger.

    Durch dein krudes vermischen von & und * und Nichtbeachtung der Arraygrenzen zerschießt du dir den Zeiger.



  • 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. 😃


Anmelden zum Antworten