const bei mehrdimensionalen Arrays



  • Gegeben sei der Integer i(int i; ),
    sowie der Zeiger ptr auf i(int* ptr = &i; )
    und der Zeiger ptr0 auf ptr(int** ptr0 = &ptr).

    Ich will mit ptr0 arbeiten, aber er darf i nicht veraendern koennen.
    Also hab ich ptr0 als const deklariert.
    Wie kann ich i vor ptr0 schuetzen? Bzw. etwas allgemeiner formuliert: Wie kann ich bei mehrdimensionalen Arrays solche Referenten vor Schreibzugriff aus Ebenen, die hoeher als unmittelbar ueber dem Referenten liegen schuetzen?

    thx in advance



  • Das ist im Allgemeinen der Unterschied zwischen "const int *i" und "int *const i" 😉
    Siehe auch: http://www.parashift.com/c++-faq-lite/const-correctness.html#faq-18.5



  • *nochmalDrueberNachdenk*



  • Raptor schrieb:

    Lies nochmal genau

    Dito 😉

    Raptor schrieb:

    Wenn ich ptr0 als int ** const deklariere loest das mein Problem nicht.

    Jo, weiß ich, weil "int **const" ein konstanter Pointer auf einen Pointer auf einen int ist. Was du willst ist aber ein Pointer auf einen Pointer auf einen konstanten int, und das ist "const int **".
    Folgender Bleistift:

    #include <iostream>
    
    int
    main(int argc, char **argv)
    {
      int i = 42;
      int *pi = &i;
      const int *const *ppi = &pi;
    
      **ppi = 23;
      std::cout << **ppi;
    
      return 0;
    }
    

    Kompostiert:

    thomas@Majestix:~/Source/temp$ g++ main.c++ -Wall
    main.c++: In function »int main(int, char**)«:
    main.c++:10: Fehler: assignment of read-only location
    thomas@Majestix:~/Source/temp$
    

    Es ist nicht nur eine Warnung, es ist ein Fehler, dem **ppi etwas zuzuweisen.
    Das funktioniert auch (oder besser: funktioniert auch nicht *g*), wenn ppi ein "const int **" wäre. Allerdings gäbe es dann in Zeile 8 einen Fehler, weil ein "type **" nicht auf einen "const type **" gecastet werden kann. Stattdessen kann man aber einen "type *" auf "const type *" casten (merke: erst der Doppelpointer geht nicht), weshalb ppi vom Typ "const int *const *" ist. Das Resultat liest sich für den Programmierer wie: "Ein Pointer auf einen konstanten Pointer auf ienen konstanten int". Damit sorgt die Type Safety dafür, daß i tatsächlich nicht verändert werden kann, auch nicht durch Dereferenzieren von ppi.

    Edit: Merke: Pointer-Syntax in C++ ist ziemlich genau und ziemlich einfach, man muss es nur einmal verstanden haben 😉

    Edit Reloaded:
    Die ganze "const const"-Problematik kannst du umgehen, indem (bezogen auf mein Beispiel) pi ein "const int *" ist, dann darf auch ppi "nur" ein "const int **" sein. Das illegale hier ist nämlich nur die Zuweisung, nicht die Art der Pointer an sich. Aber ich weiß nicht, ob du auch einen "const int *" gebrauchen kannst, das kommt auf deinen konkreten Code an.



  • Ich habs verstanden 😃
    Ich wollte grade damit kontern, wie man denn dann den "Mittelteil" schuetzen kann, weil ja z.B. das const in int const**** und int**** const nur die beiden Enden des Baumes, den die ganzen Pointer bilden schuetzt.
    Allerdings kann man das folgendermassen machen:

    #include <iostream>
    using namespace std;
    
    int main()
    {
    	int i(42);
    	int * pi = &i;
    	int** ppi = &pi;
    
    	//So wirds gemacht :) :
    	const int* const * const* const pppi = &ppi;
    	***pppi = 24; //ERROR
    	**pppi = NULL; //ERROR
     	*pppi = NULL; //ERROR
    	pppi = NULL; //ERROR
    	cout << i << endl;
    }
    

    Und die Fehlermeldung ist diese hier:

    UniX:~/test$ g++ consttest.cpp
    consttest.cpp: In function 'int main()':
    consttest.cpp:13: error: assignment of read-only location
    consttest.cpp:14: error: assignment of read-only location
    consttest.cpp:15: error: assignment of read-only location
    consttest.cpp:16: error: assignment of read-only variable 'pppi'
    UniX:~/test$
    

    Der Schluessel ist es wirklich von rechts nach links zu lesen.
    Vielen Dank! 🙂



  • Raptor schrieb:

    Der Schluessel ist es wirklich von rechts nach links zu lesen.

    Jupp, weil die type modifiers in C selbst eine right-to-left associativity haben. Genauso wie der assignment operator (=). Deswegen geht auch

    int i, j, k, l, m;
    i = j = k = l = m = 42;
    

    Wenn du das von links nach rechts liest, kommst du auf keinen grünen Zweig, deswegen geht das Konstrukt in vielen anderen Sprachen auch nicht.
    In C kannst du Typen nahezu beliebig genau deklarieren und kriegst (fast) immer genau das Ergebnis, das du geschrieben hast, egal was du erwartest 😃


Log in to reply