2009-09-24 12 views
8

Ho le seguenti due strutture in cui "struttura figlio" ha una "struttura di rusage" come elemento.Programmazione C. Come copiare in profondità una struttura?

Poi creo due le strutture di tipo "figlio" chiamiamoli Childa e childB

Come faccio a copiare solo la struct rusage da Childa a childB?

typedef struct{       
     int numb; 
     char *name; 
     pid_t pid; 
     long userT; 
     long systemT; 
     struct rusage usage; 
}child; 


typedef struct{ 
    struct timeval ru_utime; /* user time used */ 
    struct timeval ru_stime; /* system time used */ 
    long ru_maxrss;  /* maximum resident set size */ 
    long ru_ixrss;   /* integral shared memory size */ 
    long ru_idrss;   /* integral unshared data size */ 
    long ru_isrss;   /* integral unshared stack size */ 
    long ru_minflt;  /* page reclaims */ 
    long ru_majflt;  /* page faults */ 
    long ru_nswap;   /* swaps */ 
    long ru_inblock;  /* block input operations */ 
    long ru_oublock;  /* block output operations */ 
    long ru_msgsnd;  /* messages sent */ 
    long ru_msgrcv;  /* messages received */ 
    long ru_nsignals;  /* signals received */ 
    long ru_nvcsw;   /* voluntary context switches */ 
    long ru_nivcsw;  /* involuntary context switches */ 

}rusage; 

Ho fatto la seguente, ma credo che copia la posizione di memoria, perché se ho cambiato il valore di utilizzo in Childa, cambia anche in childB.

memcpy(&childA,&childB, sizeof(rusage)); 

So che fornisce a childB tutti i valori da childA. Mi sono già occupato degli altri campi in childB, ho solo bisogno di essere in grado di copiare la struttura di rusage chiamata usage che risiede nella struttura "child".

+0

tutto il vostro lavoro il suggerimento di fare una copia esatta di Childa, ma se mai cambiare Childa, anche childB cambia. – user69514

+0

C'è qualcos'altro che non va nel tuo codice. Tutte le risposte alla tua domanda sono corrette e produrranno l'effetto che desideri. Se non funziona, il problema è altrove. –

+0

@uknown - ciò significa che le due istanze della struttura si trovano allo stesso indirizzo (ovvero che sono la stessa istanza) o che qualcosa sta cambiando due istanze distinte dei dati in due indirizzi diversi (o che si sta confondendo in cosa stai segnalando). – ChrisW

risposta

20

Semplicemente:

childB.usage = childA.usage; 
+0

Molto più semplice, possibilmente più veloce di memcpy() e certamente non più lento. –

+0

@Jonathan, probabilmente il compilatore usa memcpy – leiz

+0

Qualcuno può ricordare qual è la versione più vecchia di C che lo supporta, piuttosto che dover usare esplicitamente memcpy()? –

10

non dovrebbe essere:

memcpy(&(childB.usage), &(childA.usage), sizeof(rusage)) 
+0

Il primo parametro in memcpy è la destinazione, quindi per copiare da A a B, è necessario inserire A come secondo param. –

+0

E, naturalmente, se si dispone di un puntatore nella struttura, è necessario eseguire un po 'più di lavoro per creare un valore duplicato, ma nel proprio esempio, la struttura che si desidera copiare non ha alcun puntatore, quindi la memcpy dovrebbe essere a posto . –

+0

+1 - Sono d'accordo con la tua logica che dal momento che il rusage non ha alcun suggerimento questo dovrebbe funzionare bene. –

0

prima, il codice corretto è

memcpy(&childA,&childB, sizeof(child)); 

secondo, questo copierà i valori Asis, quindi per tutte quelle strutture lunghe e temporanee saranno sicure, ma il parametro nome char * che avrai puntatore allo stesso valore originale.

+0

Questo copierà l'intero bambino, non "copia solo la struttura di rusage da childA a childB". – ChrisW

+0

hai ragione, ho letto male la fine della domanda – Amirshk

0

childB.usage = childA.usage

Dal momento che hai l'intera struttura all'interno della struttura del bambino, semplice copia basta. Se avessi un puntatore alla struttura di rusage all'interno della struttura figlio, avrebbe potuto essere un problema. In tal caso, avresti dovuto allocare memoria per childB.usage e quindi fare una memcpy in modo tale che se qualcuno modifica/elimina childA, childB sarà illeso.

0

Si potrebbe due che in due modi, come altri hanno menzionato.

1) childB.usage = childA.usage;
2) memcpy (& childB.usage, & childA.usage, sizeof (rusage));

Primo argomento di memcpy è la destinazione, la seconda è la fonte e la terza è la lunghezza (quanti byte si desidera copiare). Dal codice che hai postato, stavi cercando di copiare l'intero childB in childA, che in realtà non è quello che volevi.

0

in questo file copio i membri di origine a DESTINAZIONE, primi utilizzando solo le assegnazioni e strcpy, poi, copio origine a memres, utilizzando solo memcpy

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

typedef struct inner 
{ 
    char *parola; 
    int n; 
} interna; 

typedef struct outer 
{ 
    struct inner *ptr; 
    int numeroesterno; 
} esterna; 


struct another 
{ 
    struct inner *ptr; 
    int numero; 
}; //never forget ; here 

int main(void) 
{ 
    esterna *origine; //ptr to structs 
    struct another *destinazione; 
    struct another *memres; 

    char *tmpParola; 
    tmpParola = malloc(30*sizeof(char)); 
    strcpy(tmpParola, "AAAAA"); 

    interna *tmp; //remember the TYPEDEF, and don't use struct interna 
    tmp = (interna *)malloc(sizeof(struct inner)); 
    // if you use struct interna in sizeof you get 
    // error: invalid application of ‘sizeof’ to incomplete type ‘struct interna’ 

    tmp->n = 500; 
    tmp->parola = tmpParola; 

    origine = (esterna *)malloc(sizeof(struct outer)); 

    origine->numeroesterno = 2; 
    origine->ptr = tmp; //the data structer pointed by tmp has already been allocated and set 

    // now I have the structure allocated and set, I want to copy this on destinazione 
    destinazione = (struct another *)malloc(sizeof(struct another)); 

    destinazione->numero = origine->numeroesterno; 

    //destinazione->ptr = tmp; //in this case you don't copy struct inner, it's just a reference 

    destinazione->ptr = (interna *)malloc(sizeof(struct inner)); 
    destinazione->ptr->parola = malloc(sizeof(char)*30); 
    strcpy(destinazione->ptr->parola, origine->ptr->parola); 
    destinazione->ptr->n = 111; 

    //modify origine 

    origine->numeroesterno = 9999; 
    strcpy(origine->ptr->parola, "parola modificata in origine"); 

    //print destinazione 

    printf("\nparola in destinazione :%s\n", destinazione->ptr->parola); 
    printf("\nparola in origine :%s\n", origine->ptr->parola); 

    //you can see that destinazione is a copy, because mofifying origine, destinazione deosn't change 

    //now we play with memcpy 

    memres = (struct another *)malloc(sizeof(struct another)); 

    memcpy(memres, destinazione, sizeof(destinazione)); //till here, is AAAAA 
    strcpy(destinazione->ptr->parola, "parola modificata in destinazione"); 

    printf("\nmemcpy, numero %d\n", memres->numero); 
    printf("\nmemcpy, parola :%s\n", memres->ptr->parola); 

    //as you can see from the output, memcpy doesn't make a copy of destinazione: 
    //modifying destinazione->ptr->parola after the assignment affects what memres carries with it 
    //So from the idea that I got, memcpy just creates the pointers to the originary structure 

    free(origine->ptr->parola); 
    free(origine->ptr); 
    return 0; 
} 
2

EDIT: Ok, ho letto male la questione , volevi solo copiare il campo di utilizzo; quindi la mia risposta è un po 'non correlata. Non lo elimino perché può ancora ricordare ai principianti il ​​potenziale problema di aliasing durante l'assegnazione o la duplicazione di una struttura contenente puntatori.

Il memcpy o l'assegnazione delle altre risposte funzionerà, ovviamente. L'unico pericolo nelle tue strutture deriva dal puntatore al nome.Se si copia una struttura all'altra, entrambe le strutture contengono lo stesso puntatore e puntano alla stessa memoria. Hai creato un alias. questo significa che se cambi il nome nello spazio allocato, sarà visibile dall'altra struttura. Inoltre, esiste il pericolo di un doppio free se si passa la struttura alla funzione standard gratuita. Per effettuare una vera e propria duplicato del struct si dovrebbe fare qualcosa di simile:

memcpy(&childA,&childB, sizeof(rusage));  
if(childB.name) 
    childA.name = strdup(childB.name); 

o in alternativa

childA = childB; 
if(childB.name) 
    childA.name = strdup(childB.name);