2011-08-02 32 views
11

高度に下降した状態になる前に、私がすでに見たような質問がありますが、私の具体的な質問には、少なくとも、(その場合は私の無知を言い訳)、またはそれらは必ずしもC固有のものではない。C:構造体の深いコピーを作成する...構造体の浅いコピーを作成する

私の質問は、メンバとしてポインタを持つ構造体の深いコピーを作成する方法と、ポインタであるメンバを持つ構造体のSHALLOWコピーを作成する方法に関するものです。次に、参照のために、ポインタメンバーなしで構造体の深いコピーを作成する方法と、ポインタメンバーなしで構造体の浅いコピーを作成する方法(最後のものが意味をなさない場合はわかりません)。

のは、我々はこれを持っているとしましょう。ここでは

typedef struct Student 
{ 
    char* first_name; 
    char* last_name; 
    int grade; 
    long id; 
} Student; 

は(ヘッダは私と一緒に負担してくださいフォーマットするのが難しい中である)私は学生を作成するために作られた汎用的な機能である:

Student* create_student(const char* first_name, const char* last_name, int grade,long id) 

{ 

    Student *newStudentp = (malloc(sizeof(Student))); 

    newStudentp -> last_name = (malloc((strlen(last_name) + 1) * sizeof(char))); 
    newStudentp -> first_name = (malloc((strlen(first_name) + 1) * sizeof(char))); 

    strncpy(newStudentp -> first_name, first_name, strlen(first_name) + 1); 
    strncpy(newStudentp -> last_name, last_name, strlen(last_name) + 1); 

    newStudentp -> grade = grade; 
    newStudentp -> id = id; 


    return newStudentp; 
} 

私は深くて浅いコピーを作ろうとします。私は今

int main() 
{ 
    Student *s1 = create_Student("Bo","Diddly", 100, 221); 
    Student *s2 = create_Student("Leeroy","Jenkins",50,1337); 
    memcpy(&s2,&s1,sizeof(Student)); //shallow copy of s1 INTO s2? 
    return 0; 
} 

愚かな何かをする場合、私たちはポインタと賢明な何かを私たち自身のコピー機能を作成する必要があります知っているポインタメンバーと構造体の詳細コピーのために、私に教えてください。その賢明なことは...私は確信していません...だから、このDEEPのコピーで私の(おそらく哀れな)試みです。

void copy_Student(Student *s1, Student *s2) 
{ 
    s2 -> grade = s1 -> grade; 
    s2 -> id = s1 -> id; 
    s2 -> first_name = s1 -> *first_name; 
    s2 -> last_name = s1 -> *last_name; 

} 

私の質問の他の部分は、おそらくちょうど口頭で説明することができます。

さて、EDITED有益なコメント読んだ後:

シャローコピーを: のmemcpy(S2、S1、はsizeof(学生));

ディープコピー:

void free_student(Student* stu) 
{ 
    free(stu -> first_name); 
    free(stu -> last_name); 
} 

void copy_Student(Student *s1, Student *s2) 
{ 
    s2 -> grade = s1 -> grade; 
    s2 -> id = s1 -> id; 
    s2 -> first_name = strdup(s1 -> first_name); 
    s2 -> last_name = strdup(s1 -> last_name); 
} 

みんなありがとう(ただし、まだエラーがある場合は指摘してください)!

おかげでそんなに、 フィル

+0

free_studentは、学生が終了した後に呼び出される必要があります。** copy_Student **には含まれていません。最初にs2を解放してからコンテンツをコピーします。いい考えではない。 –

+0

Dulyが指摘した。ありがとう! – Phil

答えて

5

浅いコピーを作成するように指定したコードはありません。それは実際にスタックを粉砕し、恐らくプログラムをクラッシュさせるでしょう。

Student *s1 = create_Student("Bo","Diddly", 100, 221); 
Student *s2 = create_Student("Leeroy","Jenkins",50,1337); 
memcpy(&s2,&s1,sizeof(Student)); //shallow copy of s1 INTO s2? 

サイズが正しい場合は、s2 = s1;と同じになります。しかし、あなたはサイズが間違っているので、それはあまりにも多くコピーされ、s2の後のメモリにあるものはすべて上書きします。本当のシャローコピーを行うには、&をオフのままに:ディープ・コピーのためのあなたが持っている

memcpy(s2,s1,sizeof(Student)); //shallow copy of s1 INTO s2 

をコードが同様に間違っている、しかし、あなたは正しい軌道に乗っています。深いコピーの背後にある基本的な考え方は、各フィールドをコピーする必要があることです。非ポインタ型の場合は浅いコピーと同じですが、ポインタの場合はスマートな処理が必要です。しかし、投稿したコードはそれをしていません。代わりにこれを試してください。

void copy_Student(Student *s1, Student *s2) 
{ 
    s2 -> grade = s1 -> grade; 
    s2 -> id = s2 -> id; 
    s2 -> first_name = strdup(s1 -> first_name); 
    s2 -> last_name = strdup(s1 -> last_name); 
} 

メモリリークを回避するための注意、あなたはまた、新しいコピーを割り当てる前にs2から古い名前を解放し、これらの名前を解放するでしょうfree_Student機能を作り、そしてまた必ずcreate_Studentコピー名ことを確認する必要があります最初に(あるいは、 "自由にすべき"フラグを含めて、リテラル文字列をコピーする必要はありません)。

ポインタ(または他の参照型)を持たない構造体の場合、データ構造自体が浅いため、深いコピーと浅いコピーの間に違いはありません。

+1

strdupはC標準ではありません – user411313

+0

@ user411313:そうですか?これはPOSIXとSVr4と4.3BSDにあります。何らかの理由であなたがそれを提供していない環境にいるなら、strlen、malloc、およびmemcpyを使って置換えを書くのは簡単です。 – Anomie

2

シャローコピーとディープコピーの違いは、一つの文章で説明することができます。浅いコピーコピーポインタ。深いコピーは、それらが指しているものをコピーします。

質問の最後から始める:ポインタがない場合は、浅いコピーと深いコピーの間に違いはありません。

浅いコピーを作成しようとすると、技術的に正確です。しかし、それは論理的に間違っています。 delete_student()関数(mallocを解放する関数)は、浅いコピーを扱うことができません。他の生徒のコピーがまだいくつあるか分からず、free()をアルストのコピーが削除されるまで延期する必要があります。

ディープコピーには非常に関連した問題があります。それは技術的に間違っています。奇妙なことに、create_student関数は、char *を別のものにコピーする方法を知っていることを示します。これは、first_namelast_nameの両方のディープコピーを持ちます。あなたのcopy_Studentは同じことをする必要があります。

0

コピーとして考えるのではなく、新しい構造体を作成しますが、複製するパラメータと同じパラメータで作成するのはなぜですか?

Student *s2 = create_Student("Leeroy","Jenkins",50,1337); 
Student *wiper = create_Student(s2->first_name, s2->last_name, 
               s2->grade, s2->id); 

wiper構造体がs2のクローンを持っている:それはあなたが既にコードを持って、微妙な違いですが。浅いコピーを作成する

、あなたがs1s2でやっているようです(memcpy)、または単に:ここ

s2 = malloc(sizeof(Student)); 
*s2 = *s1 
0
memcpy(&s2,&s1,sizeof(Student)); //shallow copy of s1 INTO s2? 

あなたはs2内ポインタs2とポインタを上書きしてしまいましたs1の対応するポインタの値によって、メモリがリークしてしまっています。

ディープコピーを実行するには、先に宛先構造体がポイントしていたメモリをすべて解放する必要があります。次に、ソース構造体が指す文字列を保持するのに十分なメモリを割り当てます。今、strncpyの上の文字列。これに代えて

void copy_Student(Student *s1, Student *s2) 
{ 
    assert((s1 != NULL) && (s2 != NULL)); 

    if(s2->first_name != NULL) free(s2->first_name); 
    if(s2->last_name != NULL) free(s2->last_name); 

    s2->grade = s1->grade; 
    s2->id = s1->id; 

    s2->last_name = (malloc((strlen(s1->last_name) + 1) * sizeof(char))); 
    s2->first_name = (malloc((strlen(s1->first_name) + 1) * sizeof(char))); 

    strncpy(s2-> first_name, s1->first_name, strlen(s1->first_name) + 1); 
    strncpy(s2-> last_name, s1->last_name, strlen(s1->last_name) + 1); 
} 
0

newStudentp -> last_name = (malloc((strlen(last_name) + 1) * sizeof(char))); 

は行います

s2->first_name = strdup (s1->first_name); 

newStudentp -> last_name = strdup (last_name); 

あなたの深いコピーは(cnicutarが示唆されていない、まさに)似た何かをしたいですcnicutarの問題それはstrcpyの前に手動でバッファを割り当てる必要があるということです。

正しく覚えている場合:

* s2 = * s1;

は浅いコピーを行います。

もちろん、深いコピーと浅いコピーの両方で、宛先ポインタがfreeであることを確認する必要があります。そうしないと、メモリリークが発生します。しかし、ポインタがfreeであっても、以前は浅くコピーされた構造にディープコピーすると、問題が発生する可能性があります。

+0

strdupはC標準ではありません、mallocは – user411313

関連する問題