2011-10-08 34 views
7

私は少し新しくて、メモリの仕組みを理解するのに問題があります。特にmemcpyのような組み込み関数があります。ここで C - Mallocとmemcpy(メモリ管理)

は私が

struct data_t { 
    int datasize; 
    void *data; 
}; 

使用していstructだと、ここで私はそれを使用している補助機能です:

struct data_t *data_create(int size) 
{ 
    struct data_t *dt=malloc(sizeof(struct data_t)+size); 
    dt->datasize=size; 
    dt->data="1234567890a"; 
    return dt; 
} 

今すぐ main機能で、私はこれをやって何の問題もありません。

struct data_t *data = data_create(1024); 
data->data="123456a";//just an example 

しかし、これによってSegフォルトが発生します。

memcpy(data->data,"123456a",strlen("1234567890a")+1); 

私の質問はなぜですか?そして、どうすればそれを避けることができますか? 私はC言語に新しいので、メモリとCのやりとりがちょっと新鮮であることに気をつけてください。

ありがとうございました。

編集:それは動作します!どうもありがとうございました。データポインタが完全に欠落しています。今はvalgrindによるとすべてがうまくいきます。

答えて

6

memcpy(data->data,"123456a",strlen("1234567890a")+1);

が割り当てられていないいくつかのごみ/無効なアドレスにdata->dataためvoid *タイプのポイントを失敗しました。 dataは、のreadonlyセクション(実行可能ファイルの.rodataのように)に格納されている文字列リテラルのアドレスを持ちます。このアドレスは書き込み可能ではありません。また、ポインタに文字列アドレスを割り当てなかった場合変数は、その後、そのように最初に割り当てる。バッファを割り当てまたはいくつかの有効な許可位置で初期化されていないいくつかの無効/ガベージアドレス値を保持することになる。

data->data = malloc (sizeof (char) * size); 

mallocアドレスのブロックの第1の位置のアドレスを戻しますatleast size * sizeof (char)バイト。sizeバイトをdata->dataが指し示すこのメモリ位置にコピーできます。

free (addr)コールでそのメモリボックを使用して作業を終了したときに、割り当てられたメモリブロックを解放することを忘れないでください。私はあなたが非常に奇妙な方法でdataバッファを割り当てることを試みている参照


(?):余分なstruct data_tとともにsizeバイトを割り当てられている

struct data_t *dt=malloc(sizeof(struct data_t)+size); 

。しかし、どんな場合でも、dataコンポーネントはまだ変更できない場所を指しています。 使用してください:

struct data_t *dt = malloc(sizeof(struct data_t)); 
dt->data = malloc (sizeof (char) * size); 
memcpy (data->data, "whatever", sizeof ("whatever")+1); 
return dt; 

を最初にやる解放する。その後、

free (dt->data); 

free (dt); 
+0

スペースが初期割り当てに配分されました。ポインタは単に割り当てられたスペースを指すように設定されていませんでした。 –

+0

@JonathanLeffler:はい、Askerは最初に割り当てるときに余分なスペースを割り当てました。ポイントに初期化しておく必要がありました。一度にすべてを割り当てる特別な必要がなければ、私は依然として明示的な呼び出しを好むでしょう。 – phoxis

+0

これは "mallocから返されたポインタを明示的にキャストしなければならない"という問題を解決するために、 "無効な変換を 'void *'から 'data_t *' [-fpermissive]に変更します。 – VasaraBharat

1

お知らせvoid *datadata_createで、ポインタである、あなたはそれのためのスペースを割り当てていなかった、あなたは読み込み専用の文字列定数"1234567890a"を指すようにしてください。

mainには、別の文字列定数"123456a"を作成し、void *dataを読み取り専用の文字列定数に設定します。

memcpyを呼び出して、書き込み可能でない(または初期化していない)メモリアドレスに書き込むと、エラーが発生します。

0

data-> dataはポインタです。そして、このポインタはどこにも向いていません。 memcpyを実行する前に、スペースを割り当てて、このスペースを指すようにデータ - >データを作成する必要があります。

data->data = malloc(strlen("1234567890a")+1); 

、その後のmemcpyは限りデータ - >データとして失敗することはありません! "123" は、コンパイル時に割り当てられているので、=

data->data = "123"

をやっNULL

は、okです、 data-> dataは文字列 "123"の先頭を指しますが、memcpy(data->data,"123",4)を呼び出すと失敗します。なぜなら、データ・データへのポインタは初期化されておらず、読めないメモリのランダムな場所を指しているからです。

+0

'memcpy'はソースコードよりも多くのバイトをソースコードよりもコピーしようとすると無効です。 – Mat

+0

はいコードに2つのエラーがあります –

3

あなたの最初の間違いはこれです:

struct data_t *dt=malloc(sizeof(struct data_t)+size); 

これは、サイズの構造体data_t +サイズのメモリのチャンクを作成します。私はあなたが期待したことは、data_t内のデータフィールドがこのメモリを使用できるが、データがこのメモリのアドレスを保持しないためできないということだったと思います。

あなたの第二の間違いは、あなたがここで、「データ」に次の文字列の値をコピーすることを前提とした:

実際には、ここで起こっ存在するメモリ「123456a」の文字列があることは何
data->data="123456a"; 

あなたのプログラムの全生涯にわたって。実際に何が起こっているのかは、データ - >データに "123456a"を割り当てると、この文字列 "123456a"のアドレスを取得して、値( "123456a")をコピーしていないデータ - >データに置きますが、または "123456a"のアドレス(0x23822 ...)。

最終的な間違いは、このでした:

memcpy(data->data,"123456a",strlen("1234567890a")+1); 

あなたはメモリに値をコピーするために「123456a」を試してみましたデータによって指されます。データは何を指していますか?これは、以前に割り当てられた文字列 "123456a"を含むメモリの読み取り専用領域を指しています。言い換えれば、プログラムに "123456a"のアドレスに書き込むように指示しました。ここで

は、あなたが期待するものを何をするかのプログラムです:

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

typedef struct { 
    size_t datasize; 
    char *data; 
} data_t; 

data_t *data_create(size_t size) 
{ 
    data_t *dt; 

    dt = malloc(sizeof(data_t)); 
    assert(dt != NULL); 
    dt->data = malloc(size); 
    assert(dt->data != NULL); 
    dt->datasize = size; 

    /* need to decide what to do when this happens */ 
    assert((strlen("1234567890a") + 1) < size); 
    strcpy(dt->data, "1234567890a"); 

    return dt; 
} 

void data_destroy(data_t *dt) 
{ 
    free(dt->data); 
    free(dt); 
} 

int main(void) 
{ 
    data_t *data = data_create(1024); 
    /* data->data="123456a"; DONT DO THIS YOU WILL CAUSE A MEMORY LEAK */ 

    assert(data->datasize >= (strlen("123456a")+1)); 
    memcpy(data->data, "123456a", strlen("123456a")+1); 

    printf("%s\n", data->data); 

    data_destroy(data); 

    return EXIT_SUCCESS; 
}