2011-02-08 30 views
40

So che posso copiare la struttura membro per membro, invece di quella posso fare una memcpy su strutture?Copia di una struttura in un'altra

È consigliabile farlo?

Nella mia struttura, ho una stringa anche come membro che devo copiare in un'altra struttura con lo stesso membro. Come lo faccio?

+3

Perché stai parlando di "funzioni membro" in una domanda contrassegnata come C? – unwind

+2

Puoi mostrarci la struttura o almeno un estratto di esso? Presumo che la stringa non sia un membro _function_, solo un membro visto che stiamo parlando di C qui.La "stringa" è un array di caratteri, un char assegnato dinamicamente o cosa? – rjnilsson

risposta

51

Copia mediante cessione pianura è migliore, dal momento che è più corto, più facile da leggere, e ha un alto livello di astrazione. Invece di dire (al lettore umano del codice) "copia questi bit da qui a lì", e chiedendo al lettore di pensare all'argomento delle dimensioni della copia, stai semplicemente facendo un semplice compito ("copia questo valore da qui a qui "). Non ci può essere alcuna esitazione sul fatto che la dimensione sia corretta o meno.

Inoltre, se la struttura è pesantemente riempita, l'assegnazione potrebbe far sì che il compilatore emetta qualcosa di più efficiente, poiché non deve copiare il padding (e sa dove si trova), ma lo mempcy() non lo farà copia sempre il numero esatto di byte che gli dici di copiare.

Se la stringa è un array effettivo, ad es.:

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

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

Quindi è ancora possibile utilizzare l'assegnazione pianura:

b = a; 

Per ottenere una copia completa. Tuttavia, per dati a lunghezza variabile modellati come questo, questo non è il modo più efficiente di eseguire la copia poiché l'intero array verrà sempre copiato.

Attenzione però, che le strutture di copiatura che contengono i puntatori a memoria heap allocata può essere un po 'pericoloso, dal momento che così facendo si è aliasing il puntatore, e in genere rendendolo ambiguo che possiede il puntatore dopo l'operazione di copia .

Per queste situazioni una "copia profonda" è davvero l'unica scelta e deve essere inserita in una funzione.

12

Se le strutture sono di tipi compatibili, sì, è possibile, con qualcosa come:

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

L'unica cosa che dovete essere consapevoli è che questo è un superficiale copia . In altre parole, se un di strutture punta alla stessa stringa se si dispone di un char * che punta a una stringa specifica.

E modificare il contenuto di uno di quei campi stringa (i dati a cui fa riferimento char * e non lo char *) cambieranno anche l'altro.

Se si desidera una copia semplice senza dover fare manualmente ogni campo, ma con il valore aggiunto di copie stringa non poco profondi, utilizzare strdup:

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

Ciò copiare l'intero contenuto della struttura, poi copia in profondità la stringa, dando effettivamente una stringa separata a ciascuna struttura.

E, se l'implementazione C non dispone di un strdup (non è parte dello standard ISO), get one from here.

4

È possibile le strutture memcpy oppure è possibile assegnarle come qualsiasi altro valore.

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

mantiene questo valore anche per le stringhe come indicato nella domanda? – Jonas

+1

Sì, a patto che non siano solo un puntatore ma un array. – Simone

34

Dal C90, si può semplicemente utilizzare:

dest_struct = source_struct; 

finché la stringa viene memorizzato all'interno di un array:

struct xxx { 
    char theString[100]; 
}; 

In caso contrario, se si tratta di un puntatore, ti bisogno di copiarlo a mano.

struct xxx { 
    char* theString; 
}; 

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

Cosa succede prima del C90? Quale sarebbe la differenza nell'assegnazione di struct tra i compilatori pre-C90 e post-C90 se la struct contiene una matrice come nell'esempio? – cesss

+0

@cesss: prima di C90/C89 non esisteva uno standard formale per C, quindi dipendeva dal compilatore usato. Non tutti i compiti supportati di 'struct's. Dato che C90 richiede ai compilatori di supportarlo, puoi essere certo che qualsiasi compilatore conforme a C90 (o successivo) ti consentirà di farlo. – sleske

0
  1. È possibile utilizzare una struttura per leggere la scrittura in un file. Non è necessario eseguire il cast come `char *. Anche la dimensione della struttura verrà mantenuta. (Questo punto non è più vicino al tema, ma immagino che:. comportarsi sulla memoria del disco è spesso simile a RAM uno)

  2. spostare (a & da) un singolo campo di stringa è necessario utilizzare strncpy e buffer di stringa temporaneo '\0' terminante. Da qualche parte devi ricordare la lunghezza del campo della stringa del record.

  3. Per spostare gli altri campi è possibile utilizzare la notazione del punto, es .: 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. È possibile incorporare ogni stringa in una le strutture che si adattano esso, per eludere punto-2 e comportarsi come Cobol: NodeB->txt2fi=NodeA->txt2fi ... ma sarà ancora bisogno di una stringa transitoria più uno strncpy come detto al punto-2 per scanf, printf altrimenti un input più lungo dell'operatore (più breve), non sarebbe stato troncato (da spazi riempiti).

  5. (NodeB->insidenode_subvar).mypointer=(NodeA->insidenode_subvar).mypointer creerà un alias di puntatore.
  6. NodeB.txt3=NodeA.txt3 fa sì che il compilatore a respingere: error: incompatible types when assigning to type ‘char[3]’ from type ‘char *’
  7. punto-4 funziona solo perché NodeB->txt2fi & NodeA->txt2fi appartengono alla stessa typedef !!

    una risposta corretta e semplice a questo argomento ho trovato su In C, why can't I assign a string to a char array after it's declared? "Array (anche di caratteri) sono cittadini di seconda classe in C" !!!

Problemi correlati