行うことの違いは何ですか:
ptr = (char **) malloc (MAXELEMS * sizeof(char *));
または
ptr = (char **) calloc (MAXELEMS, sizeof(char*));
Mallocよりもcallocを使用するのが賢明ですか、またはその逆です。
calloc()
はバッファをゼロで初期化しますが、malloc()
はメモリを未初期化のままにします。
編集:
メモリの消去には少し時間がかかるかもしれません。そのため、パフォーマンスが問題になる場合はおそらくmalloc()
を使用したいでしょう。メモリの初期化がより重要な場合は、calloc()
を使用してください。例えば、calloc()
はmemset()
への呼び出しを節約するかもしれません。
あまり知られていない違いは、Linuxのように楽観的なメモリ割り当てを持つオペレーティングシステムでは、プログラムが実際にそれに触れるまで、malloc
によって返されるポインタは実メモリによって裏付けられないということです。
calloc
は実際にメモリにアクセスします(それに0を書き込みます)、したがってOSは実際のRAM(またはスワップ)で割り当てを後退させているはずです。これがmallocより遅い理由でもあります(ゼロにする必要があるだけでなく、OSは他のプロセスをスワップアウトして適切なメモリ領域を見つける必要があります)。
Mallocの振る舞いについてのさらなる議論は、例えば this SO question を参照してください。
見落とされがちなcalloc
の利点の1つは、(に準拠した実装)整数オーバーフローの脆弱性からあなたを守るのに役立つということです。比較しなさい:
size_t count = get_int32(file);
struct foo *bar = malloc(count * sizeof *bar);
vs.
size_t count = get_int32(file);
struct foo *bar = calloc(count, sizeof *bar);
count
がSIZE_MAX/sizeof *bar
よりも大きい場合、前者は小さな割り当てとそれに続くバッファオーバーフローをもたらすかもしれません。この場合、後者は自動的に失敗します。これは大きなオブジェクトを作成できないためです。
もちろん、単にオーバーフローの可能性を無視する、非準拠の実装を探している必要があるかもしれません。
ドキュメントはcallocをmallocのように見せています。これはメモリをゼロで初期化するだけです。これは主な違いではありません。 callocのアイデアは、メモリ割り当てのためのコピーオンライトセマンティクスを抽象化することです。 callocでメモリを割り当てると、すべてゼロに初期化された同じ物理ページにマップされます。割り当てられたメモリのいずれかのページが物理ページに書き込まれると、割り当てられます。これは、巨大なハッシュテーブルを作成するためによく使用されます。たとえば、ハッシュの空の部分は余分なメモリ(ページ)によって支えられていないためです。彼らは喜んで単一のゼロで初期化されたページを指し示します、そしてそれはプロセス間でさえ共有することができます。
仮想アドレスへの書き込みはすべてページにマップされ、そのページがゼロページで、別の物理ページが割り当てられ、そこにゼロページがコピーされ、制御フローがクライアントプロセスに返されます。これはメモリマップファイル、仮想メモリなどと同じように動作します。ページングを使用します。
これはトピックについての1つの最適化の話です: http://blogs.fau.de/hager/2007/05/08/benchmarking-fun-with-calloc-and-zero-pages/
割り当てられたメモリブロックのサイズに違いはありません。 calloc
は、物理的にすべて0のビットパターンでメモリブロックを埋めます。実際には、calloc
で割り当てられたメモリブロックにあるオブジェクトは、リテラルの0
で初期化されているかのように初期値を持ちます。つまり、整数は0
の値を持ち、浮動小数点変数 - 0.0
の値、ポインタ - 適切NULLポインタ値など.
しかし、ペディキュアの観点からは、calloc
(およびmemset(..., 0, ...)
)は、タイプunsigned char
のオブジェクトを(ゼロで)正しく初期化することのみが保証されています。それ以外のものはすべて正しく初期化されることが保証されておらず、未定義の動作を引き起こす、いわゆるtrap Representationが含まれる可能性があります。言い換えれば、unsigned char
以外の型では、前述の全ゼロビットパターンは不正な値、トラップ表現を表すかもしれません。
その後、C99規格に対するTechnical Corrigendaの1つでは、すべての整数型に対して動作が定義されました(これは意味があります)。すなわち正式には、現在のC言語ではcalloc
(とmemset(..., 0, ...)
)で初期化できるのは整数型だけです。 C言語の観点からすると、一般的な場合に他の何かを初期化するためにそれを使用すると、未定義の動作が発生します。
実際には、calloc
は、私たち全員が知っているように動作します:)しかし、(上記を考慮して)それを使いたいかどうかはあなた次第です。私は個人的にはそれを完全に避け、代わりにmalloc
を使って私自身の初期化を実行することを好みます。
最後に、もう1つの重要な詳細は、要素サイズに要素数を掛けて、最終的なブロックサイズ内部的にを計算するためにcalloc
が必要であることです。それをしている間、calloc
は算術オーバーフローの可能性に注意しなければなりません。要求されたブロックサイズを正しく計算できないと、割り当てが失敗します(nullポインタ)。その間、あなたのmalloc
バージョンはオーバーフローを監視しようとしません。オーバーフローが発生した場合に備えて、予測不可能な量のメモリを割り当てます。
記事から calloc()とゼロページで楽しいベンチマーク / Georg Hagerのブログ
Calloc()を使用してメモリを割り当てるとき、要求されたメモリ量はすぐには割り当てられません。代わりに、メモリブロックに属するすべてのページは、何らかのMMUマジックによって、すべて0を含む単一のページに接続されています(下のリンク)。そのようなページが読み取られるだけの場合(ベンチマークのオリジナルバージョンでは、配列b、c、およびdに当てはまります)、データは単一のゼロページから提供されます。メモリ境界のループカーネルではそれほど多くありません。ページが書き込まれた場合(どのように関係なく)、フォルトが発生し、「実際の」ページがマップされ、ゼロページがメモリにコピーされます。これはコピーオンライトと呼ばれ、よく知られている最適化アプローチです(私もC++の講義で何度も教えました)。その後、そのページではゼロリードのトリックは機能しなくなり、これが、おそらく冗長なinitループを挿入した後のパフォーマンスが非常に低くなった理由です。
calloc
は通常malloc+memset
から0です
特にmalloc+memset
を明示的に使用するのは、一般的に少し良いです。
ptr=malloc(sizeof(Item));
memset(ptr, 0, sizeof(Item));
sizeof(Item)
はコンパイル時にコンパイラに認識されており、ほとんどの場合コンパイラはそれをメモリをゼロにするための最良の命令に置き換えます。一方、memset
がcalloc
内で発生している場合、割り当てのパラメータサイズはcalloc
コードでコンパイルされず、実際のmemset
が呼び出されることがよくあります。 sizeof(long)
のチャンクでメモリをいっぱいにし、最後に残りのスペースをバイト単位でいっぱいにするサイクルよりも。たとえアロケータがaligned_memset
を呼ぶほど賢くても、それはやはり一般的なループになるでしょう。
注目すべき例外の1つは、非常に大きなメモリのチャンク(一部のpower_of_twoキロバイト)に対してmalloc/callocを実行している場合です。この場合、割り当てはカーネルから直接行われます。 OSカーネルは通常セキュリティ上の理由でそれらが浪費するすべてのメモリをゼロにするので、十分に賢いcallocは単にさらにゼロをゼロにしてそれを返すかもしれません。繰り返しになりますが、あなたが小さいものであるとわかっているものを単に割り当てているのであれば、malloc + memsetのパフォーマンス的な方が良いでしょう。
違い1:malloc()は通常メモリブロックを割り当て、それは初期化されたメモリセグメントです。 calloc()はメモリブロックを割り当て、すべてのメモリブロックを0に初期化します。
違い2:malloc()の構文を考えると、引数は1つだけです。以下の例を見てください。
data_type ptr =(cast_type *)malloc(sizeof(data_type)* no_of_blocks);
例:int型に10ブロックのメモリを割り当てたい場合は、
int *ptr = (int *) malloc(sizeof(int) * 10 );
Calloc()の構文を考えると、2つの引数が必要です。以下の例を見てください。
data_type ptr =(cast_type *)calloc(no_of_blocks、(sizeof(data_type)));
例:int型に10ブロックのメモリを割り当てて、そのすべてをZEROに初期化したい場合、
int *ptr = (int *) calloc(10, (sizeof(int)));
類似性:
Malloc()とcalloc()の両方とも、キャスト型でない場合、デフォルトでvoid *を返します。
2つの違いがあります。
まず、引数の数にあります。 malloc()
は1つの引数(メモリはバイト単位)を取りますが、calloc()
は2つの引数を必要とします。
次に、malloc()
は割り当てられたメモリを初期化しませんが、calloc()
は割り当てられたメモリをZEROに初期化します。
calloc()
はメモリ領域を割り当てます。長さはパラメータの積になります。 calloc
はメモリをゼロで埋め、最初のバイトへのポインタを返します。十分なスペースを見つけられなかった場合はNULL
ポインタを返します。構文:ptr_var=(cast_type *)calloc(no_of_blocks , size_of_each_block);
すなわちptr_var=(type *)calloc(n,s);
malloc()
は、REQUSTED SIZEのメモリブロックを1つ割り当て、先頭バイトへのポインタを返します。必要な量のメモリを見つけられない場合は、nullポインタを返します。構文:ptr_var=(cast_type *)malloc(Size_in_bytes);
malloc()
関数は1つの引数、つまり割り当てるバイト数を取ります。一方、calloc()
関数は2つの引数を取ります。これらの各要素に割り当てるバイト数また、calloc()
は割り当てられたスペースをゼロに初期化しますが、malloc()
は初期化しません。
<stdlib.h>
ヘッダーで宣言されているcalloc()
関数は、malloc()
関数よりも優れた点がいくつかあります。
違いはまだ言及されていません: サイズ制限
void *malloc(size_t size)
はSIZE_MAX
までしか割り当てることができません。
void *calloc(size_t nmemb, size_t size);
はSIZE_MAX*SIZE_MAX
について割り当てることができます。
この機能は、線形アドレス指定を使用する多くのプラットフォームではあまり使用されません。そのようなシステムは、calloc()
をnmemb * size <= SIZE_MAX
で制限します。
disk_sector
と呼ばれる512バイトの型を考え、コードはlot個のセクタを使いたいと考えています。ここで、コードはSIZE_MAX/sizeof disk_sector
セクターまでしか使用できません。
size_t count = SIZE_MAX/sizeof disk_sector;
disk_sector *p = malloc(count * sizeof *p);
さらに大きい割り当てを可能にする次のことを考慮してください。
size_t count = something_in_the_range(SIZE_MAX/sizeof disk_sector + 1, SIZE_MAX)
disk_sector *p = calloc(count, sizeof *p);
そのようなシステムがそのような大きな割り当てを供給できるのであれば、別の問題です。今日はほとんどしません。 SIZE_MAX
が65535だったとき、それは長年にわたって起こりました。与えられた ムーアの法則 、これはSIZE_MAX == 4294967295
を持つ特定のメモリモデルと100GBのメモリプールで2030年頃に起こると思われます。
malloc()
とcalloc()
は、動的メモリ割り当てを可能にするC標準ライブラリの関数です。つまり、どちらも実行時にメモリ割り当てを許可します。
プロトタイプは次のとおりです。
void *malloc( size_t n);
void *calloc( size_t n, size_t t)
主に2つの違いがあります。
動作:malloc()
は、初期化せずにメモリブロックを割り当てます。このブロックから内容を読み取ると、ガベージ値が発生します。一方、calloc()
はメモリブロックを割り当て、それをゼロに初期化します。そして明らかにこのブロックの内容を読むとゼロになります。
構文:malloc()
は1つの引数(割り当てられるサイズ)を取り、calloc()
は2つの引数(割り当てられるブロック数と各ブロックのサイズ)を取ります。
両方からの戻り値は、成功した場合、割り当てられたメモリブロックへのポインタです。それ以外の場合は、メモリ割り当ての失敗を示す _ null _ が返されます。
例:
int *arr;
// allocate memory for 10 integers with garbage values
arr = (int *)malloc(10 * sizeof(int));
// allocate memory for 10 integers and sets all of them to 0
arr = (int *)calloc(10, sizeof(int));
calloc()
およびmalloc()
を使用して、memset()
と同じ機能を実現できます。
// allocate memory for 10 integers with garbage values
arr= (int *)malloc(10 * sizeof(int));
// set all of them to 0
memset(arr, 0, 10 * sizeof(int));
malloc()
は高速であるためcalloc()
よりも使用することをお勧めします。値をゼロで初期化したい場合は、代わりにcalloc()
を使用してください。
ブロック数:
malloc()必要なメモリの単一ブロックを割り当てます。
calloc()要求されたメモリの複数のブロックを割り当てます
初期化:
malloc()は、割り当てられたメモリをクリアして初期化しません。
calloc()は、割り当てられたメモリをゼロで初期化します。
速度:
malloc()の速度は高速です。
calloc()の速度は比較的遅いです。
構文:
void *malloc(size_t size); // syntex for malloc() function
void *calloc(size_t num, size_t size); // syntex for calloc() function
引数:
malloc()構文を検討する場合、引数は1つだけです。
calloc()構文を検討する場合、2つの引数を取ります。
メモリ割り当ての方法::
malloc()関数は、使用可能なヒープから目的の「サイズ」のメモリを割り当てます。
calloc()関数は、「num * size」に等しいサイズのメモリを割り当てます。
名前の意味:
mallocという名前は、メモリ割り当てに起因することを意味します。
callocという名前は、連続した割り当てを意味します。