行うことの違いは何ですか:
ptr = (char **) malloc (MAXELEMS * sizeof(char *));
または:
ptr = (char **) calloc (MAXELEMS, sizeof(char*));
mallocよりもcallocを使用したり、その逆を使用したりするのはどのような場合に適していますか?
ptr = calloc(MAXELEMS, sizeof(*ptr));
行うことの違いは何ですか:
ptr = (char **) malloc (MAXELEMS * sizeof(char *));
または:
ptr = (char **) calloc (MAXELEMS, sizeof(char*));
mallocよりもcallocを使用したり、その逆を使用したりするのはどのような場合に適していますか?
ptr = calloc(MAXELEMS, sizeof(*ptr));
回答:
calloc()
malloc()
初期化されていないメモリを残しながら、初期化されていないバッファを提供します。
大規模な割り当ての場合、calloc
主流のOS でのほとんどの実装は、OSから既知のゼロ化されたページを(POSIX mmap(MAP_ANONYMOUS)
またはWindows などを介してVirtualAlloc
)取得するため、ユーザー空間に書き込む必要はありません。これが通常の方法でmalloc
OSからより多くのページを取得する方法です。calloc
OSの保証を利用するだけです。
つまり、calloc
メモリは引き続き「クリーン」で遅延割り当てされ、システム全体で共有されるゼロの物理ページにコピーオンライトがマッピングされます。(仮想メモリを備えたシステムを想定しています。)
一部のコンパイラでは、malloc + memset(0)をcallocに最適化することもできますが、メモリをとして読み取る場合は、callocを明示的に使用する必要があります0
。
書き込む前にメモリを読み取る予定がない場合はmalloc
、OSから新しいページを取得するのではなく、内部の空きリストからダーティメモリを(潜在的に)取得できるように使用します。(または、小さな割り当てのために空きリストのメモリブロックをゼロにする代わりに)。
の埋め込み実装でcalloc
はcalloc
、OSがない場合や、プロセス間の情報リークを防ぐためにページをゼロにするファンシーなマルチユーザーOSではない場合、メモリがゼロになる可能性があります。
組み込みLinuxでは、mallocは可能ですmmap(MAP_UNINITIALIZED|MAP_ANONYMOUS)
。これは、マルチユーザーシステムでは安全でないため、一部の組み込みカーネルでのみ有効です。
calloc
OSはそれをスピードアップするためにいくつかのトリックを行うことができるので、必ずしもより高価ではありません。FreeBSDがアイドルCPU時間を取得すると、それを使用して、メモリの割り当て解除されたブロックを回避してゼロに設定し、ブロックにマークを付ける単純なプロセスを実行し、プロセスにフラグを付けます。したがって、を実行するとcalloc
、最初にそのような事前ゼロ化されたブロックの1つを見つけようとし、それをユーザーに渡します-ほとんどの場合、ブロックを見つけます。
あまり知られていない違いは、Linuxのような楽観的なメモリ割り当てを備えたオペレーティングシステムでは、によって返されるポインタはmalloc
、プログラムが実際に触れるまで、実際のメモリによってバックアップされないことです。
calloc
確かにメモリに触れます(メモリにゼロを書き込みます)。したがって、OSが割り当てを実際のRAM(またはスワップ)でバックアップしていることを確認できます。これがmallocよりも遅い理由でもあります(ゼロにする必要があるだけでなく、OSは他のプロセスをスワップアウトして適切なメモリ領域を見つける必要もあります)。
mallocの動作についての詳細は、たとえばこのSOの質問を参照してください
calloc
ゼロを書き込む必要はありません。割り当てられたブロックの大部分がオペレーティングシステムによって提供される新しいゼロページで構成されている場合、それらはそのままにされる可能性があります。もちろん、これはcalloc
、上の汎用ライブラリ関数ではなく、オペレーティングシステムに合わせて調整する必要がありmalloc
ます。または、実装者はcalloc
各単語をゼロと比較する前に、ゼロと比較することができます。これは時間の節約にはなりませんが、新しいページを汚すことはありません。
dlmalloc
ような実装ではmemset
、mmap
新しい匿名ページ(または同等のページ)を使用してチャンクを取得した場合、はスキップされます。通常、この種の割り当ては、256kから始まる大きなチャンクに使用されます。私は自分のものを除いてゼロを書く前にゼロと比較する実装を知りません。
omalloc
もスキップしmemset
ます。calloc
これまで、アプリケーション(ページキャッシュ)でまだ使用されていないページに触れる必要はありません。ただし、非常に原始的なcalloc
実装は異なります。
しばしば見落とされがちな利点の1つcalloc
は、整数のオーバーフローの脆弱性からユーザーを保護するのに役立つ(その準拠実装)ことです。比較:
size_t count = get_int32(file);
struct foo *bar = malloc(count * sizeof *bar);
対
size_t count = get_int32(file);
struct foo *bar = calloc(count, sizeof *bar);
前者count
は、より大きい場合、小さな割り当てとその後のバッファオーバーフローを引き起こす可能性がありSIZE_MAX/sizeof *bar
ます。この場合、大きなオブジェクトは作成できないため、後者は自動的に失敗します。
もちろん、オーバーフローの可能性を単に無視する非準拠の実装に注意する必要があるかもしれません...これが対象のプラットフォームで懸念事項である場合は、とにかく手動でオーバーフローをテストする必要があります。
char
は、オーバーフローではなく、結果をchar
オブジェクトに割り当てる際の実装定義の変換です。
size_t
64ビットなので問題ない」である場合、それはセキュリティバグにつながる欠陥のある考え方です。size_t
はサイズを表す抽象型であり、32ビットの数値とaの任意の積size_t
(注:sizeof *bar
64ビットのC実装では原則として2 ^ 32より大きい可能性があります!)がに収まると考える理由はありませんsize_t
。
ドキュメンテーションは、callocをmallocのように見せます。これはメモリをゼロ初期化するだけです。これは主な違いではありません!callocのアイデアは、メモリ割り当てのコピーオンライトセマンティクスを抽象化することです。callocでメモリを割り当てると、メモリはすべてゼロに初期化された同じ物理ページにマップされます。割り当てられたメモリのいずれかのページが物理ページに書き込まれると、割り当てられます。これは、巨大なハッシュテーブルを作成するためによく使用されます。たとえば、空のハッシュの部分は、追加のメモリ(ページ)によってサポートされないためです。それらは喜んで単一のゼロで初期化されたページを指しており、プロセス間で共有することもできます。
仮想アドレスへの書き込みはページにマップされ、そのページがゼロページである場合、別の物理ページが割り当てられ、ゼロページがそこにコピーされ、制御フローがクライアントプロセスに返されます。これは、メモリマップファイル、仮想メモリなどが機能するのと同じように機能します。ページングを使用します。
このトピックに関する1つの最適化ストーリーを次に示します。http: //blogs.fau.de/hager/2007/05/08/benchmarking-fun-with-calloc-and-zero-pages/
割り当てられるメモリブロックのサイズに違いはありません。calloc
物理的なすべてゼロのビットパターンでメモリブロックを埋めるだけです。実際には、多くの場合に割り当てられたメモリブロックに位置するオブジェクトが想定されcalloc
、それらがリテラルで初期化されたかのようinitilial価値を持つ0
の値持つ必要があり、すなわち整数0
の値-浮動小数点変数、0.0
ポインタを-適切なヌル・ポインタ値を、 等々。
ただし、詳細な観点から見ると、calloc
(およびmemset(..., 0, ...)
)は、タイプのオブジェクトを(ゼロで)適切に初期化することのみが保証されていますunsigned char
。それ以外はすべて正しく初期化されることが保証されておらず、いわゆるトラップ表現が含まれている可能性があり、これにより未定義の動作が発生します。つまり、unsigned char
前述のすべて0のビット以外のタイプのpattermは、不正な値、トラップ表現を表す可能性があります。
その後、Technical Corrigenda to C99標準の1つで、動作はすべての整数型に対して定義されました(これは理にかなっています)。つまり、正式には、現在のC言語では、整数型のみをcalloc
(およびmemset(..., 0, ...)
)で初期化できます。C言語の観点から、それを使用して他の一般的なケースを初期化すると、未定義の動作が発生します。
実際にcalloc
は、私たち全員が知っているように動作します:)が、それを使用するかどうか(上記を考慮)はあなた次第です。私は個人的にはそれを完全に避け、malloc
代わりに使用して自分で初期化することを好みます。
最後に、もう1つの重要な詳細は、要素のサイズに要素の数を掛けてcalloc
、最終的なブロックサイズを内部で計算するために必要なことです。その際、calloc
算術オーバーフローの可能性を監視する必要があります。要求されたブロックサイズを正しく計算できない場合は、割り当てが失敗します(nullポインター)。その間、malloc
バージョンはオーバーフローを監視しようとしません。オーバーフローが発生した場合に備えて、「予測不可能な」量のメモリを割り当てます。
memset(p, v, n * sizeof type);
ため、問題になるようn * sizeof type
です。for(i=0;i<n;i++) p[i]=v;
堅牢なコードにはループを使用する必要があると思います。
n
エレメントのサイズを有する場合の要素が存在しsizeof type
、その後、n*sizeof type
任意のオブジェクトの最大サイズ未満でなければならないので、オーバーフローすることはできませんSIZE_MAX
。
SIZE_MAX
が、ここには配列はありません。から返されたポインタは、calloc()
を超えた割り当てメモリをポイントできSIZE_MAX
ます。多くの実装では、2つの引数の積に制限を行うcalloc()
にはSIZE_MAX
、まだC仕様では、その制限を課しません。
Geoc Hagerのブログのcalloc()とゼロページを使ったベンチマークの楽しみの記事から
calloc()を使用してメモリを割り当てる場合、要求されたメモリの量はすぐには割り当てられません。代わりに、メモリブロックに属するすべてのページは、いくつかのMMUマジック(以下のリンク)によってすべてゼロを含む単一のページに接続されます。そのようなページが読み取られるだけの場合(これは、ベンチマークの元のバージョンの配列b、c、dに当てはまりました)、データは単一のゼロページから提供されます。もちろん、これはキャッシュに適合します。メモリにバインドされたループカーネルについては、これで十分です。ページが(どのように)書き込まれた場合、障害が発生し、「実際の」ページがマップされ、ゼロページがメモリにコピーされます。これはコピーオンライトと呼ばれ、よく知られている最適化アプローチです(C ++の講義で何度も教えました)。その後、
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を使用した方がよい場合があります。
calloc()
よりも遅くなる2番目のポイントもありmalloc()
ます。malloc()はコンパイル時定数を持つことが多いが、calloc()
一般的な乗算(size_t
64ビットの場合、非常にコストのかかる64ビット* 64ビット= 64ビット演算でも)を使用するために必要です。
struct foo { char a,b,c; };
。 ed領域全体を常にクリアする場合は、常に+ calloc
よりも優れています。 size *要素のintオーバーフローも注意深く効率的にチェックします。malloc
memset
malloc
calloc
違い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ブロックのメモリを割り当て、すべてをゼロに初期化する場合、
int *ptr = (int *) calloc(10, (sizeof(int)));
類似点:
両方ともmalloc()
、calloc()
型キャストされていない場合、デフォルトでvoid *を返します。
2つの違いがあります。
まず、引数の数です。malloc()
1つの引数(バイト単位で必要なメモリ)を取りますが、calloc()
2つの引数が必要です。
第二に、割り当てられたメモリをゼロに初期化するmalloc()
一方でcalloc()
、割り当てられたメモリを初期化しません。
calloc()
メモリ領域を割り当てます。長さはそのパラメータの積になります。calloc
ゼロでメモリを埋め、最初のバイトへのポインタを返します。十分なスペースが見つからない場合は、NULL
ポインターを返します。構文:ptr_var=(cast_type *)calloc(no_of_blocks , size_of_each_block);
ieptr_var=(type *)calloc(n,s);
malloc()
REQUSTED SIZEの単一メモリブロックを割り当て、最初のバイトへのポインタを返します。必要なメモリ量を見つけられなかった場合は、nullポインタを返します。構文:ながら機能は、バイト数が割り当てることである一つの引数を取る関数は、要素の数であり、いずれか二つの引数をとり、他のバイトの数は、これらの要素のそれぞれに割り当てること。また、割り当てられたスペースをゼロに初期化しますが、初期化しません。ptr_var=(cast_type *)malloc(Size_in_bytes);
malloc()
calloc()
calloc()
malloc()
calloc()
中で宣言された関数<stdlib.h>
ヘッダーが勝る利点をいくつか提供していますmalloc()
機能。
malloc()
およびcalloc()
は、動的メモリ割り当てを可能にするC標準ライブラリの関数です。つまり、どちらも実行時にメモリ割り当てを可能にします。
プロトタイプは次のとおりです。
void *malloc( size_t n);
void *calloc( size_t n, size_t t)
2つの間に主に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));
and 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()
代わりに使用してください。
まだ言及されていない違い:サイズ制限
void *malloc(size_t size)
までしか割り当てることができませんSIZE_MAX
。
void *calloc(size_t nmemb, size_t size);
約割り当てることができます SIZE_MAX*SIZE_MAX
ます。
この機能は、リニアアドレッシングを備えた多くのプラットフォームではあまり使用されません。このようなシステムはで制限さcalloc()
れnmemb * size <= SIZE_MAX
ます。
512バイトのタイプが呼び出されdisk_sector
、コードが多くのセクターを使用したいとします。ここでは、コードは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が与えられたムーアの法則これは、特定のメモリモデルと2030年について発生される疑いがある、SIZE_MAX == 4294967295
ギガバイトの100にし、メモリプール。
size_t
32ビットよりも大きくなります。唯一の問題は、より小さな割り当てへのポインタを返すのではなくcalloc
、積が超過する値を使用してSIZE_MAX
ゼロを生成することに依存できるかどうかです。
calloc()
割り当てを超えることが許可されていSIZE_MAX
ます。これは過去に16ビットで発生しましたが、size_t
メモリが安くなり続けているため、一般的ではないにしても、今後も発生しない理由はありません。
SIZE_MAX
。確かに、そのような割り当てが成功する可能性がある状況が存在する必要はありません。そのような割り当てを処理できない実装が返す必要があることを義務付けることによる特別な利点があるかどうかはわかりませんNULL
(特に、一部の実装でmalloc
はまだコミットされていないスペースへのリターンポインターがあり、コードが実際に使用しようとすると利用できない場合があるため)それ)。
size_t
れないのはuint64_t
なぜですか?
ブロック数:
malloc()は、要求されたメモリの単一ブロックを割り当てます。
calloc()は要求されたメモリの複数のブロックを割り当てます
初期化:
malloc()-割り当てられたメモリをクリアして初期化しません。
calloc()-割り当てられたメモリをゼロで初期化します。
速度:
malloc()は高速です。
calloc()はmalloc()より低速です。
引数と構文:
malloc()は1つの引数を取ります:
バイト
calloc()は2つの引数を取ります。
長さ
void *malloc(size_t bytes);
void *calloc(size_t length, size_t bytes);
メモリ割り当ての方法:
malloc関数は、使用可能なヒープから目的の「サイズ」のメモリを割り当てます。
calloc関数は、「num * size」に等しいサイズのメモリを割り当てます。
名前の意味:
名前mallocは「メモリ割り当て」を意味します。
名前callocは「連続割り当て」を意味します。
malloc
家族の結果をキャストしません