ポインターのデフォルト値はありません。ポインターは、現在保存されているものを指します。初期化していないので、行
newCell.subcells[i] = ...
メモリの不確実な部分に効果的にアクセスします。subcells[i] は次と同等であることを思い出してください
*(newCell.subcells + i)
左側にガベージが含まれている場合i
、ガベージ値に追加して、その不明な場所でメモリにアクセスすることになります。あなたが正しく言ったように、有効なメモリ領域を指すようにポインターを初期化する必要があります。
newCell.subcells = malloc(bytecount)
どの行の後、そのバイト数にアクセスできますか。他のメモリ ソースに関しては、さまざまな種類のストレージがあり、それぞれに用途があります。得られる種類は、所有しているオブジェクトの種類と、コンパイラに使用するように指示するストレージ クラスによって異なります。
malloc
型のないオブジェクトへのポインターを返します。メモリのその領域を指すポインターを作成すると、オブジェクトの型は、ポイントされたオブジェクト型の型になります。メモリはどの値にも初期化されず、通常はアクセスが遅くなります。得られたオブジェクトを と呼びallocated objects
ます。
- オブジェクトをグローバルに配置できます。それらのメモリはゼロに初期化されます。ポイントの場合は NULL ポインターを取得し、フロートの場合は適切なゼロも取得します。適切な初期値に依存できます。
- ローカル変数があり、
static
ストレージ クラス指定子を使用している場合、グローバル オブジェクトと同じ初期値ルールが適用されます。メモリは通常、グローバル オブジェクトと同じ方法で割り当てられますが、それは決して必要ではありません。
- ストレージ クラス指定子のない、または を使用したローカル変数がある場合
auto
、変数はスタックに割り当てられます (C でそのように定義されていなくても、これはもちろんコンパイラが実際に行うことです)。そのアドレスを取得できます。その場合、コンパイラーはもちろんレジスターに入れるなどの最適化を省略しなければなりません。
- ストレージ クラス指定子
register
で使用されるローカル変数は、特別なストレージを持つものとしてマークされます。その結果、そのアドレスを取得できなくなります。register
最近のコンパイラでは、洗練されたオプティマイザにより、通常はもう使用する必要はありません。ただし、あなたが本当に専門家であれば、それを使用するとある程度のパフォーマンスが得られるかもしれません.
オブジェクトには、さまざまな初期化ルールを示すために使用できる保存期間が関連付けられています (正式には、少なくともオブジェクトが存続する期間のみを定義します)。auto
および で宣言されたオブジェクトは、register
自動保存期間を持ち、初期化されません。何らかの値を含める場合は、明示的に初期化する必要があります。そうしないと、有効期間が始まる前にコンパイラがスタックに残したものがすべて含まれます。によって割り当てられたオブジェクトmalloc
(またはそのファミリの別の関数などcalloc
) には、ストレージ期間が割り当てられています。ストレージも初期化されません。例外は、使用する場合です。calloc
この場合、メモリはゼロに初期化されます (「実際の」ゼロ。つまり、NULL ポインター表現に関係なく、すべてのバイトが 0x00 になります)。static
およびグローバル変数で宣言されたオブジェクトには、静的ストレージ期間があります。それらのストレージは、それぞれのタイプに適したゼロに初期化されます。オブジェクトに型があってはならないことに注意してください。ただし、型のないオブジェクトを取得する唯一の方法は、割り当てられたストレージを使用することです。(C のオブジェクトは「ストレージの領域」です)。
それで、何が何ですか?これが固定コードです。メモリのブロックを割り当てたら、割り当てたアイテムの数を取り戻すことはできないため、そのカウントを常にどこかに保存することをお勧めします。dim
カウントを格納する構造体に変数を導入しました。
Cell makeCell(int dim) {
/* automatic storage duration => need to init manually */
Cell newCell;
/* note that in case dim is zero, we can either get NULL or a
* unique non-null value back from malloc. This depends on the
* implementation. */
newCell.subcells = malloc(dim * sizeof(*newCell.subcells));
newCell.dim = dim;
/* the following can be used as a check for an out-of-memory
* situation:
* if(newCell.subcells == NULL && dim > 0) ... */
for(int i = 0; i < dim; i++) {
newCell.subcells[i] = makeCell(dim - 1);
}
return newCell;
}
これで、dim=2 の場合は次のようになります。
Cell {
subcells => {
Cell {
subcells => {
Cell { subcells => {}, dim = 0 }
},
dim = 1
},
Cell {
subcells => {
Cell { subcells => {}, dim = 0 }
},
dim = 1
}
},
dim = 2
}
C では、関数の戻り値がオブジェクトである必要はないことに注意してください。ストレージが存在する必要はまったくありません。したがって、変更することはできません。たとえば、次のことはできません。
makeCells(0).dim++
割り当てられたメモリを再度解放する「解放機能」が必要になります。割り当てられたオブジェクトのストレージは自動的に解放されないためです。ツリー内のすべてのポインターfree
に対してそのメモリを解放するために呼び出す必要があります。subcells
あなたがそれを書き上げるための練習として残されています:)