2017-09-28 9 views
2

以下のプログラムでreallocを使ってメモリを再割り当てしようとしていますが、malloc(i =(int *)malloc(5 * sizeof(int)))を使って反応した初期メモリをreallocした後もチェックしています私は別のポインタ(すなわち* m)を使ってチェックしたrealocの後にデータにアクセスすることができます。これは適切な行動ですか?またはreallocが呼び出されるとメモリは解放されるべきですか?は、既存のメモリをrealloc解放しますか?

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

    int main() 
    { 
     int *i,*jn, *m; 
     i = (int*)malloc(5 * sizeof(int)); 
     int j,k=10; 

     for(j=0 ;j<5; j++) 
     { 
     i[j] = j; 
     printf("%d \n",i[j]); 
     } 

     for(j=0 ;j<5; j++) 
     { 
     printf("%p\n",i++); 
     } 

     jn = (int *)calloc(5, sizeof(*i)); 

     for(j=0 ;j<5; j++) 
     { 
     printf("%p\n",jn++); 
     } 

     i = i-5; 
     m = i; 

     printf("m = %p %d\n",(m+1), *(m+1)); 

     i =(int *)realloc(i,8*sizeof(int)); 

     for(j=0 ;j<8; j++) 
     { 

     printf("%d\n",i[j]); 
     } 

     for(j=0 ;j<8; j++) 
     { 

     printf("%p\n",i++); 
     } 
     printf("m = %p %d\n",(m+1), *(m+1)); 

     return 0; 
} 
+1

私はこれを特定の行動ではなく所有権の問題と考えます。 'realloc'が成功した場合、それは着信メモリの所有権を取るか(それを操作するか' free'ingする)、呼び出し関数によって使用できる(所有されている)ポインタを返します。 'realloc'が失敗した場合(' NULL'を返す)、あなたの関数は元のメモリの所有権を保持し、それが終了したら '解放 'しなければなりません。 – Myst

答えて

4

まず、reallocは単に拡大/で」元のブロックを縮小し、新しいメモリブロックを割り当ててデータをコピーし、オリジナルのものを解放する、または

    1. に決めるかもしれません新しい場所を割り当てずに「場所」を指定します。

    どのアプローチを選択するかは、実装やさまざまな外部要因によって異なります。それは最初のアプローチに従うかもしれません。あるいは、それは第2のアプローチに従うかもしれない。ポインタimの値をreallocの後に比較することで、どのアプローチに続いたのかを簡単に把握できます。

    第2に、reallocが第1のアプローチに従う(すなわち、新しいメモリブロックを割り当てる)と決定された場合、古いブロックは確かにreallocによって解放される。その場合、元のメモリ位置にアクセスしようとすると、未定義の動作につながります。

    reallocが第2のアプローチに従う(つまり、元のメモリブロックを "インプレース"に拡張または縮小する)と決定された場合、mおよびiは同じ場所を指し続けます。その場合、同じデータをmまで見ることは驚くことではありません。

    P.S.つまり、コードの動作は、、簡潔なまたはのいずれかです。です。それは実際に行動が「適切」であるかどうかを分析するのに実際には使用できません。メモリが実際に解放された場合、あなたの期待はどうでしたか?ポインタを変更し、ちょうど大きな割り当てられたサイズをしていないなど、より効率的な何かを行うことができ、それはコピーを避けるために、どこかのメモリをマップするために、カーネルの機能を使用することができます

    void * 
    realloc(void *old, size_t newsz) 
    { 
        size_t old_sz = internal_function_that_finds_old_size(old); 
        void *new = malloc(newsz); 
        if (new == NULL) 
         return NULL; 
        memcpy(new, old, oldsz); 
        free(old); 
        return new; 
    } 
    

    realloc

  • +2

    C11規格には(7.22.3。5):_ 'realloc'関数は、' ptr'が指し示す古いオブジェクトを解放し、 'size'で指定されたサイズを持つ新しいオブジェクトへのポインタを 返します。 ...新しいオブジェクトのメモリが に割り当てられない場合、古いオブジェクトは割り当て解除されず、その値は変更されません。 ... 'realloc'関数は、新しいオブジェクトへのポインタ(古いオブジェクトへのポインタと同じ値の を持つ可能性があります)を返します。新しいオブジェクトが に割り当てられなかった場合はnullポインタです。C99は同じことを言います。 C90やC11とは異なり、C90は割り当て解除されていた古いメモリについては明示的ではありませんでした。コード上から –

    +0

    は、I出力の下になった。(0 0x9a40008 0x9a4000c 0x9a40010 0x9a40014 0x9a40018 0x9a40020 0x9a40024 0x9a40028 0x9a4002c 0x9a40030 M = 0x9a4000c 1 0x9a40038 0x9a4003c 0x9a40040 0x9a40044 0x9a40048 0x9a4004c 0x9a40050 0x9a40054 M = 0x9a4000cのreallocは、古いメモリを解放している場合1)は、この出力のどの* m個のポインタが古いメモリ内の古いメモリロケーションと存在しているデータにアクセスすることが来ます場所 –

    +0

    @SumitNaik解放されたメモリにアクセスすると、さまざまな方法で無限に出現する*未定義の動作*が発生します。古い値を「見る」ように見えるかもしれません。ここの本当の疑問はあなたが気にする理由です。たとえあなたが解放されたメモリに何らかの形でアクセスすることができたとしても、残ったデータには "ゴミ"が保存されています。それは何も意味しない。 – AnT

    3

    reallocは同等ですしかし、一般的にはreallocは、これが最悪の場合の動作であるため、上記のように扱う必要があります。

    今、あなたのプログラムについて言えば、無効なポインタでメモリに触れていると、何かが起こる可能性があります。 mは、reallocの呼び出し後に有効なポインタであることを停止します。誰でもあなたの使用を止めさせるわけではなく、あなたがそれを使用すればあなたのプログラムはもはや分かりやすいことを保証されなくなります。

    +1

    新しく青で強調表示された「新」! –

    +0

    @MatteoItalia heh。私は、SOの構文強調表示がC/C++の神話を信じていると思います。 – Art

    関連する問題