配列animals
はポインターの配列です。あるサイズのバッファの配列ではありません。したがって、
sizeof(*animals)
その配列の最初の要素のサイズを取得します。に相当
sizeof(char*)
配列にはポインターが格納されるためです。だから、読む行で
char *output[sizeof(*animals)];
1 つの配列に 4 つまたは 8 つのポインターを割り当てます (プラットフォーム上のポインターの幅によって異なります。通常は 4 または 8 です)。しかし、それはもちろん無意味です!あなたがしたかったのは、 と同じサイズのポインターの配列を作成することですanimals
。まず動物配列の合計サイズを取得してから、1 つの要素のサイズで割る必要があります。
char *output[sizeof(animals)/sizeof(*animals)];
今、それがあなたが望むものです。しかし、ポインターにはまだ不定値があります... 次に、を使用して配列を渡します*&animals
(他の場合も同じです)。どうして?直接渡れanimals
ます。そのアドレスを取得して逆参照することは、最初から何もしないことと同じです。
次に、呼び出す関数で、要素が指す文字列をanimal
不確定な宛先にコピーします (配列の要素 (ポインター) にはまだ不確定な値があることを思い出してoutput
ください。まだ値を割り当てていません!)。最初に適切な量のメモリを割り当て、要素がそれを指すようにする必要があります。
while(*animals) {
// now after this line, the pointer points to something sensible
*output = malloc(sizeof("new animal ") + strlen(*animals));
sprintf(*output, "new animal %s", *animals);
output++; // no need to dereference the result
animals++; // don't forget to increment animals too!
}
その他、上記のサイズについて
確認しなければならない重要なことが 1 つあります。サイズの計算方法です。何をするにしても、常にストリングに十分なスペースがあることを確認してください! AC 文字列は、文字と、文字列の終わりを示す終端のヌル文字で構成されます。したがって、は、 および*output
のためのスペースが含まれるように、少なくとも同じ大きさのバッファーを指す必要が"new animal "
あり*animals
ます。最初の文字は 11 文字です。2 番目は、実際に何をコピーするかによって異なります。その長さがstrlen
返されます。したがって、合計で必要です
12 + strlen(*animals)
終端の null を含むすべての文字のスペース。その番号をコードにハードコードするのは良いスタイルではありません。プレフィックスが変更される可能性があり、数を更新するのを忘れたり、1 つか 2 つの文字について数え間違えたりする可能性があります。sizeof
これが、先頭に追加したい文字列リテラルを提供するを使用する理由です。sizeof
式はそのオペランドのサイズに評価されることを思い出してください。main
前に配列の合計サイズを取得するために使用します。これを文字列リテラルに使用します。すべての文字列リテラルは文字の配列です。文字列リテラルは、ヌル文字に加えて入力した文字で構成されます。strlen
は C 文字列の長さをカウントし、その長さに終端のヌル文字を含まないため、次の条件が成立します。
// "abc" would have the type char[4] (array of 4 characters)
sizeof "..." == strlen("...") + 1
いずれにしても sizeof char は 1 であるため、1 つの要素のサイズで割る必要はありません。違いはありません。なぜsizeof
strlen の代わりに使用するのですか? 終端の null 文字がすでに考慮されており、コンパイル時に評価されるためです。コンパイラは、sizeof 式が返すサイズを文字通り置き換えることができます。