Konstanten und Arrays



  • Hallo Leute,

    Erstmal Danke im Voraus für eine Antwort.

    Es ist nur eine kleine Sache, die mich momentan ein bisschen stutzen lässt:

    int main()
    {
    int a = 3;

    const int Groesse = a;

    bool MyFeld[Groesse]; // Funktioniert nicht!

    cout << Groesse << endl; // Funktioniert!

    return 0;
    }

    Hier wird eine normale Variable mit 3 definiert. Dann wird eine Konstante erzeugt und auf 3 gesetzt.
    Ich habe schon mit den Konstanten experimentiert und weiß, dass ich diese Konstante normal verwenden könnte.
    Die Fehlermeldungen kommen alle aus der Zeile mit dem Array, was ich deklariere, weil dort anscheinend kein konstanter Wert angegeben ist.

    Jetzt interessiert mich: warum funktioniert das hier nicht, wenn Groesse doch eine normale Konstante ist ? Wenn ich "Groesse" normal auf 3 setzen würde, würds doch auch klappen. Und der cout-Befehl funktioniert doch auch.

    Warum kann man damit dann kein Array deklarieren ?

    PS: mir ist bewusst, dass man dieses Problem auch mit Zeigern und Speicherreservierung lösen könnte. Trotzdem interessiert es mich, warum es nicht so klappt.

    Herzlichen Dank und Freundliche Grüße
    anonym83



  • int main()
    {
    	int a = 3;
    
    	const int Groesse = a;
    
    	bool MyFeld[Groesse];     // Funktioniert nicht!
    
        cout << Groesse << endl   // Funktioniert!
    
    	return 0;
    }
    


  • Das Problem ist, dass der Compiler zur Kompilierungszeit wissen muss was das Array für eine Grösse hat. Schau z.B mal das hier an:

    void foo(int n)
    {
     const int n2 = n;
     int foo[n2];
    }
    

    Woher soll der Compiler wissen wie viel Speicher er für das Array bereitstellen muss?



  • genau, wie Drakon es gesagt hat, muss der Compiler zum Übersetzungszeitpunkt wissen, wie groß das Array sein wird.

    daher geht dann auch:

    int main() { 
        const int a = 3; 
        const int Groesse = a; 
        bool MyFeld[Groesse];     // funktioniert 
        cout << Groesse << endl   // funktioniert 
    }
    


  • weil es keine konstante ist. groesse hat den wert von a, der zu dem zeitpunkt in a war, und lässt sich nicht mehr ändern ( groesse = 3; würde zu einem fehler führen)

    warum das mit dem array nicht geht? weil der compiler zur compilezeit wissen will, wie gross das array sein soll und das ist bei dir offensichtlich nicht der fall (ok, bei so einem trivialen beispiel würde ich eigentlich vom compiler verlangen, dass ers trotzdem macht, aber spricht genug dafür es nicht zu machen)

    im umkehrschluss wäre ja auch sowas möglich:

    int main()
    {
       int a;
       cin >> a;
    
       const int GROESSE = a;
       int feld[GROESSE];
    
       return EXIT_FAILURE;
    }
    

    was du da verlangst wäre eine "konstantiierung"...

    EDIT: wichtigen vertuer rictig gestellt
    @nachfolgenden drakon: sry hab mich vertippt, meinte natürlich compiletime und NICHT laufzeit



  • Skym0sh0 schrieb:

    warum das mit dem array nicht geht? weil der compiler zur laufzeit wissen will, wie gross das array sein soll

    Der Compiler muss während dem kompilieren Speicher für das Array vorsehen. Mit der Laufzeit hat das nichts zu tun.



  • Die Sprache C++ verwendet oft Konzepte, die sich nicht 1:1 am Code herleiten lassen, wenn man die Sprache nicht kennt. Deswegen sollte man sich auch ein schlaues Buch schnappen und dort diese Konzepte nachlesen. Das Konzept, welches hier eine Rolle spielt ist das Konzept der "konstanten Ausdrücke". Um ein Array a la

    int arr[N];
    

    zu definieren, muss N ein "konstanter Ausdruck" sein. Ein "konstanter Ausdruck" ist aber nicht dasselbe wie eine const-Variable. Eine const-Variable kann ein konstanter Ausdruck sein, muss aber nicht. Das kommt nämlich drauf an, wo sie deklariert und wie sie initialisiert wird. "const" heist einfach nur "kann nicht mehr geändert werden". Der Unterschied zu einem konstanten Ausdruck ist der, dass der Wert eines konstanten Ausdrucks leicht zur Compile-Zeit berechenbar ist. Erstes Beispiel:

    int foo();
    
    int main() {
      const int x = foo();
      // x ist zwar const, aber kein konstanter Ausdruck
    }
    

    Beispiel 2:

    int main() {
      const int x = 40+2;
      // x ist ein konstanter Ausdruck.
    }
    

    x ist im letzten Fall deswegen ein konstanter Ausdruck, weil

    • int ein Literal-Typ ist,
    • x mit const deklariert wird und
    • x selbst mit einem konstanten Ausdruck initialisiert wird

    Und weil ein Aufruf einer "normalen" Funktion nicht Teil eines konstanten Ausdrucks sein kann (das sagt der C++ Standard), ist x im ersten Beispiel auch kein konstanter Ausdruck.

    In Deinem Fall ist a kein konstanter Ausdruck. Und weil Du Groesse mit a initialisierst und a kein konstanter Ausdruck ist, ist Groesse auch kein konstanter Ausdruck.

    "Konstanter Ausdruck" ist also strenger als nur "const". Es geht dabei um einen leicht zur Übersetzungszeit berechenbaren Wert. Erst mit C++11 gibt es die Möglichkeit, als Programmierer explizit zu sagen, dass man einen konstanten Ausdruck erzeugen möchte:

    int foo();
    
    constexpr int square(int x) { return x*x; }
    
    int main() {
      constexpr int a = 42;  // OK
      constexpr int b = a+3; // OK
      constexpr int c = foo(); // Compilier-Fehler, da der Initialisierer
                               // kein konstanter Ausdruck ist.
      constexpr int d = square(a); // OK
      constexpr int e = square(foo()); // Fehler! square ist zwar eine constexpr-
                                       // Funktion. Aber der Aufruf ist kein
                                       // konstanter Ausdruck, weil nicht alle
                                       // Parameter jeweils ein konstanter Ausdruck
                                       // sind.
    }
    

    Und weil ich hier c und e als konstanten Ausdruck erzeugen möchte, ich aber einen dazu unpassenden Initialisierer verwende, kann mir das der Compiler hier ankreiden. Er gibt mir deswegen zwei Fehler aus.

    Das mit den constexpr-Funktionen ist aber auch neu, dass man die jetzt als Teil eines konstanten Ausdrucks verwenden darf.



  • Vielen Dank.

    Ich hab nochmal woanders nachgeschlagen und da wird auch der Unterschied zwischen Runtime-Konstante und Compiletime-Konstante erklärt.

    Die konstanten Ausdrücke sind Compiletime-Konstanten (=zur Kompilierungszeit konstant). Alle anderen Konstanten sind Runtime-Konstanten und werden erst zur Laufzeit festgelegt.

    Bei einem Array braucht man die konstanten Ausdrücke (Compiletime-Konstanten).

    Gruß
    anonym


Log in to reply