私はいつもJavaでプログラミングしてきたので、おそらくこれについて混乱しているのでしょう。
Java私はポインタを宣言します:
_int[] array
_
初期化するか、メモリを割り当てます。
_int[] array = {0,1,0}
int[] array = new int[3]
_
さて、Cでは、それはすべてとても混乱しています。最初は、宣言するのと同じくらい簡単だと思いました。
_int array[]
_
それを初期化するか、メモリを割り当てます:
_int array[] = {0,1,0}
int array[] = malloc(3*sizeof(int))
int array[] = calloc(3,sizeof(int))
_
間違っていない限り、上記のすべては同等のJava-Cです。
その後、今日、次のコードを見つけました。
_pthread_t tid[MAX_OPS];
_
以下のいくつかの行、初期化の種類なし...
_pthread_create(&tid[0],NULL,mou_usuari,(void *) 0);
_
驚いたことに(少なくとも私には)、コードは機能します!少なくともJavaでは、それはNice "NullPointerException"を返します!
だから、順番に:
Java-Cのすべての「翻訳」は正しいですか?
なぜそのコードが機能するのですか?
malloc(n*sizeof(int))
とcalloc(n,sizeof(int))
の使用に違いはありますか?
前もって感謝します
配列にメモリを割り当てることはできません。配列の寿命全体にわたって、配列のサイズは固定されています。配列をnullにすることはできません。配列はポインターではありません。
malloc
は、プログラム用に予約されているメモリブロックのアドレスを返します。それを(メモリブロックである)配列に「割り当てる」ことはできませんが、このメモリブロックのアドレスをポインタに保存できます。幸いなことに、配列サブスクリプションはポインタを介して定義されます。 、例えば.
int *ptr = malloc(5 * sizeof *ptr);
ptr[2] = 5; // access the third element "of ptr"
free(ptr); // always free at the end
サイズなしで配列を宣言する場合(つまり、array[]
)、単に配列のサイズが初期化リストから決定されることを意味します。あれは
int array[] = {1, 2, 3, 4, 5}; // is equal to
int array[5] = {1, 2, 3, 4, 5};
サイズや初期化子なしで配列を宣言しようとするとエラーになります。
コード pthread_t tid[MAX_OPS];
は、tid
という名前の配列pthread_t
およびサイズMAX_OPS
。
配列に自動ストレージがある場合(つまり、宣言が関数内にあり、静的ではなく、グローバルではない場合)、配列要素のそれぞれに不定値があります(そのような値を読み取ろうとする未定義の動作が発生します)。幸いなことに、関数呼び出しは、配列の最初の要素のアドレスを最初のパラメーターとして受け取り、おそらく関数内でそれ(要素)を初期化するだけです。
calloc
とmalloc
の違いは、calloc
が返すメモリブロックがゼロに初期化されることです。あれは;
int *ptr = calloc(5, sizeof *ptr);
// is somewhat equal to
int *ptr = malloc(5 * sizeof *ptr);
memset(ptr, 0, 5 * sizeof *ptr);
の違い
int *ptr = malloc(5 * sizeof *ptr);
// and
int array[5];
array
には自動ストレージがあり(スタックに格納され)、スコープ外になった後に「解放」されます。ただし、ptr
(ヒープに格納される)は動的に割り当てられ、プログラマがfree
dにする必要があります。
3つの非常に基本的で厳格な(そして誤解を招く!)Cトピックが欠落しています。
int array[] = malloc(3*sizeof(int));
と書くと、コンパイルエラーが発生します(次のようなものです) 'identifier':配列の初期化には中括弧が必要です)。
これは、配列を宣言すると静的な初期化のみが許可されることを意味します。
int array[] = {1,2,3};
_は、スタック上で3つの連続した整数を予約します。int array[3] = {1,2,3};
_これは前のものと同じです。int array[3];
_は、スタック上で3つの連続した整数を予約しますが、それらを初期化しません(内容はランダムなゴミになります)int array[4] = {1,2,3};
_初期化子リストがすべての要素を初期化しない場合、残りは0に設定されます(C99§6.7.8/ 19):この場合、1,2,3,0を取得しますこれらのすべての場合、allocating new memoryではなく、すでにスタックにコミットされているメモリを使用していることに注意してください。問題が発生するのは、スタックがいっぱいの場合のみです(推測すると、スタックオーバーフロー)。このため、_int array[];
_の宣言は間違っており、意味がありません。
malloc
を使用するには、ポインターを宣言する必要があります:_int* array
_。
int* array = malloc(3*sizeof(int));
を記述するとき、実際には3つの操作を実行しています。
int* array
_は、スタック(メモリアドレスを含む整数変数)にポインターを予約するようコンパイラーに指示しますmalloc(3*sizeof(int))
はヒープ3連続整数に割り当て、最初の整数を返します=
_は、戻り値(割り当てた最初の整数のアドレス)をポインター変数にコピーしますだから、あなたの質問に戻るには:
_pthread_t tid[MAX_OPS];
_
はスタック上の配列であるため、割り当てる必要はありません(_MAX_OPS
_が16の場合、16 pthread_tを収めるために必要な連続したバイト数をスタック上で予約します)。このメモリのコンテンツはガベージになります(スタック変数はゼロに初期化されません)が、_pthread_create
_はその最初のパラメーター(_pthread_t
_変数へのポインター)に値を返し、以前のコンテンツを無視します。コードは問題ありません。
Cは、静的メモリ割り当てと動的メモリ割り当てを提供します。スタックから、またはコンパイラが管理する実行可能メモリに配列を割り当てることができます。これは、Javaでスタックにintを割り当てたり、ヒープにIntegerを割り当てたりする方法とまったく同じです。 Cの配列は、他のスタック変数とまったく同じです。範囲外になるなど。
{}とmalloc/callocの主な違いは、{}配列が静的に割り当てられ(解放する必要がない)、自動的に初期化されるのに対して、malloc/calloc配列は明示的に解放する必要があり、明示的に初期化する必要があることです。しかし、もちろん、malloc/calloc配列は範囲外にならず、(場合によっては)realloc()することができます。
2-この配列宣言は静的です:
pthread_t tid[MAX_OPS];
動的割り当ての代わりに、メモリブロックを割り当てる必要はありません。
pthread_t *tid = (pthread_t *)malloc( MAX_OPS * sizeof(pthread_t) );
メモリを解放することを忘れないでください:
free(tid);
3-mallocとcallocの違いは、callocが配列にメモリブロックを割り当て、すべてのビットを0に初期化することです。