2011-02-08 28 views
40

Sé que puedo copiar el miembro de la estructura por miembro, en lugar de eso ¿puedo hacer un memcpy en las estructuras?Copiando una estructura a otra

¿Es aconsejable hacerlo?

En mi estructura, tengo una cadena también como miembro que tengo que copiar a otra estructura que tenga el mismo miembro. ¿Cómo puedo hacer eso?

+3

¿Por qué estás hablando de "funciones de miembro" en una pregunta etiquetada como C? – unwind

+2

¿Podría mostrarnos la estructura o al menos un extracto de ella? Supongo que la cadena no es una "función" de miembro, solo un miembro ya que estamos hablando de C simple aquí.¿Es la "cadena" una matriz de caracteres, un carácter * asignado dinámicamente o qué? – rjnilsson

Respuesta

51

copia por cesión llanura que es mejor, ya que es más corto, más fácil de leer, y tiene un nivel más alto de abstracción. En lugar de decir (al lector humano del código) "copie estos bits de aquí para allá" y requiera que el lector piense en el argumento del tamaño de la copia, simplemente está haciendo una asignación simple ("copie este valor de aquí hasta aquí "). No puede haber dudas sobre si el tamaño es correcto o no.

Además, si la estructura está muy acolchada, la asignación puede hacer que el compilador emita algo más eficiente, ya que no tiene que copiar el relleno (y sabe dónde está), pero mempcy() no lo hace. siempre copie el número exacto de bytes que le dice que copie.

Si su cadena es una matriz real, es decir:

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

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

entonces todavía puede usar la asignación clara:

b = a; 

Para obtener una copia completa. Sin embargo, para los datos de longitud variable modelados así, esta no es la forma más eficiente de hacer la copia ya que toda la matriz siempre se copiará.

Tenga cuidado sin embargo, que las estructuras de copiado que contienen punteros a la pila de memoria asignada puede ser un poco peligroso, ya que al hacerlo estás aliasing el puntero, y por lo general lo que es ambiguo que posee el puntero después de la operación de copia .

Para estas situaciones, una "copia profunda" es realmente la única opción, y eso debe ir en una función.

12

Si las estructuras son de tipos compatibles, sí, se puede, con algo como:

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

La única cosa que hay que tener en cuenta es que este es un poco profunda copia . En otras palabras, si tiene un char * apuntando a una cadena específica, ambas estructuras apuntarán a la misma cadena.

Y cambiando el contenido de uno de esos campos de cadena (los datos a los que apunta el char *, no el char * mismo) también cambiarán el otro.

Si desea una copia fácil sin tener que hacerlo manualmente cada campo pero con la ventaja añadida de copias de cadenas no poco profundas, usar strdup:

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

Esto copia el contenido completo de la estructura, a continuación, copie profundamente la cuerda, dando efectivamente una cuerda separada a cada estructura.

Y, si su implementación C no tiene un strdup (no es parte del estándar ISO), get one from here.

4

Puede memcpy estructuras, o simplemente puede asignarlas como cualquier otro valor.

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

¿Esto se mantiene incluso para cadenas como se menciona en la pregunta? – Jonas

+1

Sí, siempre que no sean solo un puntero sino una matriz. – Simone

34

Desde C90, sólo tiene que utilizar:

dest_struct = source_struct; 

, siempre y cuando la cadena se memoriza el interior de una matriz:

struct xxx { 
    char theString[100]; 
}; 

De lo contrario, si se trata de un puntero, podrás necesita 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

¿Qué sucede antes de C90? ¿Cuál sería la diferencia en la asignación de estructuras entre compiladores anteriores a C90 y posteriores a C90 si la estructura contiene una matriz como en su ejemplo? – cesss

+0

@cesss: antes de C90/C89 no había un estándar formal para C, por lo que dependía del compilador que utilizaba. No todas las asignaciones admitidas de 'struct's. Como C90 requiere que los compiladores lo admitan, puede estar seguro de que cualquier compilador que cumpla con C90 (o posterior) le permitirá hacerlo. – sleske

0
  1. Puede usar una estructura para leer en un archivo. No es necesario que lo lances como `char *. El tamaño de la estructura también se conservará. (Este punto no es más cercano al tema, pero supongo que:. comportarse en la memoria dura es a menudo similar a la RAM uno)

  2. Para mover (a & de) un único campo de cadena que debe utilizar strncpy y una búfer de cadena transitoria '\0' terminación. En algún lugar debe recordar la longitud del campo de cadena de registro.

  3. Para mover otros campos que puede utilizar la notación de puntos, ej .: 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. Puede incrustar cada cadena en una estructuras que se adapten a ella, para evadir punto-2 y comportarse como Cobol: NodeB->txt2fi=NodeA->txt2fi ... pero todavía se necesita de una cadena transitoria más uno strncpy como se ha mencionado en el punto-2 para scanf, printf de lo contrario, una entrada de operador más largo (más corto), no se habría truncado (por espacios acolchados).

  5. (NodeB->insidenode_subvar).mypointer=(NodeA->insidenode_subvar).mypointer creará un alias de puntero.
  6. NodeB.txt3=NodeA.txt3 hace que el compilador rechazará: error: incompatible types when assigning to type ‘char[3]’ from type ‘char *’
  7. punto 4 obras sólo porque NodeB->txt2fi & NodeA->txt2fi pertenecen a la misma typedef !!

    una respuesta correcta y simple a este tema he encontrado en In C, why can't I assign a string to a char array after it's declared? "Arrays (también de caracteres) son ciudadanos de segunda clase en C" !!!

Cuestiones relacionadas