Zeiger und wann memcpy?



  • Abend

    Ich habe eine Frage zu Zeigern und deren "Inhalt".
    Ich bin mir nicht sicher wann man nun memcopy braucht und wann nicht.

    Beispiel:

    struct ppm
    {
      uint8_t *data;
      // ...
    };
    
    ppm myclass::take_img(void)
    {
      ppm ret_pic;
      // mache etwas
    
      ret_pic.data = new uint8_t[sizeof(rgb->data)];
      memcpy(ret_pic.data, rgb->data, sizeof(rgb->data));
    
      return ret_pic;
    }
    

    Macht man das nun so, oder geht das auch ohne memcpy?
    also so:

    //...
    
    ppm myclass::take_img(void)
    {
      ppm ret_pic;
      // mache etwas
    
      ret_pic.data = rgb->data;
    
      return ret_pic;
    }
    

    Ich stehe irgend wie etwas auf dem Schlauch.
    Bei der letzteren variante wird doch nur der Zeiger init.
    Aber wenn rgb->data gelöscht wird, wird auch ret_pic.data kein
    Inhalt mehr haben...

    Danke wenn mir mal jemand Klarheit gibt.

    Gg



  • xGhost schrieb:

    ret_pic.data = new uint8_t[sizeof(rgb->data)];
      memcpy(ret_pic.data, rgb->data, sizeof(rgb->data));
    

    So sollte man es auch nicht machen, da sizeof vermutlich nur die Größe des Pointer zurück gibt, aber nicht des gerbrauchten Speicherplatzes.

    uint8_t* p = new uint8_t[100000];
    
    sizeof(p) // liefert immer 4 Bytes auf 32-Bit Systemen (8 auf 64 Bit)
    

    Egal, worauf p zeigt.

    Nun ein Beispiel, zu deiner Frage, ich hoffe, dass Veranschaulicht das:

    int i;
    int j;
    
    // copy
    j = i;
    
    int *a;
    int *b;
    
    // copy
    *a = *b;
    
    int *c = new int[10];
    int *d = new int[10];
    
    // copy
    for (i = 0; i < 10; i++) {
      d[i] = c[i]; 
    }
    // äquivalent
    memcpy(d, c, 10*sizeof(int));
    


  • Wenn du die Daten des Arrays kopieren willst, dann brauchst du new und dann memcpy (oder std::copy oä). Damit legst du eine wirkliche Kopie an. Wenn du nur den Pointer zuweist, dann erhälst du nur eine weitere Referenz auf die Daten. Löscht oder ändert nun jemand die Daten, dann sind diese auch gelöscht bzw geändert, wenn du über den Pointer zugreifst.

    Übrigens verwendest du sizeof falsch! sizeof gibt die Größe eines Ausdrucks an. In dem Fall erhälst du eben die Größe eines Zeigers und _nicht_ die Größe des Speichers auf den der Zeiger zeigt!



  • rüdiger schrieb:

    Übrigens verwendest du sizeof falsch! sizeof gibt die Größe eines Ausdrucks an. In dem Fall erhälst du eben die Größe eines Zeigers und _nicht_ die Größe des Speichers auf den der Zeiger zeigt!

    Stimmt...
    das habe ich mir auch schon überlegt.

    Danke für die infos.



  • uint8_t *a = new uint8_t[10];
    sizeof(*a)
    

    So sollte es doch gehen?

    Gg

    /// Edit ///
    uint8_t entspricht 1 byte.
    Daher gibt sizeof auf ein uint8_t array immer die
    anzahl elemente.



  • xGhost schrieb:

    uint8_t *a = new uint8_t[10];
    sizeof(*a)
    

    So sollte es doch gehen?

    Nein!!!

    xGhost schrieb:

    /// Edit ///
    uint8_t entspricht 1 byte.
    Daher gibt sizeof auf ein uint8_t array immer die
    anzahl elemente.

    Ja, aber nicht auf einen uint8_t Pointer.

    #include <stdio.h>
    
    typedef unsigned char uint8_t;
    
    int main(int argc, char* argv[]) {
        uint8_t *a = new uint8_t[10];
    
        printf("sizeof(a) = %d\n", sizeof(a));
        printf("sizeof(*a) = %d\n", sizeof(*a));
    
        return 0;
    }
    

    Die Ausgabe ist

    sizeof(a) = 4
    sizeof(*a) = 1
    

    Aber beim 2. hättest du 10 erwartet, aber das geht nicht! Das geht nur, wenn die größe des Arrays zur Compilierzeit bekannt ist. Das ist aber, wenn du new verwendest nie der Fall.



  • xGhost schrieb:

    uint8_t *a = new uint8_t[10];
    sizeof(*a)
    

    So sollte es doch gehen?
    ...

    Geht schon, liefert aber nicht das gewünschte Ergebnis 😉
    Warum, ist wohl auch klar:

    • a hat welchen Typ ? => uint8_t *
    • *a hat welchen Typ ? => uint8_t
    • welche Größe liefert dann sizeof(*a) ? => dieselbe wie sizeof(uint8_t).

    Um es mal ganz kurz zu machen: sizeof wird zur Compilezeit errechnet ! Da kommst Du niemals an Informationen die erst zur Laufzeit bestimmt werden.
    => sizeof ist nicht das Werkzeug, das Du brauchst.
    Es bleibt Dir nichts Anderes übrig, als Dir zu merken, wieviel Elemente Du angelegt hast - ein Grund, warum sich std::vector so großer Beleibtheit erfreut, der nimmt Dir nämlich das (und viele der Aufgaben, die Du danach noch haben wirst) ab.

    Gruß,

    Simon2.



  • ProgChild schrieb:

    Aber beim 2. hättest du 10 erwartet, aber das geht nicht! Das geht nur, wenn die größe des Arrays zur Compilierzeit bekannt ist. Das ist aber, wenn du new verwendest nie der Fall.

    Jo, jetzt verstehe ich es.
    Danke.

    Ein Vektor kann ich für ein RGB Bild nicht nehmen, ohne
    das ich dann immer zwischen den C libs wrappen müsste.

    Ich kann die grösse auch aus den Bildpunkten berechnen, das
    ist nicht das Problem. Dachte nur, dass sizeof das ganze per
    laufzeit berechnet.

    Gruss,
    Ghost



  • Klar kannst du nen vector nehmen.

    class foo
    {
    public:
        void test234()
        {
    //      uint8_t* p = m_data;
            uint8_t* p = &(m_data[0]);
            for (size_t i = 0; i < 100; i++)
                p[i]++;
        }
    
    private:
    //  uint8_t* m_data;
        std::vector<uint8_t> m_data;
    };
    

    Das geht weil der Speicher von std::vector immer zusammenhängend ist, du kannst also ohne weiteres die Adresse des ersten Elements nehmen und das dann als Array behandeln (wie oben). Du kannst diese Adresse dann also auch an diverse Libraries (seis nun C oder C++ Libraries) weitergeben.
    Die Adresse des ersten Elements bleibt auch konstant solange du keine Funktion aufrufst die zu einer reallocation führen könnte, welche das sind ist AFAIK im Standard definiert.


Anmelden zum Antworten