Array von Strukturen



  • Vielen Dank nochmal! Ihr seit echt super! Ich finds richtig nett, dass ihr mir helft. Ich war heute ganzen Tag unterwegs und kam noch nicht dazu alle eure Tipps umzusetzen. Ich mach mich gleich an die Arbeit und melde mich dann später wieder, falls ich irgendwo nicht weiterkomme. Am Ende poste ich aufjedenfall den fertigen Code. 🙂



  • So sieht mein Code jetzt aus:

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    #define DARLEHENSZINS 0.05
    #define GUTHABENSZINS 0.03
    #define KONTOANZ 10
    #define BANKNR
    
    typedef struct {
           unsigned int   kontoNr;              /* Kontonummer */
           double         kontoStnd;            /* Kontostand */
           double         zinsS;                /* Zinssatz */
           double         annuitaet;            /* Annuität */
           char           habenOderDarl;        /* Guthaben/Darlehen */
           unsigned int   laufZt;               /* Laufzeit */ 
    } Konto;
    
    struct Konto konten[KONTOANZ];              /* Array mit der Größe xx */
    struct Konto *kk = konten;
    
    void eingabe();                             /* Methode um Array mit Konten zu 
                                                   füllen */
    void ausgabe();                             /* Methode um Konto im Array wieder 
                                                   auszugeben */
    
    double kapZins(float kontoStnd, int laufZt);
    
    double darZins(float kontoStnd, int annuitaet);
    
    int main(int argc, char *argv[])
    {
        int i;
        int auswahl;                            /* Speicherung für die Bedingung */
    
        printf("\n\t Zweites Programm in SS11, Strukturen");
        printf("\ von xx");
        printf("\n\t uebersetzt am %s", __DATE__);
        printf("\n\t um %s Uhr", __TIME__);
        printf("\n\n");
    
        do {
           printf("-1- Neues Konto anlegen\n");
           printf("-2- Alle Kontodaten ausgeben\n");
           printf("-3- Programm beenden\n");
           printf("\nIhre Auswahl : ");
           scanf("%d", &auswahl);
    
           getchar();
           switch(auswahl) {
              case 1 : eingabe();
                       break;
              case 2 : ausgabe();
                       break;
              case 3 : printf("Programm beendet\n");
                       break;
              default: printf("Falsche Eingabe\n");
           }
        }while(auswahl <3);
    
        system("PAUSE");	
        return 0;
    }
    
    void eingabe(Konto *konten){
    
         int anz, i;
    
         prinft("Wieviele Konten sollen erstellt werden?");  scanf("%i", &anz);
    
         if(anz == 0)
         {
                   prinft("Diese Anzahl ist ungueltig\n");
         }
    
         for(i = 0; i<anz; ++i)
         {
                   printf("Kontodaten für das %i. Konto eingeben: ", i);
                   printf("Kontostand: ");     scanf("%d", &konten->kontoStnd);
         }
    }
    

    Es tritt leider dieser Fehler auf: storage size of 'konten' isn't known

    Es ist mir klar, dass es wohl an meinem Array bzw. mit den Zeigern auf Array zusammenhängt, aber ich komme nicht drauf wie ich es richtig machen soll. Hab schon einiges rumprobiert, aber komme einfach nicht auf die richtige Lösung.

    Die Ausgabe-Funktion soll übrigens das Darlehen bzw. Anlagekapital ausgeben.

    Ich habe mir überlegt, dass ich dazu in der eingabe-Funktion ein "g" oder ein "d" als char an die Variable habenOderDarl übergebe und die Ausgabe-Funktion dann so aussehen soll:

    void ausgabe(){
    
       if(konten->habenOderDarl == 'g')
       {
          double kapZins(float kontoStnd, int laufZt);
       }
       if(konten->habenOderDarl == 'd')
       {
          double darZins(float kontoStnd, int annuitaet);
       }
    }
    

    Das sollte funktionieren, oder?



  • Erstens: Wenn du die struct per typedef struct{...} Konto; anlegst, brauchst du bei den Variablen-Definitionen das "struct" nicht mehr zu verwenden.

    Zweitens: Du hast die Funktionen eingabe() und ausgabe() mit leerer Parameterliste (das ist afair die Prä-Ansi-Formulierung für "du brauchst nicht zu prüfen, welche Parameter kommen") deklariert und ohne Parameter aufgerufen - bei der Definition wird aber ein Parameter erwartet.

    Drittens:

    void ausgabe(){
    
       if(konten->habenOderDarl == 'g')
       {
          double kapZins(float kontoStnd, int laufZt);
       }
       if(konten->habenOderDarl == "d")
       {
          double darZins(float kontoStnd, int annuitaet);
       }
    }
    

    Das ist syntaktisch falsch - wenn überhaupt, willst du an dieser Stelle die Funktionen aufrufen (und ihre Rückgabe irgendwo speichern). Außerdem solltest du dir den Unterschied zwischen einem char- und einem String-Literal ansehen 😉

    Viertens: Bei der Eingabe solltest du auch sicherstellen, daß du nicht über das Array-Ende hinaus schreibst. Bei mehr als 10 Konten würdest du Daten zerstören, von deren Existenz du noch nicht einmal weißt.



  • Ein Haufen blöder Fehler also. 😃 Danke für die schnelle Antwort! Ich werde versuchen in meinem C-Programmierung Buch Lösungen darauf zu finden.



  • Ich sitze schon seit mehr als 2 Tagen an diesem Programm und kriege es einfach nicht hin so wie ich es möchte. 😞 Wahrscheinlich ist das was ich vorhabe einfach noch viel zu kompliziert für meine Programmierkenntnisse. Kann jemand eventuell die Aufgabenstellung durchlesen und mir sagen, ob mein bisherigen Ansatz vielleicht zu kompliziert ist oder irgendwo ein Denkfehler drin ist.

    Die genau Aufgabenstellung ist:

    Vereinbaren Sie eine Struktur mit Kontodaten! Sie soll enthalten: Kontonummer, Kontostand, ob es sich um ein Haben- oder Darlehenskonto handelt, Zinssatz und Annuität. Mehrere Strukturen dieser Art sind in einen Array zu fassen. Für alle Array-Elemente ist auszurechnen, wie der Tilgungs- oder Guthabens-Verlauf ist.

    Die Werte einiger der Struktur-Felder dürfen fest vorgegeben bzw. berechnet werden. Die Höhe des aufgenommenen Darlehens und die Annuität sind aber einzulesen; ebenso die Länge der Anlagedauer und die Höhe des angelegten Kapitals. Sowohl beim Einrichten der Konten, als auch bei den Berechnungen soll jeweils mit einer Schleife über alle Konten gearbeitet werden. Eine passende Gliederung in Unterprogramme ist wichtig. Keine Funktion, auch nicht die main()-Funktion soll mehr als 100 Zeilen haben.

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

    Die eingabe()- und ausgabe()-Funktion bereiten mir Probleme. Die Anzahl der Konten soll bei der eingabe() abgefragt werden. Es ist mir aber immernoch nicht klar wie ich diese Anzahl an das Array übergeben soll und wie ich alle angelegten Konten bei der ausgabe()-Funktion ausgeben soll.



  • mr_unknown schrieb:

    Die eingabe()- und ausgabe()-Funktion bereiten mir Probleme. Die Anzahl der Konten soll bei der eingabe() abgefragt werden. Es ist mir aber immernoch nicht klar wie ich diese Anzahl an das Array übergeben soll und wie ich alle angelegten Konten bei der ausgabe()-Funktion ausgeben soll.

    1. Die Größe der Funktion ist nicht so wichtig. Wichtig ist eher, dass du jeder Funktion eine Aufgabe zuweist, die sich ständig wiederholt und die sich selbst sonst um gar nichts kümmert. Da kann eine Nachrichtenbehandlungsfunktion auch mal 5000 Zeilen lang werden.

    2. Kennst du die Funktion malloc ? Sie reserviert Speicher auf dem Heap, den du hinterher wieder freigeben musst.

    Aber in deinem Fall würde ich erstmal den Umgang mit Zeigern auf dem Stack lernen, bevor du an den für Anfänger wesentlich "gefährlicheren" Heap gehst. Lern das Zeiger- und Adressenkonzept auswendig, und dann verwende malloc .



  • Glühbirne schrieb:

    mr_unknown schrieb:

    Die eingabe()- und ausgabe()-Funktion bereiten mir Probleme. Die Anzahl der Konten soll bei der eingabe() abgefragt werden. Es ist mir aber immernoch nicht klar wie ich diese Anzahl an das Array übergeben soll und wie ich alle angelegten Konten bei der ausgabe()-Funktion ausgeben soll.

    1. Die Größe der Funktion ist nicht so wichtig. Wichtig ist eher, dass du jeder Funktion eine Aufgabe zuweist, die sich ständig wiederholt und die sich selbst sonst um gar nichts kümmert. Da kann eine Nachrichtenbehandlungsfunktion auch mal 5000 Zeilen lang werden.

    2. Kennst du die Funktion malloc ? Sie reserviert Speicher auf dem Heap, den du hinterher wieder freigeben musst.

    Aber in deinem Fall würde ich erstmal den Umgang mit Zeigern auf dem Stack lernen, bevor du an den für Anfänger wesentlich "gefährlicheren" Heap gehst. Lern das Zeiger- und Adressenkonzept auswendig, und dann verwende malloc .

    Ich habe Gestern über malloc in einem Buch gelesen und hab versucht es umzusetzen, aber ohne großen Erfolg. Ist es in diesem Fall die einzigste Möglichkeit? Wenn ja, dann muss ich mich länger damit auseinandersetzen, bis ich es hinkriege.



  • Die von mir gezeigte Lösung kommt komplett ohne malloc aus, d.h. natürlich nicht, dass du malloc nie brauchen wirst.



  • mr_unknown schrieb:

    Ich habe Gestern über malloc in einem Buch gelesen und hab versucht es umzusetzen, aber ohne großen Erfolg. Ist es in diesem Fall die einzigste Möglichkeit? Wenn ja, dann muss ich mich länger damit auseinandersetzen, bis ich es hinkriege.

    Sagen wir mal so, um Zeiger wirst du nicht herumkommen. Selbst wenn du die Plattformunabhängigkeit über Bord wirfst und HeapAlloc unter Windows verwendest, musst du immer noch wissen, was Zeiger und Adressen sind. Und auch mit C++ und dem new -operator kannst du ohne ein Dereferenzierungsobjekt nix anfangen. Viele Wege führen nach Rom, aber dafür musst du in der Lage sein, die Landkarte zu lesen.

    Im übrigen: 'einzigste' jüft üt nisch, det is de 'einzige'.



  • Das mit den Zeigern werde ich vielleicht noch hinkriegen, aber Heap würde mich wohl überfordern. Ich denke nicht, dass die das von einem Stundeten im 2. Semester erwarten. Eventuell muss ich einen Array mit einer variablen länge in die eingabe()-Funktion einbauen oder über malloc Speicher reservieren. Ich Frage mich nur was die einfachste Lösung ist. Das Programm soll nur gut genug sein, damit ich ein Testat bekomme, sonst werde ich am Ende des Semesters nicht zu der Klausur zugelassen werden. Nach 2 Vorlesungen C-Programmierung sind meine Kenntnisse leider noch ziemlich begrenzt. 😞



  • Die "einfachste" Lösung ist wohl, wenn du eine Obergrenze der Datensätze vorgibst (und ein Array in dieser Größe vorgibst). Zusätzlich legst du noch eine Variable an, die die Anzahl der tatsächlich genutzten Datensätze enthält*.
    Die nächste Variante wäre ein VLA in der main()-Funktion (da mußt du vor der Eingabe abfragen, wieviele Datensätze zu erwarten sind.
    Die dritte Variante ist malloc(), um einen entsprechend großen Speicherbereich zu reservieren.

    *das benötigst du in allen Varianten



  • Danke für all die Hilfe, CStoll! 👍 Hab nicht gedacht, dass mir dieses Programm solche Probleme bereiten wird. Ich werd´ versuchen mit einer von dir vorgeschlagenen Varianten bis zum Abend zum Erfolg zu kommen. Aufgeben ist für mich keine Option, da ich das Testat für diese Aufgabe unbedingt brauche. 🙂



  • Ich habe das Programm jetzt im groben fertig, aber es sind wohl noch Denkfehler drin, denn bei der ausgabe() kommt es zu einer Endlosschleife - leider. Könnt ihr mir sagen, ob ich den folgenden Code so korrigieren kann, dass es funktioniert? Oder ist mein Ansatz koplett unbrauchbar?

    Hier der Code:

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    #define DARLEHENSZINS 0.05
    #define GUTHABENSZINS 0.03
    #define KONTOANZ 100
    #define BANKNR
    
    typedef struct {
           unsigned int   kontoNr;              /* Kontonummer */
           double         kontoStnd;            /* Kontostand */
           double         zinsS;                /* Zinssatz */
           double         annuitaet;            /* Annuität */
           char           habenOderDarl;        /* Guthaben/Darlehen */
           unsigned int   laufZt;               /* Laufzeit */ 
    } Konto;
    
    Konto konten[KONTOANZ];
    int anz;
    Konto *kk = konten;
    
    int eingabe();                             /* Methode um Array mit Konten zu 
                                                   füllen */
    int ausgabe();                             /* Methode um Konto im Array wieder 
                                                   auszugeben */
    
    double kapZinsS(double kontoStnd, unsigned int laufZt);
    
    double darZinsS(double kontoStnd, double annuitaet);
    
    int main(int argc, char *argv[])
    {
        int auswahl;                            /* Speicherung für die Bedingung */
    
        printf("\n\t Zweites Programm in SS11, Strukturen");
        printf(" von xx");
        printf("\n\t uebersetzt am %s", __DATE__);
        printf("\n\t um %s Uhr", __TIME__);
        printf("\n\n");
    
        do {
           printf("-1- Neues Konto anlegen\n");
           printf("-2- Alle Kontodaten ausgeben\n");
           printf("-3- Programm beenden\n");
           printf("\nIhre Auswahl : ");
           scanf("%d", &auswahl);
    
           getchar();
           switch(auswahl) {
              case 1 : eingabe();
                       break;
              case 2 : ausgabe();
                       break;
              case 3 : printf("Programm beendet\n");
                       break;
              default: printf("Falsche Eingabe\n");
           }
        }while(auswahl <3);
    
        system("PAUSE");	
        return 0;
    }
    
    int eingabe(int anz){
    
         int i;
    
         printf("Wieviele Konten sollen erstellt werden? ");  scanf("%i", &anz);
    
         for(i = 0; i<anz; ++i)
         {
               printf("Kontodaten fuer das %2i. Konto:\n", i+1);
               printf("Art des Kontos: ");    scanf("%2c", &konten[i].habenOderDarl);
               printf("Laufzeit: ");          scanf("%u", &konten[i].laufZt);
               printf("Guthaben/Darlehen: "); scanf("%d", &konten[i].kontoStnd);
         }
    
    }
    
    int ausgabe(const Konto *kk, int anz){
    
         int i;
    
         for(i = 0; i<anz; i++){
    
               if(kk->habenOderDarl == 'g')
               {
               kapZinsS(kk->kontoStnd, kk->laufZt);
               }
               if(kk->habenOderDarl == 'd')
               {
               darZinsS(kk->kontoStnd, kk->annuitaet);
               }
         }                 
    }
    
    /* Berechnung der Kapitalanlage mit Schleife */
    double kapZinsS(double kontoStnd, unsigned int laufZt)
    {
           unsigned i;
           double zins;
    
           for(i=1; i<=laufZt; i++){
                    zins = kontoStnd * GUTHABENSZINS;
                    kontoStnd = kontoStnd + zins;
                    printf("Jahr: %u\n", i);
                    printf("Anlaufende Zinsen: %.2d \n", zins);
                    printf("Kapital nach Zinsen: %.2d \n", kontoStnd);                
           }
           return kontoStnd;
    }
    
    /* Berechnung der Tilgung mit Schleife */
    double darZinsS(double kontoStnd, double annuitaet)
    {
           unsigned i;
           double zins;
           double tilgungsrate;
    
           for(i=i; i >= kontoStnd; i++){
                    zins = kontoStnd * DARLEHENSZINS;
                    tilgungsrate = annuitaet - zins;
                    kontoStnd = kontoStnd - tilgungsrate;
                    printf("Jahr: %u\n", i);
                    printf("Zinsen: %.2d \n", zins);
                    printf("Restschuld: %.2d \n", kontoStnd);
           }
           return kontoStnd;
    }
    

    Ich weiß nicht, ob es möglich ist auf die schnelle Fehler in so einem Code zu finden, ohne es im Compiler ablaufen zu lassen, aber ich denke für gute Programmierer stellt es kein großes Problem dar. Ich wäre euch sehr sehr dankbar!



  • Deine Funktionen eingabe() und ausgabe() erwarten jeweils einen Parameter 'anz', du rufst sie aber ohne Parameter auf, das kann nur in die Hose gehen.
    (und der Prototyp "int eingabe();" sagt einem C-Compiler gar nichts, unter C++ hättest du hier vermutlich einen Linker-Fehler)

    PS: Übrigens gibst du in der ausgabe()-Funktion n-mal den ersten Eintrag des Arrays aus.



  • Danke! Jetzt muss ich versuchen es zu korrigieren, wenn es denn möglich ist. Ich nerv´ dich wahrscheinlich schon mit meinen Fragen, aber ich geb mir Mühe - auch wenn es vielleicht nicht so aussieht. 😃 Ich bin nicht faul, aber manchmal hänge ich fest und weiß nicht wonach genau ich suchen muss.



  • Ein paar Sachen die mir noch zum Ergänzen einfallen :

    1. Wenn ich mich nicht irre sollte in C eine Funktion, die keine Argumente erwartet so aussehen : void foo(void), also mit dem void-keyword in den Parameter-klammern. Ansonsten kann die Funktion eine unbestimmte Anzahl von Argumenten von unbestimmten Typ annehmen.
    2. Deine Ausgabe ist mir immernoch suspekt. Schauen wir sie uns mal an :

    int eingabe(int anz){
    
         int i;
    
         printf("Wieviele Konten sollen erstellt werden? ");  scanf("%i", &anz);
    
         for(i = 0; i<anz; ++i)
         {
               printf("Kontodaten fuer das %2i. Konto:\n", i+1);
               printf("Art des Kontos: ");    scanf("%2c", &konten[i].habenOderDarl);
               printf("Laufzeit: ");          scanf("%u", &konten[i].laufZt);
               printf("Guthaben/Darlehen: "); scanf("%d", &konten[i].kontoStnd);
         }
    
    }
    

    Naja, wie Cstoll bereits erwähnt hat macht natürliche der int-Parameter keinen Sinn. Aber : Du fragst den benutzer, wieviele Konten er erstellen will. Dann loops du dementsprechend oft. Aber du erstellst garnicht diese Anzahl an Konton, denn du hast diese per Konstante erstellt. Und zwar sind das 100. Gibt der benutzer nun 5000 als Anzahl ein, wirst du versuchen auf Speicher zuzugreifen, der dir garnicht gehört. Das wird bei konten[100] zu einer Speicherzugriffs-Verletzung führen und dein Programm wird abstürzen.
    Was du suchst ist wohl malloc(). Damit kannst du dynamisch Speicher anfordern - d.h die Grösse eines z.b Arrays muss NICHT zu Compilezeit festehen. Gcc unterstützt glaube ich sowas wie VLA ( Variable Length Arrray, oder wie es hieß ) aber normalerweise kommst du um das malloc nicht rum ( oder realloc, kenne C nicht so gut ).
    Wie du malloc benutzt lass dir bitte von CStoll zeigen, vllt. erbarmt er sich, denn mein Akku ist fast leer. Oder du googelst einfach nach "C malloc()" da findest du sicher was.

    Mit den Zinssatzkram da will ich mich jetzt nicht rumschlagen, das wirst du schon richtig gemacht haben 😛

    Mfg



  • Wow, danke für die umfangreiche Antwort, cvcv! Ich habs leider vermutet, dass ich ohne malloc nicht auskommen werde. Ich habe darüber in meinem C-Buch gelesen, aber leider nicht verstanden wie genau es angewendet wird. So wie ich es verstanden habe gehört es dann in meine eingabe()-Funktion. Dann ergibt sich für mich ein neues Problem, denn ich weiß nicht wie ich die Felder davon an die ausgabe()-Funktion übergeben soll. Ich vermute mal mit Zeigern... 😕 Puhhh... die erste Aufgabe, die wir programmieren sollten, war um einiges einfacher.

    Aber danke, dass ihr mir helft! Ohne euch wäre ich wohl schon längst verzweifelt...



  • Punkt 1: Bei der malloc()-Funktion gibst du an, wieviel Speicher (in Byte) du haben möchstest.
    Punkt 2: Um Werte von einer Funktion zur nächsten übergeben zu können, nutzt man normalerweise Parameter und Rückgabewerte:

    int eingabe(Konto** pkonten)
    {
      Konto* konten = NULL;
      int anz;
      printf("Wieviele Konten sollen erstellt werden? ");  scanf("%i", &anz);
      konten = malloc(anz * sizeof(Konto));//sizeof() gibt die Größe eines Datensatzes an
    
      for(i = 0; i<anz; ++i)
      {
        printf("Kontodaten fuer das %2i. Konto:\n", i+1);
        printf("Art des Kontos: ");    scanf("%2c", &konten[i].habenOderDarl);
        printf("Laufzeit: ");          scanf("%u", &konten[i].laufZt);
        printf("Guthaben/Darlehen: "); scanf("%d", &konten[i].kontoStnd);
      }
      *pkonten = konten;
      return;
    }
    
    void ausgabe(Konto* konten, int anzahl);
    {
      ...
    }
    
    //Anwendung:
    Konto* konten;
    int anz = eingabe(&konten);
    ausgabe(konten,anz);
    
    free(konten);//den per malloc() angeforderten Speicher wieder freigeben
    

    @cvcv: Herzlichen Dank für das Vertrauen 🙄



  • WHUT, ich habe ne Steckdose gefunden 😮

    So, ich hab mir malloc() mal eben reingezogen :

    http://www.cplusplus.com/ schrieb:

    void * malloc ( size_t size );

    Allocate memory block
    Allocates a block of size bytes of memory, returning a pointer to the beginning of the block.

    The content of the newly allocated block of memory is not initialized, remaining with indeterminate values.

    Parameters

    size
    Size of the memory block, in bytes.

    So mal sehen ob ich das eben auf dein Programm übertragen kann ... müsste ja so dann aussehen :

    //Hier liest du wie gewohnt ein, wieviele Konten der Benutzer erstellen will
    Konto* konten = (Konto*)malloc( anz*sizeof(Konto) );
    //Hier loopst du dann.
    

    Du benutzt diesen "konten"-Zeiger jetzt einfach wie ein Array. Zb : konten[0].daten = bla; konten[1].daten = bub; etc.



  • @Cstoll Gerne gerne 🙂

    Ach : Gewöhn ihm doch gleich an schööön sauber zu sein, also prüf ob malloc() gefailed hat oder nicht 😛


Anmelden zum Antworten