Referenz auf Array fester Größe



  • Klar ist array ein Zeiger 😮

    Danke vielmals für den Hinweis mit den Klammern 🙂



  • Neku schrieb:

    Klar ist array ein Zeiger 😮

    Nein, array ist ein Array. Es darf nur im Kontext der Zeigerarithmetik als Zeiger verwendet werden.



  • Nun möchte ich aber keine Referenz auf "int*", sondern auf "int[10]"

    Was haben wir denn alles ueber Array's gelernt ?

    - Die variable "eines Array's" repraesentiert den zeiger aufs erste element.
    - Damit ist der Typ eines Arrays also Zeiger auf den ElementTyp.


    Die groesse des Arrays wird beim definieren halt nur fuer den Stack zum aufrollen gegeben.

    Preisfrage:
    void Testfunc(int ab[10]);
    wird der compiler meckern wenn ich dem nen int x[9] als parameter uebergebe ?

    Was nen compiler mit ner referenz auf nen Array mit groessenangabe macht, ist sicher nicht definiert, die meisten machen aber nen doofen zeiger draus, also kannst die groesse an der stelle nie draus ermitteln.

    Die einzige chance die hast um die Groesse (integer) in nen Typ zu bekommen, und damit volle typsicherheit zu erhalten, sind templates. Also nutze die doch dafuer ....

    Was glaubst warum plain C Arrays in C++ so gehasst und geliebt werden ? ^^

    Ciao ...



  • Der Typ ist bereits festgelegt auf wchar_t[256], da kann ich nichts machen. Ich hätte nur lieber eine Referenz mit der Größenangabe, sonst muss ich irgendwo in den Tiefen von mehreren hundert Quelldateien die Größenangabe in einem Kommentar verstecken 😛 Ist also nicht für den Compiler gedacht sondern für mich.

    *edit*
    Noch interessanter wurde es, als ich mich mit den Casts rumprügeln musste, was noch immer nicht funktioniert:

    wchar_t* (&WideStringClass::m_FreeTempPtr)[256] = *(wchar_t*(*)[256])0x00809D40;
    

    Nicht über den Sinn des ganzen nachdenken - ich hätte nur gerne eine Lösung, ob standardkonform oder nicht 😃
    Aktueller Fehler: "error C2101: '&' on constant"

    *edit2*
    Folgendes funktioniert übrigens:

    uint32& uVar = *(uint32*)0x012345678;
    


  • RHBaum schrieb:

    Nun möchte ich aber keine Referenz auf "int*", sondern auf "int[10]"

    Was haben wir denn alles ueber Array's gelernt ?

    - Die variable "eines Array's" repraesentiert den zeiger aufs erste element.
    - Damit ist der Typ eines Arrays also Zeiger auf den ElementTyp.

    Hi, ich bastel Compiler und von daher kenne ich die Frage schon. Um den Compiler zu schreiben, brauchte ich zusätzlich auch eine Lösung 😉

    In der Tat ist die Frage in C nicht so einfach, wie sie im ersten Moment scheint.
    Obwohl ihr euch widersprecht, habt ihr nämlich beide Recht. 🙂

    Willkommen im Chaos des Sprachedesigns. ^^

    Was passiert hier?

    int main(void)
    {
      char a1[5] = "12345";
      char a2[5] = "67890";
    
      char * p1  = "abcde";
      char * p2  = "fghij";
    
      p1 = p2;
      a1 = a2;
    }
    

    Bei p1=p2 sind die Erwartungen klar, die Zeiger werden überschrieben. Bei a1=a2 würde ich eine bitweise Kopie erwarten, also das die 5 Bytes von a1 überschrieben werden.
    Bei a1=a2 meldet der GCC 4 einen Typfehler, obwohl beide Typen gleich definitiv sind. Würde ich die Arrays in ein struct setzen, wäre wieder alles easy.
    Die Arrays können also keine Zeiger sein. Ein Array ist also definitiv ein eigener Typ. Somit müsste eine Unterscheidung möglich sein und damit auch eine Referenz auf int [10].

    Im Alltag ist C allerdings darauf ausgelegt, dass man diesen Unterschied nicht sieht. Der [] Operator macht nämlich bei Zeigern ohne Aufforderung eine Dereferenzierung ("*") vor der der Addition("[]"), bei lokalen Arrays auf dem Stack aber nicht (".[]"). Und das kann man im Code nicht mehr unterscheiden, da man in beiden Fällen nur "[]" schreibt. Für eine korrekte Typbehandlung müsste aber eigentlich (*var)[] schreiben, was regelmäßig braucht, aber eben nicht so hübsch aussieht.

    [] benötigt eine Position im Speicher, von der ausgehend man Addieren ("[]") kann. Also muss ein Array einen Zeiger auf das erste Element haben, obwohl es selbst kein Zeiger ist.

    Folgender Code lässt sich mit ältern Compilern fehlerfrei übersetzen. Ich habe es grade mit gcc 3.3 und gcc 4 probiert, beide akzeptieren ihn nicht mehr. Ich glaube der 2.95er nimmt ihn noch, habe aber keinen mehr hier.

    int main(void)
    {
      char Array[] = "Hallo Welt";
      char * p1 = Array;
      char * p2 = &Array;    // jetzt falsch (Typenfehler bei Zuweisung), früher identisch zu p2 = Array
    }
    

    Nach Ansicht moderner GNU Compiler, sind Arrays damit vom Typ her wohl Zeiger, den man nicht referenzieren kann, genauso wie man nicht &(&var) schreiben kann, weil &var bereits ein temporärer Zeiger ist, der keine eigene Speicherposition hat, die man erfragen könnte. Aber das Array liegt doch auf dem Stack, ist vom Typ char[] (also ein Array) und von dem Stack müsste es doch eine Adresse geben.
    &Array akzeptiert er auch, also lassen wir halt die Zuweisung mal weg:

    int main(void)
    {
      char Array[] = "Hallo Welt";
    
      printf( "%x - %x", (int) Array, (int) &Array );
    
      return 0;
    }
    

    Und siehe da: gcc 3.3 und gcc 4.0 werfen hier den zweimal den gleichen Wert aus. So ein Zufall aber auch: ein Zeiger, der auf sich selber zeigt. Ein Perpetuum Mobile der Informatik. ^^

    Das Problem entsteht durch eine syntaktische Ungenauigkeit des [] Operators, den man auf Arrays, wie auch auf Zeiger anwenden kann, obwohl ein Array vom Typ her eigentlich keine Referenz ist. Da ist ein feiner Unterschied! Denn ein Zeiger ist immer nur ein Zeiger auf ein (1.0) Datenelement, den man mit "*" dereferenziert. Kein Array, auf das man mit [] zugreift (und eben nicht dereferenziert). Wenn man das meint, müsste es eigentlich so aussehen:

    int main(void)
    {
      char *p[] = "Array";
    
      (*p)[0] = "B";
      return 0;
    }
    

    Zeiger auf ein char-Array (also nicht auf ein einzelnes char, dass man ja nicht wie ein Array durchfahren kann).

    vgl. z.B. auch:

    int main( int argc, char *argc[] );
    
    vs.
    
    int main( int argc, char **argc );
    

    Mit der Gleichsetzung von "" und "[0]", bzw "" und "[]" bei der Typdeklaration hat man sich die Unterscheidbarkeit in dieser Typen kaputt gemacht.
    Wenn Dein Typ grundsätzlich eine beliebige, aber feste Arraylänge hat, musst Du das Array in einem struct einbauen und so hast die gesuchte Typunterscheidung.

    Viel Spaß noch


  • Mod

    es ist in c oder C++ unmöglich, arrays unbestimmter größe als parameter von funktionen zu verwenden. aus diesem einen grunde gibt es eine sonderregel (6.7.5.2/5 in C99 und -kann ich jetzt auf die schnelle für C++ nicht finden). die muss auch zwingend existieren, um diese deklaration zu erlauben, denn ein array unbekannter größe ist ein unvollständiger typ, und unvollständige typen können nunmal nicht für funktionsparameter verwendet werden. diese regel besagt, dass eine deklaration mit[] so behandelt werden soll, als ob sie mit * erfolgt wäre.

    im gegensatz zu skalaren typen, sind arrays stets lvalues - und die übliche implizite wandlung in ein rvalue existiert nicht. es gibt allerdings eine implizite umwandlung in einen (rvalue) pointer auf das erste element.
    und das ist der witz daran:
    wenn der kontext ein rvalue verlangt, dann verhält sich ein array dort, als ob es ein pointer wäre (in diesem kontext kann man diese tatsächlich nicht unterscheiden). und (fast) alle oben genannten beispiele fallen eben in diese katageorie. das beweist aber nicht, das arrays pointer sind, nur das die auswahl der beispiele suboptimal ist.

    es gibt nur wenige kontexte, die ein lvalue brauchen: das brot-und-butter beispiel zuweisung klappt nun leider gerade nicht, denn ich kann arrays nicht zuweisen (eben weil es nichts passendes für die rechte seite mangels rvalue arrays gibt)
    es verbleiben operatoren, die lvalues brauchen:
    & (und wie dein beispiel richtig gezeigt hat: char * p2 = &Array ist das ergebnis eben nicht ein pointer auf char sondern ein pointer auf ein array aus 11 chars).
    sizeof - der klassiker
    zusätzlich:
    initialisierung einer referenz, hier steht rechts vom = zeichen wieder ein lvalue

    jetzt sollte klar sein, warum das

    int array[10];
    int*& ref = array;
    

    nicht geht. zwar kann array implizit in einen pointer auf das erste element, also einen pointer aiuf char gewandelt werden. das ergebnis ist aber ein rvalue, und kann folglich nicht zur initialisierung einer referenz auf (non-const) char verwendet werden.

    edit: viele (bestimmt nicht alle) rechtsschreibfehler beseitigt - heute wieder besonders schlimm



  • Ich würde einigen Leuten hier raten, ihr Grundwissen nochmal zu überprüfen. Besonders die, die Sachen wie

    Ein Array ist ein Zeiger auf den ersten Index...

    Was nen compiler mit ner referenz auf nen Array mit groessenangabe macht, ist sicher nicht definiert, die meisten machen aber nen doofen zeiger draus, also kannst die groesse an der stelle nie draus ermitteln.

    schreiben. Dieses Halbwissen verwirrt Unwissende nur. Und noch schlimmer, auch diese verbreiten dieses Halbwissen dann wieder.



  • Super, wenn ich mir das hier so ansehe, muss ich mich wohl nicht wundern dass alle paar Wochen jemand hier aufschlägt und verzweifelt versucht ein 2D-Array als Zeiger auf Zeiger zu übergeben.



  • Schön, dass ihr euch so nett unterhaltet hier, aber an meinem Problem hat sich leider noch nichts geändert. (http://www.c-plusplus.net/forum/viewtopic-var-p-is-1074379.html#1074379)



  • Neku schrieb:

    Schön, dass ihr euch so nett unterhaltet hier, aber an meinem Problem hat sich leider noch nichts geändert. (http://www.c-plusplus.net/forum/viewtopic-var-p-is-1074379.html#1074379)

    Du könntest einen neuen Typ definieren, wie ich vorgeschlagen habe mit struct oder mit typedef, diesen Typ kannst Du gleichsetzen und auch Referenzen darauf bilden.

    struct MyArray
    {
      char_t Data[256];
    };
    

    Du könntest auch eine Schleife programmieren, die 256 Bytes kopiert.
    Du könntest mit memcopy 256 Bytes kopieren.

    Du kannst nicht Arrays auf Arrays kopieren.


  • Mod

    zeig doch mal die deklaration von WideStringClass::m_FreeTempPtr



  • @Xin: Ich möchte ja eine Referenz auf das Array, anstatt es zu kopieren - darum geht es ja 😉

    @camper:

    class WideStringClass
    {
    
    public:
    
    	static wchar_t* (&m_FreeTempPtr)[256];
    	// ...
    
    };
    


  • Neku schrieb:

    @Xin: Ich möchte ja eine Referenz auf das Array, anstatt es zu kopieren - darum geht es ja 😉

    Wo ist das Problem?

    struct wchar_array256
    {
      wchar_t Data[256];
    };
    
    class WideStringClass
    {
    public:
      static wchar_array256 * m_FreeTempPtr;
    };
    

    Das sollte Dein Problem doch typgerecht lösen, oder?



  • Dann kann ich leider m_FreeTempPtr nicht wie bisher verwenden, sondern muss überall m_FreeTempPtr.Data schreiben. Der Weg über ein Struct ist schließlich etwas zu umständlich. Wenn es nicht direkt über wchar_t*(&)[256] geht, muss ich wieder zu wchar_t** zurückgehen.



  • Neku schrieb:

    Dann kann ich leider m_FreeTempPtr nicht wie bisher verwenden, sondern muss überall m_FreeTempPtr.Data schreiben. Der Weg über ein Struct ist schließlich etwas zu umständlich. Wenn es nicht direkt über wchar_t*(&)[256] geht, muss ich wieder zu wchar_t** zurückgehen.

    Immer diese Extrawünsche 😉

    class wchar_array256
    {
      private:
        wchar_t Data[256];
    
      public:
        wchar_t & operator [] (int index)
        {
          return Data[index];
        }
    };
    
    class WideStringClass
    {
    public:
      static wchar_array256 * m_FreeTempPtr;
    };
    

    Damit kannst Du jetzt auch WideStringClass::m_FreeTempPtr[ foobar ] schreiben.



  • Xin schrieb:

    Damit kannst Du jetzt auch WideStringClass::m_FreeTempPtr[ foobar ] schreiben.

    Ähh.. quatsch... der [] geht hier erstmal auf den Zeiger, nicht auf den Datentyp ^^

    (*WideStringClass::m_FreeTempPtr)[ foobar ]
    

    Mit 'ner Referenz sollte das aber auszubügeln sein, dann fehlt Dir allerdings die Möglichkeit "NULL" zuzuweisen, Du müsstest also eine
    wchar_array256::NULL Instanz haben, sofern Du sie brauchst.

    class WideStringClass
    {
    public:
      static wchar_array256 & m_FreeTempPtr;
    };
    


  • EDIT:
    Zu lahm, hehe



  • wchar_t* wString = this->m_freeTempPtr[x];
    

    So soll das aussehen 😉


  • Mod

    Neku schrieb:

    wchar_t* (&WideStringClass::m_FreeTempPtr)[256] = *(wchar_t*(*)[256])0x00809D40;
    

    Nicht über den Sinn des ganzen nachdenken - ich hätte nur gerne eine Lösung, ob standardkonform oder nicht 😃
    Aktueller Fehler: "error C2101: '&' on constant"

    *edit2*
    Folgendes funktioniert übrigens:

    uint32& uVar = *(uint32*)0x012345678;
    

    das scheint eine beschränkung des compilers zu sein. prionzipiell geht es ja um

    T& foo = *(T*)0x12345678;
    

    für beliebiges skalares T scheint visual c++ das zu akzeptieren. sobald T allerdings ein array ist, erhalten wir den beschriebenen fehler - dabei ist anzumerken, das das problem auf der rechten seite ist. interessanterweise funktioniert das hier immer (und könnte als ausweg dienen):

    T* const foo = (T*)0x12345678;
    T& bar = *foo;
    

    da foo in jedem falle vor bar initialisiert wird, wäre das eine mögliche lösung. ich würde das problem nicht unbedingt als bug unsehen, da das ergebnis des casts, der hier benutzt wird, von vornherein implementationsabhängig ist.



  • Neku schrieb:

    wchar_t* wString = this->m_freeTempPtr[x];
    

    So soll das aussehen 😉

    Das solltest Du mit etwas Phantasie auch noch selber hinbekommen. :-\

    [cpp]
    wchar_t * operator [] (int index)
    {
    return &Data[index];
    }
    [cpp]


Anmelden zum Antworten