Weiß jemand, warum die Weite der "zweite" Arraydimension im formalen Parameter benötigt wird?



  • Da ich mit **(arr + 1) auf den ersten Wert des zweiten inneren Arrays zugreifen kann, muss es einen Pointer *(arr + 1) geben, der auf diesen Zeigt.
    Und auf diesen Pointer liegt eine Speicherstelle weiter als der Pointer auf den »arr« Zeigt, denn »arr« zeigt auf den Pointer, der auf das erste Element des ERSTEN inneren Arrays zeigt.



  • Wen du ein echtes 2D-Array meinst

    int feld[3][2] = { {0, 1}, {2, 3}, {4, 5} } ;
    

    Dann sind da nur Nutzdaten. Nimm einen Debugger und schau es dir an.

    Der Compiler macht bei einem Zugriff darauf aus dem feld[i][j] ein (feld+i2+j)
    Wie du siehst, ist darin die 2 zur Berechnung des Indizes enthalten.
    Die Größe des höchsten Index spielt dagegen keine Rolle. Wenn du den falsch angibst, ist das dein Problem.
    Wie man auch sehen kann, ist das auch nur ein einfacher Zeiger.

    Der Compiler kennt im Scope von feld die genaue Größe und kann daher auch Zwischenzeiger generieren. Diese sind aber nirgends gespeichert.



  • Um es nochmal deutlich zu machen:
    Ein 2D Array ist ein 1D Array!
    Aus array[i][j] *(array + i * columns + j).
    Dafür braucht der aber columns, sonst geht die Berechnu.g nicht.
    Und deshalb musst du sie angeben.



  • Ach so einer bist du. Ich will 10 Minuten meines Lebens zurück! 😞



  • Danke DirkB, die Unterscheidung zwischen Stack und Heap muss es sein.



  • Was für einer ist "so einer"?



  • Nein, Stack und Heap sind C völlig egal.

    Und bei

    int zeile1[2] = {0,1};
    int zeile2[2] = {2,3};
    int zeile3[2] = {4,5};
    
    int feld *[3];
    feld[0] = zeile1;
    feld[1] = zeile2;
    feld[2] = zeile3;
    

    ist auch kein Heap im Spiel.
    Hier sind richtige Zeiger für die Zeilen im Spiel.
    feld ist hier kein echtes 2D-Array, auch wenn beim Zugriff auf die Elemente die gleiche Schreibweise benutzt wird.



  • Bashar schrieb:

    Ach so einer bist du. Ich will 10 Minuten meines Lebens zurück! 😞

    Dito.



  • Mit der Unterscheidung von Stack und Heap hab' ich gemeint, was ich unter "Der Compiler kennt im Scope von feld die genaue Größe und kann daher auch Zwischenzeiger generieren. Diese sind aber nirgends gespeichert." verstanden habe.
    Dein Code funktioniert leider nicht. Ich glaub' der Indirektionsstern muss vor »feld«, aber auch dann versteh' ich's nicht ganz, muss es jetzt aber auch dabei belassen und später noch mal drüber nachdenken.
    Guten Abend.



  • Ja klar muss das

    int *feld[3];
    

    sein. 🙄



  • rednaZ schrieb:

    Was für einer ist "so einer"?

    Sorry, ich reg mich wahrscheinlich mehr darüber auf als gerechtfertigt ist. Ich war mit 12 auch so, aber da gabs nur Lehrer als Opfer und kein Internet... (Falls du absolut keine Ahnung hast, worum es geht: Deine Entgegnung auf die gegebenen Antworten, die mit "Nein, ..." anfängt.)


  • Mod

    @rednaZ:

    int foo(void) {}
    int main()
    {
        foo(); // klar
        (*foo)(); // ?
        (******************************foo)(); // ???
    }
    

    stauen, verstehen und dann zu der Frage mit den Arrays zurückkehren.



  • Zeiger auf Funktionen (gleichbedeutend mit Funktionsnamen) sind völlig anders zu behandeln und inkompatibel zu Datenzeigern.
    Demzufolge ist auch die Dereferenzierung via '*' anders zu betrachten und ergibt (sinnigerweise) dann auch unterschiedliche Ergebnisse.


  • Mod

    anders wie?



  • Wutz schrieb:

    Zeiger auf Funktionen (gleichbedeutend mit Funktionsnamen) sind völlig anders zu behandeln und inkompatibel zu Datenzeigern.
    Demzufolge ist auch die Dereferenzierung via '*' anders zu betrachten und ergibt (sinnigerweise) dann auch unterschiedliche Ergebnisse.

    Das ist natürlich nicht korrekt. Der Typ einer Funktion ist kein Zeigertyp.

    ISO/IEC 9899:1999 6.9.1 (2) schrieb:

    The identifier declared in a function definition (which is the name of the function) shall have a function type, as specified by the declarator portion of the function definition.

    und

    ISO/IEC 9899:1999 6.2.5 (1) schrieb:

    The meaning of a value stored in an object or returned by a function is determined by the type of the expression used to access it. (An identifier declared to be an object is the simplest such expression; the type is specified in the declaration of the identifier.) Types are partitioned into object types (types that fully describe objects), function types (types that describe functions), and incomplete types (types that describe objects but lack information needed to determine their sizes).

    Es wäre ja auch nicht logisch. Wenn Funktionen Zeigertypen hätten, welchen Typ hätte das, worauf sie zeigen? (********f)(); liefe dann jedenfalls nicht mehr.

    Wie Arrays zerfallen Funktionen implizit in Zeiger, aber wo Arrays in Zeiger auf ihr erstes Element zerfallen, zerfallen Funktionen in Zeiger auf sich selbst:

    ISO/IEC 9899:1999 6.3.2.1 (4) schrieb:

    A function designator is an expression that has function type. Except when it is the operand of the sizeof operator) or the unary & operator, a function designator with type ‘‘function returning type’’ is converted to an expression that has type ‘‘pointer to function returning type’’.



  • @TE: Dass

    #include <stdio.h>
    
    int main(void) {
      int arr[][3] = {
        { 1, 2, 3 },
        { 4, 5, 6 },
        { 7, 8, 9 }
      };
    
      int i;
      for(i = 0; i < 9; ++i) {
        printf("%d", arr[0][i]);
      }
      putchar('\n');
    
      return 0;
    }
    

    "123456789" ausgibt, sollte Beweis genug sein, dass dieser Zeigerindirektionsunfug stumpf nicht wahr ist. Ein zweidimensionales Array ist ein Array von Arrays, nicht ein Array von Zeigern. Jedes dieser Arrays zerfällt bei Bedarf in einen Zeiger auf sein erstes Element -- arr in einen int ()[3], arr[0], arr[1] und arr[2] in int, aber deswegen sind sie jeweils keine Zeiger.

    Dass die inneren Dimensionen bei der Zeigerübergabe angegeben werden müssen, liegt daran, dass die inneren Dimensionen in der Funktion dazu gebraucht werden, die Speicherposition eines Elementes bei der Dereferenzierung zu errechnen. arr[i][j] ist letzendlich nur arr[0][i * DIMENSION + j].



  • @seldon: Ich denke, Wutz meint "anders als bei Arrays", also dass f und *f "unterschiedliche Ergebnisse [als bei Arrays]" gibt.



  • Dann könnte man genau so gut sagen, Zeiger auf void seien ganz anders zu behandeln und inkompatibel zu Zeigern auf char, und der Begriff "Datenzeiger" ergäbe keinen Sinn. Die Dereferenzierung funktioniert bei Funktionszeigern genau wie bei Zeigern auf Arrays genau wie bei Zeigern auf alles andere. Dass man unterschiedliche Dinge kriegt, wenn die Zeiger auf unterschiedliche Dinge zeigen, ist klar und erfordert keine andere Betrachtungsweise.

    Vielleicht drückt Wutz sich nur sehr unklar aus. Für mich sieht es aber eher so aus, dass er sich da Dinge zusammengereimt hat und auf dem Holzweg gelandet ist.


Anmelden zum Antworten