5

私は次のことを知っています:

  • malloc
  • calloc
  • realloc

これらの違いは何ですか?なぜmallocはほとんど排他的に使用されているように見えるのですか?コンパイラ間に動作の違いはありますか?

4

5 に答える 5

12

mallocメモリを割り当てます。メモリの内容はそのままになります(以前にあったものでいっぱいになります)。

callocメモリを割り当て、その内容をすべてゼロに設定します。

realloc既存の割り当てられたメモリブロックのサイズを変更するか、既存のメモリブロックの内容を要求されたサイズの新しく割り当てられたブロックにコピーしてから、古いブロックの割り当てを解除します。

明らかに、reallocこれは特殊な状況です。サイズを変更する(またはコピーして割り当てを解除する)ための古いメモリブロックがない場合は、それを使用する理由はありません。malloc代わりに通常使用される理由callocは、メモリをすべてゼロに設定するための実行時コストがあり、メモリを有用なデータですぐにいっぱいにすることを計画している場合(一般的なように)、ゼロにする意味がないためです。最初にそれを出します。

これらの関数はすべて標準であり、コンパイラ間で確実に動作します。

于 2010-09-24T22:03:38.550 に答える
3

あなたが言及しているものに加えて(いくつかは拡張機能です):

  • スタック上の変数も動的に割り当てられます。再帰は、それを割り当てて使用する方法です。
  • C99には可変長配列があります(BlueRajaが言及しているように)。
  • 一部のシステムallocaでは、スタックフレームに可変長のチャンクを割り当てることができる呼び出しもあります。
  • POSIXには、またはとの組み合わせを使用したメモリセグメントとファイルのマッピングがありshm_openます。openmmap
  • SysVIPCにはshmgetetcコールがあります
于 2010-09-24T22:28:30.820 に答える
2

言及されていないメモリを割り当てる1つの方法はalloca(size_t size)、現在のスタックフレームにサイズバイトのメモリを予約し、スタックフレームを離れるときにメモリを自動的に解放する方法です。

于 2010-09-24T23:53:39.760 に答える
1

callocは、次のようなものとして実装されている可能性があります。

void * calloc(size_t nmemb, size_t size) {
      size_t len = nmemb * size);
      void * ptr = malloc(len);
      if (ptr) {
          return memset(ptr, 0, len);
      }
      return ptr;
}

つまり、mallocの前に乗算を追加し、後にクリアを追加するだけです。

mallocは次のように実装できます(ただし、おそらく実装されていません)。

void * malloc(size_t size) {
      return realloc(NULL, size);
}

reallocに前のポインターとしてNULLポインターを渡すことができますが、mallocはすべてのmallocの速度を低下させ、reallocはおそらくmallocを使用するため、そのように実装されていない可能性があります。

reallocについて知っておくべき主なことは、ヒープ割り当てルーチンのいずれかが返したメモリブロックの実際のサイズを判別し、ブロックがすでに十分に大きいかどうか、または場合によってはそれが最善であるかどうかを確認できることです。ブロックを縮小または移動します。

void realloc(void * ptr, size_t size) {
    size_t alen = MALLOC_LENGTH_OF(ptr); // this just stands for some method of determining
                                     // the size of the block that was allocated, and could
                                     // be looking it up in a table or looking at a place
                                     // several bytes before the pointer, or some other
                                     // implementation specific thing
    if (0 == size) {
       free(ptr);
       return NULL;
    }
    if (alen >= size) {
        return ptr; // big enough, and not worrying about it being too big
    }
    void new_ptr = malloc(size); // since I said that malloc most likely isn't
                                // implemented using realloc using malloc here is ok
    if (new_ptr && ptr) {
       memcpy(new_ptr, ptr, alen);
    }
    free(ptr);
    return new_ptr;
}

Mallocは最も単純なため、より多く使用されます。多くの場合、プログラマーは割り当てを十分に大きくして、reallocを使用してサイズを変更することを心配する必要がなく、メモリをクリアする必要がないことがよくあります。

ライブラリごとに異なる動作があり、プログラムを他のバージョンとリンクして、この異なる動作を(通常はコンパイラを変更せずに)取得することもできます。

一部のmallocライブラリは、デバッグおよびエラー検出用です。他の人はより良いパフォーマンスを提供するかもしれません。いくつかは、同時に複数の異なるスレッドにメモリを割り当てるように最適化されており、割り当てまたは解放を実行するために異なるスレッドがヒープ全体をロックダウンする必要がないようにします。

ただし、これらはすべて、アプリケーションの観点から同じセマンティクスを提供する必要があります。

于 2010-09-24T22:27:25.157 に答える
0

malloc:ptr =(int *)malloc(10);があるとしましょう。これにより、連続する10バイトのメモリスペースが割り当てられ、最初のバイトのアドレスがポインタ変数ptrに格納されます。割り当てられたメモリにガベージ値が含まれるようになりました。
したがって、iが0から3まで変化する場合scanf( "%d"、ptr + i); 4つの連続した場所に4つの整数を格納します。ptrのアドレスは1番目の整数、ptr+1のアドレスは2番目の整数というようになります。したがって、printf( "%d"、atstrick(ptr + i)); 対応する値を出力します。変数や配列に割り当てられたメモリとは異なり、動的に割り当てられたメモリには名前が関連付けられていません。上で見たように。

calloc: 2つの違いを除いてmallocに似ています。1。宣言: ptr =(int *)calloc(5、sizeof(int)); ここでは2つの引数があります。5は割り当てられたブロック数ではなく、2番目の引数は4バイトに相当します。これはptr =(int *)malloc(5 * sizeof(int));と同等です。2. callocでは、最初に割り当てられたメモリはガベージではありませんが、0です。ヒープに十分なメモリがない場合、mallocとcallocの両方がNULLを返します。

于 2014-01-07T17:33:02.693 に答える