13

次の場合:

int* array = malloc(10 * sizeof(int));

そしてそれらは私がreallocを使用します:

array = realloc(array, 5 * sizeof(int));

2行目(そしてそれだけ)で、それは返すことができNULLますか?

4

7 に答える 7

13

はい、できます。には実装の保証はなくrealloc()、縮小しても別のポインターを返す可能性があります。

たとえば、特定の実装でオブジェクト サイズごとに異なるプールを使用する場合、realloc()実際には、小さいオブジェクト用にプール内の新しいブロックを割り当て、大きいオブジェクト用にプール内のブロックを解放することができます。したがって、小さいオブジェクトのプールがいっぱいになると、失敗して が返されNULLます。


または、単にブロックを移動した方がよいと判断する場合もあります。

次のプログラムを使用して、glibc で実際に割り当てられたメモリのサイズを取得しました。

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

int main()                                                                   
{                                                                            
    int n;                                                                   

    for (n = 0; n <= 10; ++n)                                                
    {                                                                        
        void* array = malloc(n * sizeof(int));                               
        size_t* a2 = (size_t*) array;                                        

        printf("%d -> %zu\n", n, a2[-1]);                                    
    }                                                                        
}

n <= 6 の場合は 32 バイトが割り当てられ、7 ~ 10 の場合は 48 バイトが割り当てられます。

したがって、 に縮小int[10]するint[5]と、割り当てられたサイズは 48 から 32 に縮小され、実質的に 16 の空きバイトが与えられます。(前述のとおり) 32 バイト未満のものは割り当てられないため、これらの 16 バイトは失われます。

ブロックを別の場所に移動すると、48 バイト全体が解放され、実際にそこに何かを入れることができます。もちろん、これは単なる SF の話であり、実際の実装ではありません ;)。


C99 標準からの最も関連性の高い引用 ( 7.20.3.4 The reallocfunction ):

戻り値

4realloc関数は、新しいオブジェクトへのポインタ (古いオブジェクトへのポインタと同じ値を持つ可能性があります) を返すか、新しいオブジェクトを割り当てることができなかった場合は null ポインタを返します。

ここでは「5月」がキーワードです。それが起こり得る特定の状況については言及されていないため、一見明白に聞こえるとしても、それらのいずれにも依存することはできません.


ちなみに、やや非推奨と考えてよいと思います。realloc()C++ を見てみると、新しいメモリ割り当てインターフェイス ( new/deleteおよびアロケータ) は、そのようなことさえサポートしていません。彼らは常にあなたが新しいブロックを割り当てることを期待しています。しかし、それは単なる緩いコメントです。

于 2012-08-25T20:20:52.103 に答える
6

他の回答はすでに質問を釘付けにしていますが、realloc呼び出しが「トリミング」であることがわかっていると仮定すると、次のようにラップできます。

void *safe_trim(void *p, size_t n) {
    void *p2 = realloc(p, n);
    return p2 ? p2 : p;
}

戻り値は常に size のオブジェクトを指しますn

いずれにせよ、 の実装はreallocオブジェクトのサイズを知っているため、「トリミング」であると判断できるため、上記のロジックを内部で実行しないことは、実装の品質の観点から病的に悪いでしょう。ただし、reallocはこれを行う必要がないため、上記のラッパーを使用するか、 を呼び出すときに類似のインライン ロジックを使用して、自分で行う必要がありますrealloc

于 2012-08-25T20:51:19.490 に答える
3

realloc言語 (およびライブラリ) の仕様は、「トリミング」がポインター値を保持することを保証しないのと同様に、そのような保証を行いません。

実装reallocは、最も「原始的な」方法で実装することを決定する場合があります。つまりmalloc、新しいメモリ ブロックに対して無条件を実行し、データをコピーしてfree、古いブロックを -ing することです。明らかに、このような実装は、メモリ不足の状況では失敗する可能性があります。

于 2012-08-25T20:19:22.470 に答える
3

それを頼りにしないでください。標準にはそのような規定はありません。「または、新しいオブジェクトを割り当てることができなかった場合は null ポインター」を示​​すだけです。

そのような実装を見つけるのは難しいでしょうが、標準によれば、それでも準拠しています。

于 2012-08-25T20:19:28.160 に答える
2

あなたが説明したシナリオでは、理論的に失敗する可能性があると思います。

ヒープの実装によっては、既存の割り当てブロックをトリミングできない場合があります。代わりに、最初に小さなブロックが割り当てられ、次に古いブロックからデータがコピーされ、その後解放されます。

たとえば、これはバケット ヒープ戦略 (tcmalloc などの一部の一般的なヒープで使用される) の場合に当てはまります。

于 2012-08-25T20:21:51.250 に答える
-1

reallocは既存のメモリの縮小に失敗しないため、 は返されませんNULLNULL拡張中に失敗した場合にのみ戻ることができます。

ただし、一部のアーキテクチャでは縮小が失敗するrealloc可能性があり、小さいサイズのメモリを個別に割り当て、古いメモリを解放して断片化を回避するなど、別の方法で実装できます。その場合、メモリを縮小すると NULL が返される可能性があります。しかし、その実装は非常にまれです。

NULLただし、メモリを縮小した後もチェックを続けるために、より安全な側にいる方がよいでしょう。

于 2012-08-25T20:16:28.963 に答える