Hilfe bei Pointern und Dynamischen Speicher



  • Andromeda schrieb:

    HansKlaus schrieb:

    Andromeda schrieb:

    Rätselfrage: ist x oder i der Pointer?

    i zeigt halt auf was anderes 🙄

    Auf was denn?

    kommt halt darauf an, welchen wert i hat.



  • der witz ist, dass [] für eingebaute typen auch kommutativ ist.

    void foo (int* array, int i){
       assert(array[i] == i[array]);
    }
    


  • dove schrieb:

    der witz ist, dass [] für eingebaute typen auch kommutativ ist.

    Das ist kein Witz, sondern die logisch Folgerung daraus.



  • naja ob ich den wert von i als basisadresse nehme und dann den wert von array hinzuaddiere, oder umgekehrt ist ja auch egal.



  • DirkB schrieb:

    Andromeda schrieb:

    DirkB schrieb:

    x[i] ist identisch mit *(x+i)

    Rätselfrage: ist x oder i der Pointer?

    Solange da ein Pointer und ein integraler Typ ist, ist es egal.

    So ist es. 🙂

    DirkB schrieb:

    Dies ergibt sich aus dem Kommutativgesetz, dass für die Addition gültig ist.

    Das ergibt sich eher aus der C-Syntax, die sowas erlaubt.



  • DirkB schrieb:

    dove schrieb:

    der witz ist, dass [] für eingebaute typen auch kommutativ ist.

    Das ist kein Witz, sondern die logisch Folgerung daraus.

    logisch ist das nicht, nur wenn man wirklich die definition x[y] == *(x+y) ernst nimmt. die ist aber auch nicht absolut/in stein gemeißelt...

    struct Foo {
        int i;
        int const& operator*() const { return i; }
    
    };
    
    Foo operator+(Foo a, int i) {
     return a;
    }
    
    Foo operator+(int i, Foo a) {
     return a;
    }
    
    int main()
    {
        Foo f { 42 };
    
        *f; //ok
        *(f+0); //ok
        *(0+f); //ok
        f[0]; //ooops
    }
    


  • dove schrieb:

    DirkB schrieb:

    dove schrieb:

    der witz ist, dass [] für eingebaute typen auch kommutativ ist.

    Das ist kein Witz, sondern die logisch Folgerung daraus.

    logisch ist das nicht, nur wenn man wirklich die definition x[y] == *(x+y) ernst nimmt. die ist aber auch nicht absolut/in stein gemeißelt...

    struct Foo {
        int i;
        int const& operator*() const { return i; }
       
    };
    
     
    Foo operator+(Foo a, int i) {
     return a;
    }
        
    Foo operator+(int i, Foo a) {
     return a;
    }
    
    int main()
    {
        Foo f { 42 };
        
        *f; //ok
        *(f+0); //ok
        *(0+f); //ok
        f[0]; //ooops
    }
    

    Wenn man einfach Operatoren umbiegt, kann man natürlich jede Seltsamkeit hinfrickeln. Daher bevorzuge ich C. Bei einem C++-Codeschnipsel weißt du nie, was wirklich passiert.



  • wenn man den []-operator auch noch überlädt, klappts auch.



  • Andromeda schrieb:

    Wenn man einfach Operatoren umbiegt, kann man natürlich jede Seltsamkeit hinfrickeln. Daher bevorzuge ich C. Bei einem C++-Codeschnipsel weißt du nie, was wirklich passiert.

    ja, das überladen von operatoren ist eines der wesentlichen merkmale von C++. wenn man sich an bestehende konventionen hält, ist das auch überhaupt nicht schlimm. blöd ist es nur, wenn man einen operator falsch implementiert und daher mehr arbeit ausführen lässt, als nötig wäre. in C muss man sich dann eben darauf verlassen, das irgendwelche funktionen, die man aufruft, richtig und gut geschrieben sind.

    leider? reicht es eben nicht, operator+ und den dereferenzierungsoperator zu überladen, um dieselbe funktionalittät wie mit zeiger+integral zu bekommen. das ist aber so eine unbedeutende randerscheinung, dass man als normaler C++-anwender damit trotzdem gut leben kann.



  • Kleine Frage man schließt ja in einem char* die letzte Stelle mit einer Null ab.

    Wenn ich das hier mache :

    char* name = "Darmstadt";
    //char* ptmp = name;
    name[9] = 0 ;
    
    cout << name << endl;
    

    Warum stürzt da mein Programm ab ? Laut Debugger macht er alles richtig.
    Er erstellt ein Array und an der "9" Stelle gibt er mir eine \0 .

    Kann es seien das ich durch

    char* name = "Darmstadt";
    

    ein Array erzeuge von [i] Stellen und ich dem Array an der 9ten Stelle eine Null angebe und er versucht sie auszugeben und "0" ja kein erlaubter Zustand seien darf?

    Oder hat das was mit dem Speicher zu tuen? Weil bei meinem Dynamischen Speicher muss ich ja mit einer NULL \0 abschließen
    Mfg



  • Der Compiler gibt eine Warnung aus. Ein Stringliteral stellt einen const char* - eun Zeiger auf einen Speicherbereich, welcher nicht beschrieben werden darf.



  • Und noch eine letzte Frage 🙂
    Bin dann echt durch und ihr habt mir bisher sehr sehr gut weitergeholfen 1000000 facher Dank dafür... folgendes :

    char* m_name;
    	char* name = "Darmstadt";
    	//char* ptmp = name;
    	m_name = new char[9];
    	m_name = name;
    

    Hab das mal zu Übungszwecken eingetippt und durch den Debugger gejagt zur Verdeutlichung... Kann mir mal einer erklären, warum bei

    m_name = name;
    

    ( das der Inhalt übernommen wird ist klar ) aber das die Adressen mit übernommen werden ist mir ein Rätsel ... Sind doch beide verschiedene Arrays?
    ist das Normal ?
    Weil in dem Script meines Profs wird das per For-Schleife realiesert und sozusagen Jeder einzelne Buchstabe ....

    for (m_curlenName=0;m_curlenName<m_maxlenName;m_curlenName++)
    	{
    		m_name[m_curlenName]=name[m_curlenName];
    	}
    


  • buu2188 schrieb:

    ( das der Inhalt übernommen wird ist klar )

    Ne, das ist nicht klar. Was heißt "übernehmen" für dich in diesem Fall? Das was Du wahrscheinlich als "Inhalt" verstehst ( "Darmstadt" ?) wird hier nicht kopiert.

    buu2188 schrieb:

    [...] aber das die Adressen mit übernommen werden ist mir ein Rätsel ... Sind doch beide verschiedene Arrays?

    Ein Array ist kein Pointer. Ein Pointer ist kein Array. Ein Array ist kein Pointer. Ein Pointer ist kein Array. Ein Array ist kein Pointer. Ein Pointer ist kein Array. Ein Array ist kein Pointer. Ein Pointer ist kein Array. Ein Array ist kein Pointer. Ein Pointer ist kein Array. Ein Array ist kein Pointer. Ein Pointer ist kein Array. Ein Array ist kein Pointer. Ein Pointer ist kein Array. Ein Array ist kein Pointer. Ein Pointer ist kein Array. Ein Array ist kein Pointer. Ein Pointer ist kein Array. Ein Array ist kein Pointer. Ein Pointer ist kein Array. Ein Array ist kein Pointer. Ein Pointer ist kein Array. Ein Array ist kein

    buu2188 schrieb:

    ist das Normal?

    Ja.

    Weder name noch m_name in deinem Beispiel ist ein Array. Ein Array ist ein Speicherblock, dessen Größe zur Übersetzung des Programms bereits feststeht (und auch nachträglich nicht geändert werden kann). Arrays leben auf dem Stapelspeicher (Stack), Dynamisch reservierter Speicher jedoch auf dem Freispeicher (Heap).

    char* m_name;              // Typ: char * (pointer to char)
    char* name = "Darmstadt";  // Typ: char * (pointer to char) 1)
    char foo[10];              // Typ: char[10] (array of 10 char)
    char bar[] = "Darmstadt";  // Typ: char[10] (array of 10 char)
    
    1. Eigentlich sollte name vom Typ char const * (pointer to const char) sein, da er auf ein Zeichenkettenliteral zeigt. Zeichenkettenliterale dürfen zur Laufzeit nicht beschrieben werden und sind deshalb const .

    Machst du nun foo = bar dann wird dir dein Lieblingscompiler sagen, daß du das nicht tun kannst. Arrays haben keine Kopiersemantik. Deshalb gibt es std::copy und Konsorten. Zu Fuß gehts eben mit einer Schleife.

    Machst du m_name = name so wird der Wert der Variable name der Variable m_name Zugewiesen. Dieser Wert ist eine Adresse - was auch sonst, beides sind schließlich Pointer. Beide Zeigen nach der Zuweisung auf den Anfang desselben Speicherbereichs. Der Speicherbereich, den du mit new char[9] (zu klein für "Darmstadt" !!) reserviert hast, ist dir nach der Zuweisung m_name = name nicht mehr Zugänglich, da du nirgends mehr die Adresse auf seinen Anfang gespeichert hast. Du kannst ihn weder verwenden noch jemals wieder ordentlich freigeben. Du hast ein Speicherleck.

    Das willst du aber wahrscheinlich nicht:

    #include <cstring>
    #include <iostream>
    
    class foo_t {
        private:
            char const * m_name;
    
        public:
            foo_t( char const * name )
            {
                m_name = name;  // dont. do. this.
            }
    
            void print_name() const
            {
                std::cout << m_name << '\n';  // booom!??
            }
    };
    
    int main()
    {
        char * bar = new char[ 10 ];
        std::strcpy( bar, "Darmstadt" );
    
        foo_t foo{ bar };
        foo.print_name();    // ok.
    
        delete[] bar;
    
        foo.print_name();  // BOOOOOOM!!
    }
    

    Da der Speicherbereich auf den bar zeigt vor dem zweiten Aufruf von print_name() freigegeben wurde, greift die Methode dann auf Speicher zu, der deinem Programm nicht mehr gehört. Das ist ein Fehler und fliegt dir früher oder später um die Ohren. Richtig wäre im Konstruktor einen ausreichend großen Speicherbereich anzufordern ( new[] ) und die Zeichenkette, auf die der Parameter name zeigt dahin zu kopieren. Ob nun mit einer Schleife, mit std::strcpy() oder std::copy() läuft aufs selbe raus.



  • was ist ein

    char*
    

    dann? Ich dachte es wäre das selbe wie

    char[]
    

    Ein Pointer auf das erste Element eines char?

    Bitte mal mit einem c++ Anfängerbeispiel sowie der Herr auf der ersten Seite des Threads 😞

    Vielen Dank 🕶



  • char* ist ein Pointer und char[] das Array. Das Array ist jedoch implizit in einen Pointer konvertierbar.

    char a[] = "hello";
    char* p = a;
    


  • Swordfish schrieb:

    Ein Array ist kein Pointer. Ein Pointer ist kein Array.

    Ein Array ist nach der Definition in Größe und Lage unveränderlich.
    Der Name vom Array alleine steht für die Anfangsadresse des Array.

    Einem Pointer kannst du jederzeit einen neuen Wert zuweisen, so dass er auf andere Speicherstellen verweist

    Ein char[] als Funktionsparamter ist ein char*.

    Aber: Ein Array ist kein Pointer. Ein Pointer ist kein Array.

    char a[] = "hello";
    char b[] = "world";
    char* p = a;  // p zeigt auf das h von "hello"
    p = b;        // p zeigt auf w von "world"
    p++;          // p zeigt auf o von "world", das Zeichen hinter w
    
    a = b; geht nicht
    a++;   geht nicht
    
    sizeof(a) ergibt 6 (5 Buchstaben + '\0')
    sizeof(b) ergibt 6
    sizeof(p) ergibt sizeof(char*), die Größe eines Pointers
    


  • Ahhh ok vielen Dank 🙂
    Das heißt also wenn zB

    char* irgendetwas = "Hallo";
    

    Dann zeigt der Pointer auf die erste Speichersetelle und somit das "H"?



  • buu2188 schrieb:

    char* irgendetwas = "Hallo";
    

    Dann zeigt der Pointer auf die erste Speichersetelle und somit das "H"?

    Ja, ja das heißt es.

    Etwas genauer:
    "1" ist ein Stringliteral, da wird automatisch die '\0' angehängt. Es sind also zwei Zeichen
    '1' ist ein Zeichen, das die Ziffer für Eins darstellt. IM ASCII ist das der Wert 49
    '\1' ist ein Zeichen, das den Wert 1 hat. Siehe Escapesequencen und ASCII.
    1 ist der Wert 1.

    Die erste Speicherstelle enthält ein 'H'



  • Vielen Dank habe es nun endlich verstanden 🙂



  • buu2188 schrieb:

    was ist ein

    char*
    

    dann? Ich dachte es wäre das selbe wie

    char[]
    

    Ich hab' mir wirklich Mühe gegeben. Hast du wenigstens versucht, mein Geschreibsel zu verstehen!???


Anmelden zum Antworten