2011-08-10 10 views
1
#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 

int main() 
{ 
    int * ptr; 
    printf("before malloc pointer is :%p \n",ptr); 
    printf("before malloc valu is :%d \n",*ptr); 
    ptr = malloc(sizeof(int)); 
    printf("after malloc pointer is %p \n",ptr); 
    printf("after malloc valu is :%d \n",*ptr); 
    int jig=32; 
    *ptr = jig; 
    printf("after assignment valu is : %d\n",*ptr); 
    free(ptr); 
    printf("after free %p \n",ptr); // after free pointer holds sane address then 
    printf("after fee is %d\n",*ptr); // why it coudnt print that??? 
    return 0; 
} 

出力は次のようになります。フリー()の仕組みは?

before malloc pointer is :0x6edff4 
before malloc valu is :7265660 
after malloc pointer is 0x9a52008 
after malloc valu is :0 
after assignment valu is : 32 
after free 0x9a52008 
after fee is 0 

我々はそのメモリの値を印刷することはできませんなぜ無料まだポインタは、そのメモリのアドレスを保持した後??。

無料()は何ですか?

すべてのメモリを0にするだけですか?

+0

のprintfで「のmalloc VALUの前に」、あなたはNULLポインタを参照解除されています。それをしないでください。 –

+0

ポインタの宣言の後にNULLが指していない...それは安全です。 –

+1

いいえ、それは標準化されていないので、必ずしも安全ではありません。さらに、NULLの場合でもそれを尊重してはなりません。それはまともなシステム上のsegフォルトにつながります。また、今後はキャップロックの使用を控えてください。 –

答えて

4

フリースティルポインタがそのメモリのアドレスを保持した後、そのメモリの値を印刷できない理由

メモリがあなたのものではなくなったためです。あなたはfree dです。つまり、OSがそれを再利用することは許されていますが、より多くのメモリを割り当てる必要がある場合はどこにでも適合します。あなたはもはやそれを所有していないので、そのメモリに保持されているデータの価値を見ているビジネスはもうありません。また、その

注:

int *ptr; 
... 
printf("Before malloc valu is :%d\n", *ptr); 

も同様に無効です。 ptrはゴミ値を保持しており、どこでも指し示すことができます。参照解除すると、アクセス可能なメモリ位置であることが保証されません。これらの例

の両方が標準の「THISを、しないでください」とあなたは、標準を無視した場合、あなたの上司が見ている時はいつでもあなたのコードは恐ろしい方法で解除されます、と言う意味未定義の動作を呼び出します。

何が無料ですか?

すべてのメモリを0にするだけですか?

いいえ、必須ではありません。 OSは多くの場合、バックグラウンドで使用されていないメモリをゼロにしてcallocへの呼び出しを高速化しますが、freeはオペレーティングシステムに「このメモリで済んでいます。 OSは通常、いくつかのハウスキーピングデータを更新して、メモリブロックがプロセスによって所有されていないことを示します。そのため、後でmallocを呼び出すと必要な場合に使用できます。

+0

うわー...あなたはすべてを説明しています...あなたと思っています –

+0

私は自由にしたそれらのメモリにアクセスすることができます。 –

+1

@ Mr.32 - いいえ。メモリを解放した後のメモリへのアクセスは、未定義の動作です。コンパイラはあなたのコードに何かをさせることが法的に許可されています(通常のジョークは、鼻の悪魔です:[http://www.catb.org/jargon/html/N/nasal-demons.html])。 –

3

freeメモリをシステムに返します。 mallocへのパートナー操作です。 mallocで割り当てたメモリブロックはすべて、freeを呼び出してシステムに戻す必要があります。 freeに電話をした後、そのメモリにアクセスすることはできません。

freeを少なくともデバッグビルドで呼び出すと、ポインタをNULLに設定することをお勧めします。後で誤って逆参照しようとするとエラーが発生することがあります。


なぜ、まだ解放されているメモリにもアクセスできますか?まあ、あなたは確かにそうすることはできません。たいていのメモリ管理システムの実装は、時にはそのような濫用から逃れることができることを意味します。多くのメモリマネージャは、オペレーティングシステムから大きなメモリブロックを割り当て、次にアプリケーションに小さなサブブロックを割り当てます。 freeを呼び出すと、アロケータはそのブロックをすぐに利用可能なメモリのプールに戻しますが、OSメモリ割り当てルーチンは通常高価であるため、メモリをOSに戻す必要はありません。したがって、メモリは依然としてプロセスに割り当てられているため、アクセスすると動作するように見えることがあります。あなたのアプリではなくメモリマネージャーが所有しているだけです。そのようなことがここであなたに起こっています。

もちろん、あなたのソフトウェアを最も重要なクライアントのマシンに導入してしまえば、このような悪用を免れることはできません。

+0

私たちが何かをmallocするとき..どこにいてもこのメモリは見つけます。スタック..?ヒープで..?ラムで.. –

+0

@ 32これは実装固有のものですが、ほとんどのシステムでは 'malloc'はヒープメモリを割り当てます。 –

+0

RAM上のスタックとヒープの両方。 Mallocはヒープスペースを確保する必要があるため、関数の最後には削除されません。 –

3

malloc()free()の興味深いことは、彼らが実際にあなたに与えるメモリを変更しないということです。彼らは単にそれが "考えられた"方法を変えるだけです。

malloc()を呼び出すと、メモリのセグメントが選択され、自分のものになります。それはあなたのものですが、好きなように使うことができます。

あなたが完了したら、あなたはfree()ですが、まだそこにあります。それは今でも同じメモリですが、それはもうあなたのものとはみなされません。誰かがそれを使用している可能性があります。

[1]仮想アドレッシングを想定していますが、これは必ずしも真実ではないかもしれません。しかし、それはたいてい真実です。

1

通常、メモリマネージャには、後続の割り当てを満たすために使用されるフリーブロックのリンクリストのようなものがあります。

ここに私が数年前に書いた最小限の実装があります。それは深刻な使用のために本当に意図した(または適切な)ではありませんが、少なくともヒープを管理するための一つの方法のいくつかの一般的な概念を与える:

#include <stddef.h> 

typedef struct node { 
    size_t size; 
    struct node *next; 
} node; 

node *free_list; 

static void *split_end(node *block, size_t new_size) { 
    size_t difference = block->size - new_size; 

    node *temp = (node *)((char *)block + difference); 
    temp->size = new_size; 
    block->size = difference; 
    return (void *)((size_t *)temp+1); 
} 

static void *split_begin(node *block, size_t new_size) { 
    size_t difference = block->size-new_size; 
    node *temp = (node *)((char *)block + new_size); 
    temp->size = difference; 
    temp->next = free_list; 
    free_list = temp; 
    return block; 
} 

void b_init(void *block, size_t block_size) { 
    ((node *)block)->size = block_size - sizeof(node); 
    ((node *)block)->next = NULL; 
    free_list = block; 
} 

void b_free(void *block) { 
    node *b = (node *)((size_t *)block -1); 

    b->next = free_list; 
    free_list = b; 
} 

void *b_malloc(size_t size) { 
    node *temp, **ptr; 
    size_t larger = size+sizeof(node); 
    size += sizeof(size_t); 

    for (ptr = &free_list; 
     NULL != ptr; 
     ptr = &((*ptr)->next)) 
    { 
     if ((*ptr)->size >= size) { 
      if ((*ptr)->size <= larger) { 
       temp = (*ptr); 
       (*ptr) = (*ptr)->next; 
       return (void *)((size_t *)temp + 1); 
      } 
      else 
       return split_end(*ptr, size);  
     } 
    } 
    return NULL; 
} 

void *b_realloc(void *block, size_t new_size) { 
    node *b = (node *)((char *)block - sizeof(size_t)); 
    char *temp; 
    size_t i, size; 

    if (new_size == 0) { 
     b_free(block); 
     return NULL; 
    } 

    new_size += sizeof(size_t); 

    size = b->size; 
    if (new_size <size) 
     size = new_size; 

    size -= sizeof(size_t); 

    if (b->size >= new_size+sizeof(node *)) 
     return split_begin(b, new_size); 

    if (b->size >= new_size) 
     return b; 

    temp = b_malloc(new_size); 
    if (NULL == temp) 
     return NULL; 

    for (i=0; i<size;i++) 
     temp[i] = ((char *)block)[i]; 
    b_free(block); 
    return temp; 
} 

#ifdef TEST 
#define num 10 

int main(void) { 

    int i; 
    char block[4096]; 
    char *temp[num]; 
    char *big; 

    b_init(block, sizeof(block)); 

    big = b_malloc(100); 

    for (i=0; i<num; i++) 
     temp[i] = b_malloc(10); 

    for (i=0; i<num; i++) 
     b_free(temp[i]); 

    b_realloc(big, 200); 
    b_realloc(big, 10); 
    b_realloc(big, 0); 

    return 0; 
} 

#endif