2009-09-24 13 views
8

Ich habe die folgenden zwei Strukturen, in denen "child struct" eine "rusage struct" als Element hat.C Programmierung. Wie man eine Struktur tief kopiert?

Dann erstelle ich zwei structs vom Typ „Kind“ nennen wir sie Childa und childB

Wie kopiere ich nur die rusage Struktur von Childa zu 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; 

Ich habe folgendes, aber ich denke, es kopiert den Speicherplatz, denn wenn ich den Wert der Nutzung in Childa verändert, ändert sich auch in childB.

Ich weiß, dass gibt childB alle Werte von childA. Ich habe bereits auf die anderen Felder in childB aufgepasst, ich muss nur in der Lage sein, die Russe-Struktur namens usage zu kopieren, die sich in der "child" -Struktur befindet.

+0

all Ihr Vorschlag Arbeit eine exakte Kopie von Childa zu machen, aber wenn ich jemals Childa ändern, childB ändert sich auch. – user69514

+0

Mit Ihrem Code stimmt etwas nicht. Alle Antworten auf Ihre Frage sind korrekt und erzeugen den von Ihnen gewünschten Effekt. Wenn es nicht funktioniert, ist das Problem woanders. –

+0

@uknown - das bedeutet, dass entweder die beiden Strukturinstanzen dieselbe Adresse haben (dh sie sind dieselbe Instanz), oder dass etwas zwei unterschiedliche Instanzen der Daten an zwei verschiedenen Adressen ändert (oder dass Sie sich irren) in dem, was du berichtest). – ChrisW

Antwort

20

einfach:

childB.usage = childA.usage; 
+0

Viel einfacher - möglicherweise schneller als memcpy() und sicherlich nicht langsamer. –

+0

@ Jonathan, der Compiler verwendet wahrscheinlich memcpy – leiz

+0

Kann sich jemand erinnern, was ist die älteste Version von C, die das unterstützt, anstatt memcpy() explizit verwenden zu müssen? –

10

Sollte es nicht sein:

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

Der erste Parameter in memcpy ist das Ziel. Um A nach B zu kopieren, brauchen Sie Platz A als zweites param. –

+0

Und natürlich, wenn Sie einen Zeiger in der Struktur haben, müssten Sie etwas mehr Arbeit, um einen doppelten Wert zu machen, aber in Ihrem Beispiel, die Struktur, die Sie kopieren möchten, hat keine Zeiger, so dass Memcpy in Ordnung sein sollte . –

+0

+1 - Ich stimme Ihrer Logik zu, dass, da die Russe keine Zeiger hat, das gut funktionieren sollte. –

0

erste, der richtige Code ist

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

Sekunde, dies kopiert die Werte ASIS, so für all diese langen und Zeit Strukturen wird es sicher sein, , aber die Char * Name-Parameter haben Sie Zeiger zum selben ursprünglichen Wert.

+0

Das wird das ganze Kind kopieren, nicht "kopieren Sie nur die Russe-Struktur von childA nach childB". – ChrisW

+0

du hast Recht, ich habe das Ende der Frage falsch gelesen – Amirshk

0

childB.usage = childA.usage

Da Sie die gesamte Struktur innerhalb der Kindstruktur haben, genügt einfache Kopie. Wenn Sie in der Kindstruktur einen Zeiger auf die Rausagestruktur hatten, könnte das ein Problem gewesen sein. In diesem Fall müssten Sie Speicher für childB.usage zuweisen und dann einen memcpy ausführen, damit childB bei jedem Ändern/Löschen von childA unversehrt bleibt.

0

Sie könnten zwei auf zwei Arten, wie andere bereits erwähnt haben.

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

Das erste Argument von memcpy ist das Ziel, das zweite ist die Quelle und das dritte ist die Länge (wie viele Bytes Sie kopieren möchten). Aus dem Code, den Sie gepostet haben, haben Sie versucht, das gesamte childB in childA zu kopieren, was wirklich nicht erwünscht ist.

0

in dieser Datei kopieren ich die Mitglieder von origine Destinazione, zunächst nur mit Zuweisungen und strcpy, dann kopieren i origine zu memres, nur MEMCPY mit

#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, ich die Frage falsch verstanden , Sie wollten nur das Verwendungsfeld kopieren; Also meine Antwort ist ein wenig unabhängig. Ich lösche es nicht, weil es immer noch Anfänger an das potentielle Aliasing-Problem erinnert, wenn man eine Struktur mit Zeigern zuweist oder dupliziert.

Die memcpy oder Zuordnung der anderen Antworten wird natürlich funktionieren. Die einzige Gefahr in Ihren Strukturen kommt vom Zeiger zum Namen.Wenn Sie eine Struktur in die andere kopieren, haben Sie beide Strukturen, die den gleichen Zeiger enthalten und auf denselben Speicher zeigen. Sie haben einen Alias ​​erstellt. Das heißt, wenn Sie den Namen im zugewiesenen Bereich ändern, wird er von der anderen Struktur aus sichtbar. Außerdem besteht die Gefahr eines doppelten free, wenn Sie Ihre Struktur an die Standardfreigabe übergeben. Um eine echte Kopie der Struktur machen Sie so etwas tun sollen:

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

oder alternativ

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