2つの機能があるとしましょう:
void function1(int *ptr) {
printf("%d", *ptr);
}
と
void function2(char *str) {
printf("%s", str);
}
の前に参照演算子がないのに、function2 が機能するのはなぜstr
ですか? 中には思った通りの値ではなく指し示すアドレスstr
しかありません。
2つの機能があるとしましょう:
void function1(int *ptr) {
printf("%d", *ptr);
}
と
void function2(char *str) {
printf("%s", str);
}
の前に参照演算子がないのに、function2 が機能するのはなぜstr
ですか? 中には思った通りの値ではなく指し示すアドレスstr
しかありません。
str の前に参照演算子がない場合、function2 が機能するのはなぜですか
%s
は、標準で定義されているように、char *
、つまりアドレスを想定しているためです。
7.21.6.1
l 長さ修飾子が存在しない場合、引数は文字型の配列の最初の要素へのポインタでなければなりません。配列の文字は、終端のヌル文字まで (ただし、ヌル文字は含みません) 書き込まれます。精度が指定されている場合、そのバイト数を超えて書き込まれることはありません。精度が指定されていないか、配列のサイズより大きい場合、配列にはヌル文字が含まれます。
を使用する場合、 apointer to a char
は特別だからprintf
です。それを単一の char へのポインターとして扱う代わりに、文字のNUL
区切られた配列の最初の要素へのポインターとして扱い、単なるポインターではなく文字列を出力します。
私たちが書くとき
char *s="hello";
s
デフォルトでは、最初の要素の最初のアドレスのアドレスを取得します。つまり、「h」のアドレスとprintfの%sは、要素@の最初の場所ではなく文字列全体を出力します。そのため、服従演算子は必要ありません。最初の要素を出力するか、すべての要素を出力するかは、Cコンパイラを混乱させた可能性があります。
これは、printf()
渡されるさまざまなタイプの引数を理解するように関数が作成されているためです。文字列内の書式指定子は、printf()
各引数が何を期待するかを示します。次に、ドキュメントに何を渡すかが示されます。
すなわち。基本的にprintf()
は、定義された仕様に従っており、それに従っているため機能します。
したがって、最初の例では、%d 形式を使用します。 printf()
これは、引数が整数値であることを意味します。整数へのポインターではなく、整数です。これが機能する理由です:
void function1(int *ptr) {
printf("%d", *ptr);
}
これはしません:
void function1(int *ptr) {
printf("%d", ptr);
}
2番目の例は文字列であり、Cの文字列は実際には直接のデータ型ではないため、ここで混乱の可能性があります(そのため)。 これらは、他の文字が続き、NULL \0 で終了する文字へのポインタです。
void function2(char *str) {
printf("%s", str);
}
ここで、文字列が C のデータ型である場合、他の値と同じ方法でそれらを渡すことになるでしょう (これは純粋に仮説です)。
void function2(string str) {
printf("%s", str);
}
要約すると:
%d -> int
%s -> char *
C で文字列を参照する方法は、最初の文字のアドレスです。文字列を読み取る関数は、このアドレスのバイトを読み取り、それを使用して何かを実行し (たとえば、 の場合は出力しますprintf()
)、次の文字に移動します。これは、文字列の終わりを示す 0 バイトが見つかるまで続きます。
これは基本的にメモリを節約する方法です。のようなその他の基本的なデータ型int
は十分に小さく、値を安価にコピーできるため、オブジェクトのアドレスを参照する必要はありません。