web-dev-qa-db-ja.com

Cのprintf形式文字列に%cと%sの両方があるのはなぜですか?

Cのprintfフォーマット文字列に%cおよび%s

そんなこと知ってる %cは単一の文字を表し、%sはヌルで終わる文字列を表しますが、文字列表現だけでは十分ではありませんか?

70
Billy Rubina

おそらく、ヌルで終了する文字列と文字を区別するためです。彼らがただ%s、すべての単一文字もヌルで終了する必要があります。

char c = 'a';

上記の場合、cはnullで終了する必要があります。これは私の仮定です:)

98
Mahesh

_%s_は、_0_(または_'\0'_、同じこと)に達するまで文字を出力します。

_char x;_がある場合、printf("%s", &x);で印刷する-_%s_は_char*_-_&x + 1_は_0_ではない可能性があるため、予期しない結果が生じます。

したがって、ヌル終了(非常に非効率的)でない限り、単一の文字を印刷することはできません。

編集:他の人が指摘したように、2つはvar argsパラメータに異なることを期待しています-1つはポインタ、もう1つは単一の文字です。しかし、その違いはいくらか明確です。

73
Luchian Grigore

単一の文字をヌルで終了する必要があるという他の人からの問題は、実際の問題ではありません。これは、%.1s形式で精度を指定することで対処できます。

私の見解でより重要なのは、そのフォームの%sに対して、1つまたは複数の文字へのポインターを提供する必要があるということです。これは、右辺値(計算式、関数の戻り値など)を出力したり、変数を登録したりできないことを意味します。

編集:私はこの回答に対する反応に本当に腹を立てているので、おそらくこれを削除します。これは本当に価値がありません。質問を読んだり、質問の専門性を理解する方法を知らなくても、人々はこれに反応するようです。

それを明確にするために、%.1sよりも%cを好むべきだとは言いません。%cに置き換えられない理由はこれらのその他の回答は技術的に間違っています。ヌル終了は%sの問題ではありません。

37
Jens Gustedt

Printf関数は可変引数関数です。つまり、引数の数が可変です。引数は、関数(printf)が呼び出される前にスタックにプッシュされます。関数printfがスタックを使用するためには、スタック内にあるものに関する情報を知る必要があり、そのためにフォーマット文字列が使用されます。

例えば.

printf( "%c", ch );    tells the function the argument 'ch' 
                       is to be interpreted as a character and sizeof(char)

一方、

printf( "%s", s );   tells the function the argument 's' is a pointer 
                     to a null terminated string sizeof(char*)

それ以外の場合、printf関数内でスタックの内容を決定することはできません。 Cでは実行時に型チェックが行われないため、「ch」と「s」を区別します。

28
Anders

%sは、nullが見つかるまですべての文字を出力する(変数をポインターとして扱う)と言います。

%cは、1文字だけを印刷することを示します(変数を文字コードとして扱います)

文字がポインターのように扱われるため、文字に%sを使用しても機能しません。次に、nullが見つかるまでメモリ内のその場所に続くすべての文字を印刷しようとします。

他の回答から盗む別の方法で説明する。

%sを使用して文字を印刷したい場合は、次を使用して文字のアドレスを適切に渡し、nullが見つかるまで画面にゴミを書き込まないようにすることができます。

char c = 'c';
printf('%.1s', &c);
13
Juan Mendes

%sの場合、値ではなく文字列のアドレスを提供する必要があります。

%cには、文字の値を提供します。

%sの代わりに%cを使用した場合、文字の後に'\0'を提供する方法を教えてください。

7
RolandXu

この楽しい質問に別の視点を追加したいと思います。

本当にこれはデータ型付けに帰着します。ここで、charへのポインタを提供し、

"%.1s"

これは確かに真実かもしれません。しかし、その答えは、プログラマーに柔軟性を提供しようとするCデザイナーの試みにあり、実際、アプリケーションのフットプリントを(わずかではあるが)減らす方法です。

プログラマーは、一連のif-elseステートメントまたはswitch-caseを実行したい場合があります。その場合、状態に基づいて単純に文字を出力する必要があります。このため、単一文字は32ビットまたは64ビット(64ビットコンピューターの場合)であるポインターに対して8ビットであるため、文字のハードコーディングは実際にメモリ内の実際のスペースを少なくすることができます。ポインターは、メモリ内でより多くのスペースを占有します。

実際の文字対文字へのポインタを使用してサイズを小さくしたい場合、printfタイプの演算子内でこれを行うには2つの方法が考えられます。 .1をキーオフすることもできますが、ルーチンは、char型またはchar型へのポインタまたは文字列(char型の配列)に対するポインタを本当に提供していることを確実に知るためにどのようになっていますか?これが、「%c」を使用した理由です。

楽しい質問:-)

5
trumpetlicks

%cは、整数であるcharを予期し、エンコード規則に従って出力します。

%sはchar値を含むメモリの場所にpointerを期待し、0(null)文字が見つかるまでエンコード規則に従ってその場所の文字を出力します。

したがって、内部では、2つのケースが似ているように見えますが、1つは値で動作し、もう1つはポインターで動作するため、あまり共通点はありません。 1つは特定の整数値をASCII文字として解釈するための命令であり、もう1つはメモリ位置の文字をcharごとに繰り返し、ゼロ値が見つかるまでそれらを解釈するためのものです。

2
Gerasimos R

Cには%cおよび%s書式指定子は異なるタイプを処理するためです。

charと文字列は、nightと1とほぼ同じです。

2
Philip

printf("%.1s", &c)printf("%c", c)を使って実験しました。以下のコードを使用してテストし、bashのtimeユーティリティを使用して実行時間を取得しました。

    #include<stdio.h>
    int main(){
        char c = 'a';
        int i;
        for(i = 0; i < 40000000; i++){
            //printf("%.1s", &c); get a result of 4.3s
            //printf("%c", c); get a result of 0.67s
        }
        return 0;
    }

結果は、%cの使用は%.1sの10倍高速であると言います。したがって、%sは%cのジョブを実行できますが、パフォーマンスのためには%cが必要です。

2
Ray

誰もどんな参照でも答えを提供していないので、ここに pubs.opengroup.com のprintf仕様があります。これは [〜#〜] ibm [〜 #〜]

%c

Int引数はunsigned charに変換され、結果のバイトが書き込まれます。

%s

引数は、charの配列へのポインターでなければなりません。配列のバイトは、終端のヌルバイトまで書き込まれます(ただし、含まれません)。精度が指定されている場合、それ以上のバイト数は書き込まれません。精度が指定されていないか、配列のサイズより大きい場合、アプリケーションは、配列にヌルバイトが含まれていることを確認する必要があります。

1