Kopieren einer Struktur in eine andere

Lesezeit: 7 Minuten

Benutzeravatar von asir
anstreben

Ich weiß, dass ich die Struktur Mitglied für Mitglied kopieren kann, stattdessen kann ich eine memcpy auf Strukturen?

Ist es ratsam, dies zu tun?

In meiner Struktur habe ich auch eine Zeichenfolge als Mitglied, die ich in eine andere Struktur mit demselben Mitglied kopieren muss. Wie mache ich das?

  • Warum sprechen Sie in einer als C gekennzeichneten Frage über “Memberfunktionen”?

    – abschalten

    8. Februar 2011 um 8:59 Uhr

  • Könnten Sie uns die Struktur oder zumindest einen Auszug davon zeigen? Ich gehe davon aus, dass die Zeichenfolge kein Mitglied ist Funktion, nur ein Mitglied, da wir hier von einfachem C sprechen. Ist der “String” ein Char-Array, ein dynamisch zugewiesenes Char* oder was?

    – rjnilsson

    8. Februar 2011 um 9:00 Uhr

Benutzeravatar von unwind
entspannen

Das Kopieren durch einfache Zuweisung ist am besten, da es kürzer und einfacher zu lesen ist und eine höhere Abstraktionsebene hat. Anstatt (zum menschlichen Leser des Codes) zu sagen: “Kopiere diese Bits von hier nach dort” und den Leser dazu aufzufordern, über das Größenargument für die Kopie nachzudenken, machst du nur eine einfache Zuweisung (“Kopiere diesen Wert von von hier nach hier”). Es kann kein Zögern darüber geben, ob die Größe stimmt oder nicht.

Wenn die Struktur stark aufgefüllt ist, kann die Zuweisung den Compiler außerdem dazu bringen, etwas effizienter auszugeben, da er die Auffüllung nicht kopieren muss (und weiß, wo sie sich befindet), aber mempcy() nicht, also kopiert es immer die genaue Anzahl von Bytes, die Sie ihm zum Kopieren mitteilen.

Wenn Ihre Zeichenfolge ein tatsächliches Array ist, dh:

struct {
  char string[32];
  size_t len;
} a, b;

strcpy(a.string, "hello");
a.len = strlen(a.string);

Dann können Sie immer noch die einfache Zuweisung verwenden:

b = a;

Um eine vollständige Kopie zu erhalten. Für so modellierte Daten mit variabler Länge ist dies jedoch nicht die effizienteste Methode zum Kopieren, da immer das gesamte Array kopiert wird.

Beachten Sie jedoch, dass das Kopieren von Strukturen, die Zeiger auf Heap-zugeordneten Speicher enthalten, etwas gefährlich sein kann, da Sie dies tun Aliasing den Zeiger, und macht es typischerweise mehrdeutig, wem der Zeiger nach dem Kopiervorgang gehört.

Für diese Situationen ist eine “tiefe Kopie” wirklich die einzige Wahl, und das muss in eine Funktion gehen.

Benutzeravatar von Simone
Simone

Seit C90 können Sie einfach verwenden:

dest_struct = source_struct;

solange die Zeichenfolge in einem Array gespeichert ist:

struct xxx {
    char theString[100];
};

Wenn es sich um einen Zeiger handelt, müssen Sie ihn andernfalls von Hand kopieren.

struct xxx {
    char* theString;
};

dest_struct = source_struct;
dest_struct.theString = malloc(strlen(source_struct.theString) + 1);
strcpy(dest_struct.theString, source_struct.theString);

  • Was passiert vor C90? Was wäre der Unterschied in der Strukturzuweisung zwischen Pre-C90- und Post-C90-Compilern, wenn die Struktur ein Array wie in Ihrem Beispiel enthält?

    – zess

    27. März 2017 um 10:10 Uhr

  • @cesss: Vor C90/C89 gab es keinen formalen Standard für C, daher hing es vom verwendeten Compiler ab. Nicht alle unterstützten die Zuweisung von structs. Da C90 Compiler benötigt, um es zu unterstützen, können Sie sicher sein, dass jeder Compiler, der C90 (oder höher) entspricht, dies zulässt.

    – schleske

    28. September 2017 um 9:02 Uhr

Benutzeravatar von paxdiablo
paxdiablo

Wenn die Strukturen kompatible Typen sind, ja, das können Sie mit etwas wie:

memcpy (dest_struct, source_struct, sizeof (*dest_struct));

Das einzige, was Sie beachten müssen, ist, dass dies eine ist seicht Kopieren. Mit anderen Worten, wenn Sie eine char * auf eine bestimmte Zeichenfolge zeigen, beide Strukturen zeigen auf dieselbe Zeichenfolge.

Und das Ändern des Inhalts eines dieser Zeichenfolgenfelder (die Daten, die die char * weist darauf hin, nicht auf die char * selbst) wird auch die andere ändern.

Wenn Sie eine einfache Kopie wünschen, ohne jedes Feld manuell ausführen zu müssen, aber mit dem zusätzlichen Bonus von nicht flachen Zeichenfolgenkopien, verwenden Sie strdup:

memcpy (dest_struct, source_struct, sizeof (*dest_struct));
dest_struct->strptr = strdup (source_struct->strptr);

Dadurch wird der gesamte Inhalt der Struktur kopiert und dann die Zeichenfolge tief kopiert, wodurch jeder Struktur effektiv eine separate Zeichenfolge zugewiesen wird.

Und wenn Ihre C-Implementierung keine hat strdup (es ist nicht Teil des ISO-Standards), holen Sie sich eines von hier.

Du kannst memcpy Strukturen, oder Sie können sie einfach wie jeden anderen Wert zuweisen.

struct {int a, b;} c, d;
c.a = c.b = 10;
d = c;

In C ist Memcpy nur dummerweise riskant. Solange Sie alle drei Parameter genau richtig eingeben, sind keine der Strukturmitglieder Zeiger (oder Sie beabsichtigen ausdrücklich, eine flache Kopie zu erstellen) und es gibt keine großen Ausrichtungslücken in der Struktur, durch die memcpy Zeit verschwenden wird (oder die Leistung spielt keine Rolle), dann auf jeden Fall memcpy. Sie gewinnen nichts außer Code, der schwerer zu lesen ist, anfällig für zukünftige Änderungen ist und in Codeüberprüfungen von Hand überprüft werden muss (weil der Compiler dies nicht kann), aber hey, ja, sicher, warum nicht.

In C++ schreiten wir zum lächerlich Riskanten vor. Möglicherweise haben Sie Member von Typen, die nicht sicher memcpyable sind, wie std::string, was dazu führt, dass Ihre empfangende Struktur zu einer gefährlichen Waffe wird und den Speicher bei jeder Verwendung zufällig beschädigt. Beim Emulieren von Slice-Kopien können Sie Überraschungen im Zusammenhang mit virtuellen Funktionen erleben. Der Optimierer, der erstaunliche Dinge für Sie tun kann, weil er beim Kompilieren von = volles Typwissen garantiert, kann nichts für Ihren memcpy-Aufruf tun.

In C++ gibt es eine Faustregel: Wenn Sie memcpy oder memset sehen, stimmt etwas nicht. Es gibt seltene Fälle, in denen dies nicht zutrifft, aber sie beinhalten keine Strukturen. Sie verwenden Memcpy, wenn und nur wenn Sie Grund dazu haben blindlings Kopieren Bytes.

Die Zuweisung hingegen ist einfach zu lesen, überprüft die Korrektheit zur Kompilierzeit und bewegt sich dann intelligent Werte zur Laufzeit. Es gibt keinen Nachteil.

  • “In C++ gibt es eine Faustregel: Wenn Sie memcpy oder memset sehen, stimmt etwas nicht.” Scheint eine starke Aussage zu sein, wenn man bedenkt, dass std::memcpy buchstäblich die einzige legale Möglichkeit ist, bestimmte Operationen in C++ auszuführen, vgl. youtu.be/_qzMpk-22cc?t=1814

    – heiner

    29. November 2021 um 16:48 Uhr

Grant Millers Benutzeravatar
Grant Miller

Sie können die folgende Lösung verwenden, um Ihr Ziel zu erreichen:

struct student 
{
    char name[20];
    char country[20];
};
void main()
{
    struct student S={"Wolverine","America"};
    struct student X;
    X=S;
    printf("%s%s",X.name,X.country);
}

  • “In C++ gibt es eine Faustregel: Wenn Sie memcpy oder memset sehen, stimmt etwas nicht.” Scheint eine starke Aussage zu sein, wenn man bedenkt, dass std::memcpy buchstäblich die einzige legale Möglichkeit ist, bestimmte Operationen in C++ auszuführen, vgl. youtu.be/_qzMpk-22cc?t=1814

    – heiner

    29. November 2021 um 16:48 Uhr

Benutzeravatar der Community
Gemeinschaft

  1. Sie können eine Struktur zum Lesen und Schreiben in eine Datei verwenden. Sie müssen es nicht als `char* umwandeln. Auch die Strukturgröße bleibt erhalten. (Dieser Punkt kommt dem Thema nicht am nächsten, aber raten Sie mal: Das Verhalten auf dem Festplattenspeicher ist oft ähnlich wie auf dem RAM.)

  2. Um ein einzelnes Zeichenfolgenfeld (zu und von) zu verschieben, müssen Sie verwenden strncpy
    und einen transienten Zeichenfolgenpuffer '\0' beenden. Irgendwo müssen Sie sich an die Länge des Datensatz-String-Felds erinnern.

  3. Um andere Felder zu verschieben, können Sie die Punktnotation verwenden, z. B.:
    NodeB->one=intvar;
    floatvar2=(NodeA->insidebisnode_subvar).myfl;

    struct mynode {
        int one;
        int two;
        char txt3[3];
        struct{char txt2[6];}txt2fi;
        struct insidenode{
            char txt[8];
            long int myl;
            void * mypointer;
            size_t myst;
            long long myll;
             } insidenode_subvar;
        struct insidebisnode{
            float myfl;
             } insidebisnode_subvar;
    } mynode_subvar;
    
    typedef struct mynode* Node;
    
    ...(main)
    Node NodeA=malloc...
    Node NodeB=malloc...
    
  4. Sie können jede Zeichenfolge in eine passende Struktur einbetten, um Punkt-2 zu umgehen und sich wie Cobol zu verhalten:
    NodeB->txt2fi=NodeA->txt2fi
    … aber Sie benötigen immer noch eine transiente Zeichenfolge plus eins strncpy wie unter Punkt-2 für erwähnt scanf, printf
    andernfalls wäre eine längere Operatoreingabe (kürzer) nicht abgeschnitten worden (durch Leerzeichen aufgefüllt).

  5. (NodeB->insidenode_subvar).mypointer=(NodeA->insidenode_subvar).mypointer

    erstellt einen Zeigeralias.

  6. NodeB.txt3=NodeA.txt3

    bewirkt, dass der Compiler ablehnt:
    error: incompatible types when assigning to type ‘char[3]’ from type ‘char *’

  7. Punkt-4 funktioniert nur, weil NodeB->txt2fi & NodeA->txt2fi gehören zu denselben typedef !!

    Eine richtige und einfache Antwort auf dieses Thema, die ich bei In C gefunden habe, warum kann ich einem Zeichenarray keine Zeichenfolge zuweisen, nachdem es deklariert wurde? “Arrays (auch von Zeichen) sind Bürger zweiter Klasse in C”!!!

1417100cookie-checkKopieren einer Struktur in eine andere

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy