2010-07-22 9 views
12

¿Cuál es la forma estándar de copiar dos estructuras que contienen matrices char?Copie dos estructuras en C que contengan punteros de char

Aquí hay un código:

#include stdio.h> 
#include string.h> 
#include stdlib.h> 

typedef struct { 
    char* name; 
    char* surname; 
} person; 

int main(void){ 
    person p1; 
    person p2; 

    p1.name  = (char*)malloc(5); 
    p1.surname = (char*)malloc(5); 

    strcpy(p1.name, "AAAA"); 
    strcpy(p1.surname, "BBBB"); 

    memcpy(&p2, &p1, sizeof(person)); 
    free(p1.name); 
    printf("%s\n", p2.name); 
    return 0; 
} 

La línea printf("%s\n", p2.name); no imprime algo, porque liberó a la memoria intermedia.

El problema con mis estructuras es que son más grandes que struct person. Contienen cientos de punteros de char, y tengo que copiar a cada miembro uno por uno.

¿Hay alguna otra manera de copiar dos estructuras que contienen matrices de caracteres sin usar malloc y strcpy para cada miembro?

+0

¿Cómo funciona memcpy, si la memoria no está asignada para p2, ¿Alguien puede explicarlo? ¿No debería arrojar alguna excepción en el tiempo de ejecución? – JagsVG

+1

Sus estructuras contienen * punteros *, no * matrices *. Sus punteros pueden contener la dirección de una matriz de caracteres, pero si desea que se copie esa matriz, debe gestionarla explícitamente. –

Respuesta

13

Usted tiene otra opción que proporciona una función de copia a sí mismo:

void copy_person(person *dst, const person *src) 
{ 
    dst->name = malloc(strlen(src->name) + 1); 
    dst->surname = malloc(strlen(src->surname) + 1); 
    strcpy(dst->name, src->name); 
    strcpy(dst->surname, src->surname); 
} 

que puede ser más elaborado que eso: la comprobación de errores, factorizar el strlen + strcpy en una función auxiliar, etc.

Eso es lo los constructores de copia en C++ son para.

+4

Si está en un sistema POSIX (por ejemplo, linux), podría simplemente usar 'strdup' en lugar de' malloc + strcpy'. –

+1

@Jens: eso es lo que tenía en mi cabeza cuando escribí "factoring .... en una función auxiliar". –

7

Sí, struct copia que contiene carbón de leña matrices funcionará sin ningún problema, pero con estructura de char punteros (o cualquier tipo de puntero para el caso) tendrá que hacer manualmente.

También tenga en cuenta que el molde del tipo de retorno malloc no es necesario en C (está en C++) y puede ocultar un prototipo faltante para malloc.

0

Tiene que asignar memoria a cualquier puntero si desea hacer una copia. Sin embargo, siempre puede hacer que un puntero apunte a la memoria ya asignada. Por ejemplo, puede hacer lo siguiente:

p2.name = p1.name (p1.name is already allocated memory) 

Esto es peligroso , ya que hay más de una referencia a la misma posición de memoria. Si libera p1.name o p2.name, se produce una situación peligrosa.

Para copiar todo el contenido, debe asignar memoria a los punteros de la estructura p2.

p2.name = <allocate memory> 
Copy individual struct members instead of a memcpy of the entire struct 

Esto se debe a que la memoria no está asignada de forma contigua. También sizeof(struct) le dará el tamaño de los miembros de la estructura y no la memoria asignada.

Por ejemplo, sizeof(p2) = 8 = sizeof(p1)= sizeof(person) incluso después de asignar memoria a los miembros de p1.

Sería un caso diferente si los miembros hubieran sido matrices de caracteres.

1

Un poco fuera de la caja de pensamiento:

Dado que la estructura de su estructura es estática, se podría escribir un pequeño programa de utilidad o secuencia de comandos para generar el código de copia para ti.

Tome el código fuente de su definición de estructura como entrada, y luego diseñe un conjunto de reglas para generar el código de copiado.

Esto es una instantánea, y no sé si fue más rápido escribir el código de copiado manualmente, pero al menos es un problema más interesante.

1

Para obtener más información sobre la respuesta de Alexandre C. es posible que desee hacer el malloc() como una operación única para que un free() también sea simple.

Este enfoque proporciona un grado de protección en el que malloc() solo tendrá éxito o fallará para que no tenga un problema de malloc() que falla a mitad de la construcción de una copia. Con este enfoque, podría mezclar person con punteros a person que se han mallocido, por lo que es posible que desee tener dos tipos de datos diferentes, en la línea de los siguientes para marcar mejor cuál es cuál.

He proporcionado dos alternativas para la copia con una usando las funciones de biblioteca estándar C strcpy() y strlen() y la otra usando una función simple que hace una copia directa y devuelve un puntero al punto donde lo dejó en el búfer de destino.

No he intentado compilar este ejemplo, por lo que puede haber problemas con él.

Existe una posible preocupación con este enfoque. Como las cadenas individuales no están mal colocadas, puede encontrarse con un problema si mueve las cadenas individuales usando sus punteros con la idea de que cada una de las cadenas individuales es su propia área de memoria mal colocada. Este enfoque asume que se quiere el objeto completo o no se quiere nada de él.

#include <stdio.h> 
    #include <string.h> 
    #include <stdlib.h> 

    typedef struct { 
     char* name; 
     char* surname; 
     char* address1; 
    } person, *personptr; 

    // copy a string to destination string return pointer after end of destination string 
    char * StrCpyRetEnd (char *pDest, char *pSrc) 
    { 
     while (*pDest++ = *pSrc++); 
     return pDest; 
    } 
    personptr DeepCopyPerson (person *pSrc) 
    { 
     personptr  pDest = 0; 
     unsigned int iTotalSize = sizeof(person); 

     iTotalSize += (strlen(pSrc->name) + 1) * sizeof(char); 
     iTotalSize += (strlen(pSrc->surname) + 1) * sizeof(char); 
     iTotalSize += (strlen(pSrc->address1) + 1) * sizeof(char); 
     pDest = malloc(iTotalSize); 
     if (pDest) { 
#if 1 
      // alternative one without a helper function 
      pDest->name = (char *)(pDest + 1); strcpy (pDest->name, pSrc->name); 
      pDest->surname = pDest->name + strlen(pDest->name) + 1; strcpy (pDest->surname, pSrc->surname); 
      pDest->address1 = pDest->surname + strlen(pDest->surname) + 1; strcpy (pDest->address1, pSrc->address1); 
#else 
      // alternative two using StrCpyRetEnd() function 
      pDest->name = (char *)(pDest + 1); 
      pDest->surname = StrCpyRetEnd (pDest->name, pSrc->name); 
      pDest->address1 = StrCpyRetEnd (pDest->surname, pSrc->surname); 
      strcpy (pDest->address1, pSrc->address1); 
#endif 
     } 
     return pDest; 
    } 

    int main(void){ 
     person p1; // programmer managed person with separate mallocs 
     personptr p2; // created using ClonePerson() 

     p1.name  = malloc(5); 
     p1.surname = malloc(5); 
     p1.address1 = malloc(10); 

     strcpy(p1.name,"AAAA"); 
     strcpy(p1.surname,"BBBB"); 
     strcpy(p1.address1,"address1"); 

     p2 = DeepCopyPerson (&p1); 

     free(p1.name); 
     printf("%s\n", p2->name); 

     free (p2); // frees p2 and all of the memory used by p2 
     return 0; 
    } 
Cuestiones relacionadas