最初のものは機能するのに、2 番目のものは機能しないのはなぜですか?
最初の例では、文字を出力するように要求しているのではなく、null で終わる文字の配列を文字列として出力するように要求しているためです。
ここでの混乱は、文字列を整数や文字と同じように「ネイティブ型」と考えていることです。C はそのようには機能しません。文字列は、null バイトで終わる一連の文字への単なるポインタです。
本当に文字列をネイティブ型と考えたい場合は (実際にはそうではないことに注意してください)、次のように考えてください: 文字列の型は であり、 ではchar *
ありませんchar
。したがって、を示すフォーマット指定子と一致するようにprintf("%s\n", a);
a を渡しているため、機能します。2 番目の例と同等の問題を得るには、文字列へのポインタ、つまり.char *
char *
char **
%d
または、 is not %s
, butに相当するものは%c
、1 つの文字を出力します。それを使用するには、文字を渡す必要があります。printf("%c\n", a)
と同じ問題が発生しprintf("%d\n", b)
ます。
あなたのコメントから:
aには「abc」のアドレスが格納されていると思います。では、印刷すると abc が表示されるのはなぜですか? *a の値を取得するには、出力する必要があると思います。
これは、ネイティブオブジェクトとしての文字列の緩い考え方が崩れるところです。
これを書くとき:
char *a = "abc";
何が起こるかというと、コンパイラは 4 文字の配列 <code>'a'、'b'
、'c'
、および — を'\0'
どこかに格納a
し、最初の . を指しa
ます。これが実際には 4 つの別個の文字からなる配列であることを覚えている限り、その配列へのポインター"abc"
と考えるのは理にかなっていますa
(少なくとも、配列とポインター演算が C でどのように機能するかを理解している場合)。しかし、それを忘れると、a
単一のオブジェクトを保持する単一のアドレスを指していると考えると"abc"
、混乱します。
GNU printf
man ページからの引用(C 標準はリンクできないため):
d、私
int 引数は符号付き 10 進数表記に変換されます…</p>
c
… int 引数は unsigned char に変換され、結果の文字が書き込まれます…</p>
s
… const char * 引数は、文字型の配列へのポインター (文字列へのポインター) であることが期待されます。配列の文字は、終端の null バイト ('\0') まで (ただし、含まない) 書き込まれます …</p>
最後に一つだけ:
「文字列」などの値がない場合、どのようにprintf("%s", a)
または他の関数が文字列を出力または検索できるのか疑問に思うかもしれません。strchr(a, 'b')
彼らは規則を使用しています: 彼らは文字へのポインタを取り、そこから最初の null までのすべての文字を出力または検索します。たとえば、次のprint_string
ような関数を作成できます。
void print_string(char *string) {
while (*string) {
printf("%c", *string);
++string;
}
}
または:
void print_string(char *string) {
for (int i=0; string[i]; ++i) {
printf("%c", string[i]);
}
}
char *
いずれにせよ、 は単一の文字ではなく、文字の配列の先頭へのポインターであると想定し、null 文字に到達するまで配列内の各文字を出力します。これは、標準ライブラリ全体printf
で、 などの関数に組み込まれている「ヌル終了文字列」の規則です。strstr