2011-02-08 66 views
40

構造体メンバをメンバー単位でコピーできますが、構造体の代わりにmemcpy構造体をコピーできますか?ある構造体を別の構造体にコピーする

そうすることをお勧めしますか?

私の構造では、同じメンバーを持つ別の構造体にコピーしなければならないメンバとしての文字列もあります。それ、どうやったら出来るの?構造は、互換性のあるタイプである場合

+3

なぜCでタグ付けされた質問の「メンバー関数」について話していますか? – unwind

+2

構造体または少なくとも構造体の抽出を表示できますか?私は文字列がメンバー_function_ではないと仮定します"文字列"は文字配列か、動的に割り当てられるchar *か何か? – rjnilsson

答えて

51

普通の割り当てによるコピーは、短く読みやすく、抽象度が高いため、最適です。 (コードの人間の読者に)「これらのビットをここからそこにコピーする」と言うのではなく、読者にコピーのサイズの引数について考えるように要求するのではなく、単純な割り当て(「この値をここにここに」)。サイズが正しいかどうかについては心配する必要はありません。

構造が重く埋め込まれていると、割り当てがパディングをコピーする必要がなく(そしてどこにあるかを知っているので)、コンパイラがより効率的に放射するようになるかもしれませんが、mempcy()はそうしませんコピーするバイト数を常に正確にコピーしてください。

文字列が実際の配列、つまり:

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

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

は、その後、あなたはまだ、プレーンの割り当てを使用することができます。

b = a; 

は完全なコピーを取得するには。このようにモデル化された可変長データの場合、配列全体が常にコピーされるので、これはコピーを行う最も効率的な方法ではありません。

そうすることによって、あなたはエイリアシングポインタ、および一般的にコピー動作後のポインタを所有している人、それは曖昧作っているので、しかし、ヒープ割り当てられたメモリへのポインタを含むそのコピーの構造体は、少し危険なことができます注意してください。

"ディープコピー"は実際には唯一の選択肢であり、その機能に入る必要があります。

12

は、はい、あなたは、のようなものとすることができます

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

あなたが知っておく必要がある唯一のものは、これが浅いコピーであるということです。つまり、特定の文字列を指しているchar *がある場合は、の両方の構造が同じ文字列を指します。

これらの文字列フィールド(char *自体ではなく、char *が指し示すデータ)の内容を変更すると、他のものも変更されます。

あなたがstrdupを使用し、手動で各フィールドを行うことなく、しかし非浅い文字列のコピーの追加ボーナスを簡単にコピーしたい場合:

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

これは、構造体の全体の内容をコピーし、その後、各構造体に別々の文字列を効果的に与えて、文字列を深くコピーします。

また、C実装にstrdup(ISO標準の一部ではない)がない場合はget one from hereです。

4

あなたはmemcpy構造体でもかまいません。他の値と同じように割り当てることもできます。

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

これは質問に記載されている文字列でも保持されますか? – Jonas

+1

はい、ポインタではなく配列です。 – Simone

34

C90は、あなたが簡単に使用することができますので:

dest_struct = source_struct; 

として長い文字列は、アレイ内に記憶されるよう:

struct xxx { 
    char theString[100]; 
}; 

そうでなければ、それはポインタだ場合、あなた'LL手でそれをコピーする必要があります。

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

C90の前にはどうなりますか?あなたの例のような配列が構造体に含まれている場合は、C90以前のコンパイラとC90以降のコンパイラの間の構造体の代入の違いは何ですか? – cesss

+0

@cesss:C90/C89の前には、Cの正式な標準がなかったので、使用したコンパイラに依存していました。 'struct'のすべてのサポートが割り当てられているわけではありません。 C90はそれをサポートするためにコンパイラを必要とするので、C90(またはそれ以降)に準拠するコンパイラであれば誰でも実行できます。 – sleske

0
  1. 構造体を使用してファイルに書き込むことができます。 `char * 'としてキャストする必要はありません。 構造体のサイズも保持されます。単一文字列フィールド(から&に)移動するに

  2. あなたはstrncpy とAを使用する必要があります。 ( ハードメモリに振る舞うことは、多くの場合、1をRAMに似ているこの点は話題に最も近いではありませんが、それを推測。)一時的な文字列バッファ'\0'が終了します。 どこかで、レコード文字列フィールドの長さを覚えておく必要があります。ポイント-2を回避するために、あなたはそれに合わせて構造体の中に、各文字列を埋め込むことができます例: 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... 
    
  3. 、 を使用すると、ドット表記を使用することができ、他のフィールドを移動するには

  4. NodeB->txt2fi=NodeA->txt2fi ...しかしscanfためのポイント-2で述べたように、あなたはまだ過渡文字列 プラスワンstrncpyの必要があるでしょう、printf:コボルのように振る舞いますそうでなければ、オペレータは長い入力(短い)、 は(スペースが埋め込まれた)切り捨てられませんでした。

  5. (NodeB->insidenode_subvar).mypointer=(NodeA->insidenode_subvar).mypointer は、ポインタエイリアスを作成します。
  6. NodeB.txt3=NodeA.txt3 は、コンパイラが拒否する原因: error: incompatible types when assigning to type ‘char[3]’ from type ‘char *’
  7. ポイント-4は、同じtypedefに属しているだけNodeB->txt2fi & NodeA->txt2fiので動作します!

    このトピックに正しいと簡単な答え私は、「(も文字の)配列がCに二級市民です」 In C, why can't I assign a string to a char array after it's declared? で発見!

関連する問題