Mehrdimensionale arrays mit Aufzählungstyp



  • Hallo zusammen,

    unser Prof will dass wir für nächste Woche eine Aufgabe mit einem Mehrdimensionalen Array lösen.
    Das Array soll die Umsätze einer Firma in 4 Quartalen und 6 Regionen einlesen. Die Quartale sollen in int und die Regionen in einem enum Typ eingelesen werden.

    Die Umsätze für Land und Region sollen dann einzeln eingelesen werden. Also 4x6 Felder.
    Nun hab ich überhaupt nicht die leiseste Ahnung wie er sich das vorstellt. Irgendwie seh ich den Sinn dahinter nicht für das Array einen Aufzählungstyp zu nehmen. In der Hörsaalübung haben wir dafür eine einfache int variable genommen.

    enum land{rlp, nrw, bayern, berlin, sachsen, bawue};
        land region;
        land umsatz[4][region];
    
        for (int i=0; i<4; i++){
            for (int j=0; j<bawue; j++)
                 cin >> umsatz[i,j]; //??? Warum geht das nie?
        }
        for (int i=0; i<4; i++){
            for (int j=0; j<bawue; j++){
                cout << umsatz[i,j];
            }
            cout << endl;
        }
    

    Nun hab ich 2 Probleme. Das erste ist, dass ich irgendwie keine enum variablen einlesen kann. Daran probier ich mich jetzt schon länger. GEHT DAS ÜBERHAUPT?? Enum variablen über cin einlesen? Der compiler meckert immer bei dem cin. Mit dem Cout klappts teilweise auch nicht richtig.
    Und das zweite wäre wo der sinn steckt es als enum typ zu machen. Ist doch das selbe als wenn ich einfach ein int nehme.

    Und wie les ich das denn ein? Ich hab in Google rausgefunden das das angeblich nicht geht. Aber warum sollte unser Prof was unmögliches von uns verlangen?

    Mit dem cout von enum typen hab ich auch probleme. Hab hier mal ein kleines testprogramm gemacht. Da funktioniert es auch nicht. Ich hab nicht mal ne Fehlermeldung. Es kommt nur "run failed".

    enum farbe {blau=0, rot=1, gruen=2};
        farbe color;
        farbe array[color];
    
        for (int i=0; i<gruen; i++)
            cout << array[i];
    

    Vielen dank schonmal für Hilfe!



  • Aber Du brauchst doch kein Feld von 4*6 Ländern, sondern Umsätzen.

    Also eher so:

    enum land {rlp, nrw, bayern, berlin, sachsen, bawue, landmax};
    
    typedef int (quartalsergebnisse)[landmax][4];
    
    void read(quartalsergebnisse& q){
      using namespace std;
      for (int i=0; i<landmax; i++){
        for (int j=0; j<4; j++)
          cin >> q[i][j]; //??? Warum geht das nie?
      }
    }
    
    void write(const quartalsergebisse& q){
      // ...
    }
    
    int main(){
      quartalsergebnisse q;
      read(q);
    }
    


  • Zuerst mal:

    umsatz[i,j]
    // Falsche Syntax, so soll's aussehen:
    umsatz[i][j]
    

    Zweitens:

    land region;
    land umsatz[4][region];
    
    // Ich glaube du willst das:
    
    int umsatz[4][6] // 4 Quartale, 6 Länder
    /* umsatz ist eine 2-dimensionale 4x6 Integer Matrix,
       welche alle Umsätze für die jeweiligen Quartal-Land Kombinationen speichert. */
    
    // Indexieren kannst du es dann so:
    land irgendeinLand = bayern;
    int irgendeinQuartal = 3;
    umsatz[irgendeinQuartal][irgendeinLand] = 123;
    

    Cabooze schrieb:

    Das erste ist, dass ich irgendwie keine enum variablen einlesen kann. Daran probier ich mich jetzt schon länger. GEHT DAS ÜBERHAUPT??

    Nö, einen Enum einlesen geht nicht. Macht ja auch keinen Sinn.
    Beim Einlesen von Daten über cin willst du ja, den vom Benutzer eingegebenen, rohen String als irgendeinen Datentyp interpretieren.
    Mit enum definierst du aber nur Aufzählungen bzw. Konstanten. Deine Code wäre daher ähnlich zu diesem Beispiel:

    cin >> 2; // In deinem Codeschnipsel ist bayern = 2
    // Enum macht nicht viel mehr, als Namen für Integer Literale zu vergeben.
    

    Das macht einfach keinen Sinn, was dir der Compiler auch mitteilt.

    Was du aber machen kannst, ist einen int einlesen und diesen zu deinem Enum casten. Und andersrum'.

    int input;
    cin >> input;
    land landInput = (land)input;
    
    int umsatzInput;
    cin >> umsatzInput;
    
    umsatz[i][landInput] = umsatzInput;
    // Wobei i eben dein Quartalindex ist.
    
    // cout in Kurzform wäre dann:
    cout << (int)umsatz[i][j];
    

    Lese dich bei Gelegenheit mal über enums ein, das sollte helfen.



  • Okay aber ist das nicht unnötig kompliziert? Ich meine... die Aufgabe soll ja lauten, dass ich jedes der insgesamt 24 Felder befülle. Also im Prinzip mit einer Schleife. Da ich ja weiterhin aber die Regionsfelder des Aufzählungstyps ebenfalls befüllen muss macht es das doch nur total sinnlos und aufwändig oder?

    Also zu deinem Beispiel:

    land region;
    land umsatz[4][region];
    
    // Ich glaube du willst das:
    
    int umsatz[4][6] // 4 Quartale, 6 Länder
    /* umsatz ist eine 2-dimensionale 4x6 Integer Matrix,
       welche alle Umsätze für die jeweiligen Quartal-Land Kombinationen speichert. */
    
    // Indexieren kannst du es dann so:
    land irgendeinLand = bayern;
    int irgendeinQuartal = 3;
    umsatz[irgendeinQuartal][irgendeinLand] = 123;
    

    Hab ich verstanden. Aber du hast ja den Wert schon als bayern vordefiniert. Aber um jetzt jedes der Felder einzutippen brauch ich ja so n algorithmus noch der die int in die enum typen konvertiert. Das ist doch total umständlich. Wo ist da der sinn? Wenn ich das Feld einfach über int variablen deklariere und einlese ist es doch viel einfacher... Und das was du mir da drunter gepostet hast haben wir bisher nie gemacht. Irgendwie versteh ich das alles grad nicht. Unser Prof macht normal nie was, was wir nicht auch in der Vorlesung behandelt haben.. Ich bin mir grad gar nicht mal sicher ob die mir das erlauben würden wenn ich das so vorzeige...



  • Hi,

    und der Sinn und Zweck, weshalb man das mit Enums machen sollte, statt einfach nur mit dem Integer Datentyp:

    a) So ein sprechendes Literal ist doch bedeutend lesbarer im Quellcode, als wenn da später einfach irgendwo 'ne Zahl steht.

    int Land = 5;
    ...
    if(Land == 5)   // so'ne Magic Number wirst du bei späterem drüberfliegen deines
                    // codes einfach nicht so schnell erkennen, bzw. interpretieren
                    // können wie z.B. im folgenden Beispiel
    {
    }
    

    vs.

    land Land = bawue;
    ...
    if(Land == bawue)  // hier sieht man auch noch nach Jahren direkt, dass ein 
                       // Vergleich der Land-Variablen mit Baden-Würtemberg gemacht 
                       // werden soll.
    {
    }
    

    b) Typsicherheit ... Wenn du irgendwann an eine Funktion einen Wert übergibst, kannst du auch den Enum-Typen wählen. Somit ist dann jedem, der deine Funktion nutzen will direkt klar, welchen Typ du dort erwartetst und was für mögliche Werte dieser Typ hat (muss man halt bei der Enum-Deklaration nachschauen). Wenn du statt dessen einen Integer als Variablentypen in deiner Funktion erwartest, könnte ein anderer Programmierer auf die Idee kommen, dort irgendeine beliebige Integerzahl reinzupacken.

    void setLand(int Laendercode);
    

    vs.

    void setLand(land Laendercode);
    

    Bei der unteren Methode steht fest, dass dort ein Wert aus der Enumeration erwartet wird (Wert 0-5 bei deinem Beispiel). Im oberen Beispiel könnte man aber denken, dass eine 42 auch erlaubt wäre.



  • Ok. Und wieso funktioniert das dann schon wieder nicht:

    template <typename t>
    void einlesen(t A[], int n, land region){
        for (int i = 0; i <= n; i++) {
            for (int j = 0; j <= region; j++)
                cin >> A[i][j];
        }
    
        for (int i = 0; i <= n; i++) {
            for (int j = 0; j <= region; j++)
                cout << A[i][j] << "  ";
            cout << endl;
        }
    }
    
    int main() {
    
        const int n=3;
        //const int m=4;
        enum land {rlp, nrw, bayern, berlin, sachsen, bawue};
        land region;
        int Umsatz[n][region];
    
        einlesen(Umsatz,n,region);
    

    Das ist nämlich was ich als nächstes machen wollte. Den ganzen Kram als Funktion



  • Ohne mich aufdrängen zu wollen: mein Posting oben hast Du gesehen?



  • Furble Wurble schrieb:

    Ohne mich aufdrängen zu wollen: mein Posting oben hast Du gesehen?

    Oh verzeihung. Hab ich vergessen. Ehrlich gesagt verstehe ich manche Sachen in deinem Algorithmus nicht ganz. Z.B was typedef für ein Befehl ist.
    Wenn ich es richtig verstanden habe wäre das dann so etwas wie das hier?

    template <typename t>
    void einlesen(t A[], int n, int m){
    
        enum land {rlp, nrw, bayern, berlin, sachsen, bawue};
        land region;
    
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < bawue; j++)
                cin >> A[i][j];
        }
    
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < bawue; j++)
                cout << A[i][j] << "  ";
            cout << endl;
        }
    }
    


  • Sorry: ich musste nochmal weg.

    Was ich gemacht habe ist nicht so schwer:

    Erstmal habe ich noch den künstlichen enum-Wert landmax eingeführt. Damit kannst Du bequem durch den enum iterieren.
    Und wenn Du noch Länder hinzufügen willst musst Du nur darauf achten, dass landmax weiterhin hinten in der Aufzählung steht. Damit bist Du schon mal diese magische "6" los.
    Die "4" ist nicht so magisch - wahrscheinlich ist, dass Jahre auch weiterhin in 4 Quartale geteilt werden. 😉

    Dann habe ich mir vorgestellt, wie ein Excel-Sheet aussähe. Sicherlich die Länder als Zeilen und die Quartale als Spalten. Anders wär's blöd, weil man mit einem neuen Land ja eine neue Spalte hätte und ein Sheet, dass immer weiter nach rechts, anstatt nach unten wächst.
    Also habe ich die Dimensionen vertauscht: int[landmax][4];

    Ein typedef ist eine neue Typdefinition.
    typedef int quartalsergebnisse[landmax][4]; // quartalsergebnisse ist ein Typ landmax Arrays von 4 int

    Bequemerweise kann ich sogar noch die innere Dimension weglassen:
    typedef int quartalsergebnisse[][4];
    Warum das so ist, ist jetzt glaube ich egal.

    Damit kann ich dann die Funktionen void read(quartalsergebisse&); und
    void write(const quartalsergebnisse&); deklarieren.
    Das ist doch wesentlich besser als 3 Parameter!?

    Und weils so einfach ist:
    Du könntest z.B. mit einem typedef auch noch den int verschwinden lassen. Denn was ist ein int ? Euro? Cent? Dollar? Muschelschalen?
    `

    typedef int euro;

    typedef euro quartalsergebnisse[][4]; // qartalsergebnisse ist ein Typ Array von unbekannter Größe von Array von 4 EurobeträgenAber das wirklich nur als Beispiel, wie einfachtypedef` zu verstehen ist.



  • OKay und was hälst du von dem was ich oben zusammengepfriemelt habe? Kann ich das so lassen? Wäre das auch ok?
    Wir dürfen halt in den Hausaufgaben keine Befehle nehmen die wir noch nicht hatten. Deswegen lass ich typedef und so sachen besser mal weg.



  • Cabooze schrieb:

    template <typename t>
    void einlesen(t A[], int n, land region){
        for (int i = 0; i <= n; i++) {
            for (int j = 0; j <= region; j++)
                cin >> A[i][j];
        }
    
        for (int i = 0; i <= n; i++) {
            for (int j = 0; j <= region; j++)
                cout << A[i][j] << "  ";
            cout << endl;
        }
    }
    
    int main() {
     
        const int n=3;
        //const int m=4;
        enum land {rlp, nrw, bayern, berlin, sachsen, bawue};
        land region;
        int Umsatz[n][region];
        
        einlesen(Umsatz,n,region);
    

    Ich hab' da ein paar Fragen:

    Wieso ist einlesen() ein template?
    Wieso ist der erste Parameter ein eindimensionales Array von t von unbekannter Größe? (Bonus: was ist t?, aka: was deduziert der Compiler ist t?)
    Was ist n=3??? (Tertiale?)
    Wofür ist region? Z.22. Welchen Wert hat es?
    Was macht Zeile 23? Kompiliert das?
    Z. 25.: Da stimmt doch das erste Argument nicht? Oder doch? Wieso kompiliert das?

    Unbedingt die Warnungen im Compiler einschalten.

    Ich erwarte gar nicht, dass Du alle beantworten kannst. Aber wenn Du den Code bei mir als Lehrendem abgibst, solltest Du ja eigentlich wissen, was Du da tust.



  • Wieso ist einlesen() ein template?
    Weil das doch ein 2-dimensionales Feld ist. Haben wir die Woche gelernt, dass man die nur mit einem template richtig übergeben kann.

    Wieso ist der erste Parameter ein eindimensionales Array von t von unbekannter Das war dann wohl ein Fehler. Das sollte 2D sein.

    Größe? (Bonus: was ist t?, aka: was deduziert der Compiler ist t?)
    Der Template Datentyp. Oder?^^

    Was ist n=3??? (Tertiale?)
    Weil die For Schleife bis i<=3 zählt. Ich hätte auch n=4 machen können und hätte das "=" weglassen können.

    Wofür ist region? Z.22. Welchen Wert hat es?
    Hm das sollte die Variable des Typs Land sein. Wert? Gute Frage. Ich dachte der nimmt automatisch den Wert der höchsten Variable im Enum an. Somit 5. Und dachte, das übergibt er dann direkt ins Feld unten drunter, womit dann die Größe festgelegt wird.

    Was macht Zeile 23? Kompiliert das?
    Siehe vorige Frage/Antwort.

    Z. 25.: Da stimmt doch das erste Argument nicht? Oder doch? Wieso kompiliert das?
    Was stimmt da nicht? Solang die Reihenfolge stimmt sind doch die Variablennamen im Funktionsaufruf egal, dachte ich?

    Das Programm kompiliert übrigens nicht. Aber die Fehlermeldung bringt er mir nur in Z.2 und im Funktionsaufruf.



  • Cabooze schrieb:

    Wieso ist einlesen() ein template?
    Weil das doch ein 2-dimensionales Feld ist. Haben wir die Woche gelernt, dass man die nur mit einem template richtig übergeben kann.

    Wieso ist der erste Parameter ein eindimensionales Array von t von unbekannter Das war dann wohl ein Fehler. Das sollte 2D sein.

    Größe? (Bonus: was ist t?, aka: was deduziert der Compiler ist t?)
    Der Template Datentyp. Oder?^^

    siehe unten ab "Das kompiliert, weil..."

    Cabooze schrieb:

    Was ist n=3??? (Tertiale?)
    Weil die For Schleife bis i<=3 zählt. Ich hätte auch n=4 machen können und hätte das "=" weglassen können.

    Das habe ich gesehen. Mach es doch so. Wo for-Schleifen vorkommen, werden die meist von [0,n) gezählt. Also mit kleiner, statt kleiner-gleich.
    Und eigentlich brauchst Du noch nichtmal ein n. Weil - wie ich schon gesagt habe - Jahre immer 4 Quartale haben.

    Cabooze schrieb:

    Wofür ist region? Z.22. Welchen Wert hat es?
    Hm das sollte die Variable des Typs Land sein. Wert? Gute Frage. Ich dachte der nimmt automatisch den Wert der höchsten Variable im Enum an. Somit 5. Und dachte, das übergibt er dann direkt ins Feld unten drunter, womit dann die Größe festgelegt wird.

    Nein. Das nimmt irgendeinen Wert an. Hier würde ich Dir wirklich ans Herz legen einen speziellen Wert anzulegen. Wie mein "landmax" eben.

    Cabooze schrieb:

    Z. 25.: Da stimmt doch das erste Argument nicht? Oder doch? Wieso kompiliert das?
    Was stimmt da nicht? Solang die Reihenfolge stimmt sind doch die Variablennamen im Funktionsaufruf egal, dachte ich?

    Das kompiliert, weil einlesen() ein template ist und der Compiler Magie verwendet.

    Angenommen, da stünde

    int umsatz[4][6];
    einlesen(umsatz, 4, 6);
    

    Dann würde der Compiler umsatz umwandeln in einen pointer auf int[6] . Und letzteres wäre dann auch der deduzierte Typ von t - also int[6] .
    Ich kann mir schwerlich vorstellen, dass das so gelehrt wird.

    Lass das mit dem template. (*)
    Wenn Du Dich mit dem typedef nicht anfreunden kannst, dann nimm meinetwegen

    void einlesen(int umsatz[][4], int anzahl_laender);
    

    Oder muss der Typ von Umsatz unbedingt int[4][6] sein?

    😉 Es gibt mindestens eine Möglichkeit, templates hier doch gewinnbringend einsetzen zu können. Ist aber eher exotisch.



  • In der Aufgabenstellung wird definitiv ein 2-Dimensionales Array verlangt dass als Funktionsparameter verwendet werden soll. Also ja ich fürchte da komm ich nicht drum herum. Da haben wir leider nur templates gemacht...
    Ich hab sonst keinen plan...
    Ich bin jetzt langsam am verzweifeln mit der Aufgabe



  • Cabooze schrieb:

    In der Aufgabenstellung wird definitiv ein 2-Dimensionales Array verlangt dass als Funktionsparameter verwendet werden soll. Also ja ich fürchte da komm ich nicht drum herum. Da haben wir leider nur templates gemacht...
    Ich hab sonst keinen plan...
    Ich bin jetzt langsam am verzweifeln mit der Aufgabe

    Lass Dich von mir nicht verwirren.

    Ganz klar. Ganz einfach:
    Nimm kein template.
    Nimm ein zweidimensionales Array (wie gefordert):

    void einlesen(int umsatz[4][6]); // beide Dimensionen festverdrahtet
    oder
    void einlesen(int umsatz[6][4]); // meine Version (s. Excel Argument oben)
    oder
    void einlesen(int umsatz[][spalten], int reihen); // die zweite Dimension ist festverdrahtet, die erste wird als Argument übergeben
    

    Was genau Ihr da mit templates gemacht habt erschließt sich mir leider gar nicht. Aber es erstmal konkret hinzubekommen und nachher ein template draus zu basteln ist möglich.



  • Okay danke. Dann probier ich damit mal weiter dran rum...


Log in to reply