wake-up-neo.com

Eine Struktur in eine andere kopieren

Ich weiß, dass ich das Strukturmitglied nach Mitglied kopieren kann. Kann ich stattdessen eine memcpy für Strukturen ausführen?

Ist es ratsam, dies zu tun?

In meiner Struktur habe ich auch einen String, den ich in eine andere Struktur kopieren muss, die den gleichen Member hat. Wie mache ich das?

45
asir

Kopieren durch einfache Zuweisung ist am besten, da es kürzer ist, leichter lesbar ist und eine höhere Abstraktionsebene aufweist. Anstatt (für den menschlichen Leser des Codes) zu sagen "Kopieren Sie diese Bits von hier nach dort", und müssen Sie den Leser über das Größenargument der Kopie nachdenken, indem Sie eine einfache Zuweisung vornehmen ("Kopieren Sie diesen Wert aus hier nach hier "). Es kann kein Zweifel darüber bestehen, ob die Größe korrekt ist oder nicht.

Wenn die Struktur stark aufgefüllt ist, kann die Zuweisung dazu führen, dass der Compiler etwas effizienter aussendet, da er die Auffüllung nicht kopieren muss (und weiß, wo er sich befindet), mempcy() jedoch nicht Anzahl der Bytes, die Sie kopieren möchten.

Wenn Ihre Zeichenfolge ein tatsächliches Array ist, d. H .:

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

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

Dann können Sie noch die einfache Zuordnung verwenden:

b = a;

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

Beachten Sie jedoch, dass das Kopieren von Strukturen, die Zeiger auf den Heap-zugewiesenen Speicher enthalten, ein bisschen gefährlich sein kann, da Sie Aliasing der Zeiger sind und normalerweise unklar werden, wer den Zeiger nach dem Kopiervorgang besitzt.

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

59
unwind

Seit C90 können Sie einfach Folgendes verwenden:

dest_struct = source_struct;

solange der String in einem Array gespeichert ist:

struct xxx {
    char theString[100];
};

Wenn es sich um einen Zeiger handelt, müssen Sie ihn 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);
37
Simone

Wenn die Strukturen von kompatiblen Typen sind, können Sie Folgendes angeben:

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

Das einzige, was Sie wissen müssen, ist, dass dies eine shallow - Kopie ist. Mit anderen Worten, wenn Sie einen char * haben, der auf einen bestimmten String zeigt, zeigen both -Strukturen auf den gleichen String.

Wenn Sie den Inhalt eines dieser String-Felder ändern (die Daten, auf die der char * zeigt, nicht der char * selbst), werden auch die anderen geändert.

Wenn Sie eine einfache Kopie wünschen, ohne jedes Feld manuell ausfüllen zu müssen, aber mit dem Zusatz von nicht flachen String-Kopien, 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. Anschließend wird die Zeichenfolge tief kopiert, sodass jeder Struktur eine eigene Zeichenfolge zugewiesen wird.

Wenn Ihre C-Implementierung keine strdup hat (sie ist nicht Teil des ISO-Standards), erhalten Sie von hier aus eine .

14
paxdiablo

Sie können memcpy -Strukturen verwenden oder sie einfach wie jeden anderen Wert zuweisen.

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

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);
}
0
Anvesh

In C ist Memcpy nur dumm riskant. Solange Sie alle drei Parameter genau richtig erhalten, sind keine Strukturglieder Zeiger (oder Sie beabsichtigen explizit, eine flache Kopie zu erstellen), und es gibt keine großen Ausrichtungslücken in der Struktur, die Memcpy mit Zeitschleifen verbrennt (oder Leistung spielt keine Rolle), dann auf jeden Fall memcpy. Sie erhalten nichts außer Code, der schwieriger zu lesen ist, für zukünftige Änderungen anfällig ist und in Code-Reviews von Hand verifiziert werden muss (da der Compiler dies nicht kann), aber hey yeah, warum nicht.

In C++ kommen wir zu den lächerlich riskanten. Möglicherweise haben Sie Mitglieder von Typen, die nicht sicher gespeichert werden können, wie z. B. std :: string. Dadurch wird Ihre empfangende Struktur zu einer gefährlichen Waffe, die den Speicher bei jeder Verwendung zufällig beschädigt. Beim Emulieren von Schnittkopien erhalten Sie möglicherweise Überraschungen mit virtuellen Funktionen. Der Optimierer, der wundersame Dinge für Sie erledigen kann, weil er bei der Kompilierung eine vollständige Typkenntnis 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 umfassen keine Strukturen. Sie verwenden memcpy nur dann, wenn Sie Grund haben, blind copy bytes zu kopieren. 

Die Zuweisung ist dagegen einfach zu lesen, überprüft die Kompatibilität zur Kompilierzeit und verschiebt dann zur Laufzeit intelligent Werte. Es gibt keinen Nachteil.

0
user15001
  1. Sie können eine Struktur zum Lesen und Schreiben in eine Datei verwenden. Sie müssen es nicht als `char * umwandeln. Die Strukturgröße bleibt ebenfalls erhalten. (Dieser Punkt ist dem Thema nicht am nächsten, aber erraten Sie es: Das Verhalten auf festem Speicher ähnelt häufig RAM one.)

  2. Um ein einzelnes Zeichenfolgenfeld zu verschieben, müssen Sie strncpy und einen vorübergehenden Zeichenfolgenpuffer '\0' Verwenden, der endet. Irgendwo müssen Sie sich die Länge des Datensatzfeldes merken.

  3. Um andere Felder zu verschieben, können Sie die Punktnotation verwenden, zB: 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 jeden String in eine Struktur einbetten, die zu ihm passt, um Punkt 2 zu umgehen und sich wie Cobol zu verhalten: NodeB->txt2fi=NodeA->txt2fi ... aber Sie benötigen immer noch einen transienten String plus einen strncpy, wie erwähnt bei Punkt-2 für scanf, printf, andernfalls hätte eine längere (kürzere) Bedienereingabe nicht abgeschnitten werden müssen (durch Leerzeichen).

  5. (NodeB->insidenode_subvar).mypointer=(NodeA->insidenode_subvar).mypointer Erstellt einen Zeiger-Alias.
  6. NodeB.txt3=NodeA.txt3 Bewirkt, dass der Compiler zurückweist: error: incompatible types when assigning to type ‘char[3]’ from type ‘char *’
  7. point-4 funktioniert nur, weil NodeB->txt2fi & NodeA->txt2fi zum selben typedef gehören !!

    Eine korrekte und einfache Antwort auf dieses Thema fand ich unter In C, warum kann ich einem char-Array keine Zeichenfolge zuweisen, nachdem es deklariert wurde? "Arrays (auch aus Zeichen) sind Bürger zweiter Klasse in C "!!!

0
splugenbrau