'\ 0'とCのprintf()


21

Cの入門コースで、文字列を格納するときに、文字列\0の最後にnull文字が格納されることを学びました。しかし、文字列を印刷したい場合printf("hello")\0、次のステートメントで終わっていないことがわかりましたが、

printf("%d", printf("hello"));

Output: 5

しかし、これは一貫性がないようです。文字列のような変数がメインメモリに格納されることを知っている限り、何かを印刷しているときにメインメモリにも格納される可能性があると思いますが、なぜ違いがあるのでしょうか。


1
あなたのコードが少なくとも欠けているという事実に加えて、あなた);はそのコードで何を示すつもりですか?で終わらないことをどのように証明しました\0か?
glglgl

それが格納されているメモリとは何ですか?
Tsakiroglou Fotis

Cでは、すべてのリテラル文字列は実際には文字の配列であり、null終止符が含まれています。
プログラマー

@glglgl printf()は、画面に印刷されるはずの文字数を返すと思います。
Ajay Mishra

4
@AjayMishraはい、そして確かに5文字が印刷されているはずです。終了0バイトは画面に出力されません。
glglgl

回答:


13

nullバイトは文字列の終わりを示します。文字列の長さには含まれず、文字列がで出力されても出力されませんprintf。基本的に、nullバイトは文字列操作を行う関数にいつ停止するかを伝えます。

違いが見られるのはchar、文字列で初期化された配列を作成する場合です。sizeof演算子を使用すると、ヌルバイトを含む配列のサイズが反映されます。例えば:

char str[] = "hello";
printf("len=%zu\n", strlen(str));     // prints 5
printf("size=%zu\n", sizeof(str));    // prints 6

とは話が違うと思いましたprintf()。TBH私はどのようにprintf()機能するのかわかりません。
Ajay Mishra

8

printf印刷される文字の数を返します。'\0'は印刷されません-この文字列に文字がなくなったことを通知するだけです。弦の長さにも含まれません

int main()
{
    char string[] = "hello";

    printf("szieof(string) = %zu, strlen(string) = %zu\n", sizeof(string), strlen(string));
}

https://godbolt.org/z/wYn33e

sizeof(string) = 6, strlen(string) = 5

6

あなたの仮定は間違っています。あなたの文字列は確かに\0

これは、5文字の含まれているhelloおよび0の文字。

「内部」print()呼び出しが出力するのは、印刷された文字数であり、それは5です。


6

Cでは、すべてのリテラル文字列は実際には文字の配列であり、null終止符が含まれています。

ただし、ヌルターミネータであるていない文字列(リテラルまたはしない)の長さで数え、それが印刷されていません。nullターミネータが見つかると、印刷が停止します。


文字列を配列に格納せずにこれを確認する方法はありますか?
Ajay Mishra

1
@AjayMishraまあ文字列がすでにある(前述のように)配列に...しかしそこにいなかった場合はnullターミネータは、printf文字列の境界の外に出て、「ランダム」や「ゴミ」の文字を印刷し、リターンAでしょう文字列の長さと異なる数値。文字列の長さがすでにわかっている場合は、そのインデックスの文字がであるかどうかを確認することもできます'\0'。これは機能しますが、配列のサイズにターミネータが含まれていない場合、技術的には未定義の動作です(のようにchar arr[5] = "hello";、配列へのターミネーター)。
プログラマ

@AjayMishraはい例char * p = "Hello"; int i = 0; while (p[i] != '\0') { printf("%d: %c", i, p[i]); i++; }:実行してどのように実行されるかを確認できます。インデックス付きの行とその行のコンテンツが表示されます。インデックス4の後、0文字を見つけ、whileループを中断します。そこに0文字があることがわかります。
glglgl

6

すべての答えは本当に良いですが、これらすべてを完了するために別の例を追加したいと思います

#include <stdio.h>

int main()
{
    char a_char_array[12] = "Hello world";

    printf("%s", a_char_array);
    printf("\n");

    a_char_array[4] = 0; //0 is ASCII for null terminator

    printf("%s", a_char_array);
    printf("\n");

    return 0;
}

オンラインgdbでこれを試したくない場合、出力は次のようになります。

こんにちは世界

地獄

https://linux.die.net/man/3/printf

これは、エスケープターミネータの機能を理解するのに役立ちますか?char配列や文字列の境界ではありません。-STOPを解析する人に言う文字は、ここまで(印刷)解析します。

PS:そして、それを解析してchar配列として出力した場合

for(i=0; i<12; i++)
{
    printf("%c", a_char_array[i]);
}
printf("\n");

あなたが得る:

地獄の世界

ここで、ダブルlの後の空白はnullターミネーターですが、char配列を解析すると、すべてのバイトのchar値だけになります。別の解析を行い、各バイトのint値( "%d%、char_array [i])を出力すると、(ASCIIコード-int表現を取得する)空白の値が0であることがわかります。


4

ではC機能printf()、印刷された文字の数を返し\0ているnullC言語で文字列の終わりを示すために使用されずにそこに内蔵されているターミネータstringのようなタイプをc++しかし、あなたの配列サイズのニーズが数よりも少なくとも大きくなるように、charあなたがしたいです保管する。

これがrefです:cpp ref printf()


3

しかし、文字列を印刷したい場合は、printf( "hello")と言いますが、次のステートメントで\ 0で終わっていないことがわかりました

printf("%d", printf("hello"));

Output: 5

あなたは間違っている。このステートメントは、文字列リテラル"hello"が終端のゼロ文字で終わっていないことを確認しません'\0'。このステートメントは、関数printfが終了ゼロ文字に遭遇するまで文字列の要素を出力することを確認しました。

上記のステートメントのように文字列リテラルを使用している場合、コンパイラーは、文字列リテラルの要素を含む静的ストレージ期間を持つ文字配列を作成します。

だから実際にはこの表現

printf("hello")

次のようなコンパイラによって処理されます

static char string_literal_hello[] = { 'h', 'e', 'l', 'l', 'o', '\0' };
printf( string_literal_hello );

これにおける関数printfのアクションは、次のように想像できます。

int printf( const char *string_literal )
{
    int result = 0;

    for ( ; *string_literal != '\0'; ++string_literal )
    {    
        putchar( *string_literal );
        ++result;
    }

    return result;
}

文字列リテラル「hello」に格納されている文字数を取得するには、次のプログラムを実行します

#include <stdio.h>

int main(void) 
{
    char literal[] = "hello";

    printf( "The size of the literal \"%s\" is %zu\n", literal, sizeof( literal ) );

    return 0;
}

プログラム出力は

The size of the literal "hello" is 6

0

最初にコンセプトをクリアする必要があります。配列を処理するとクリアされるため、使用している印刷コマンドは、括弧内に配置されている文字を数えるだけです。配列文字列で\ 0で終わる必要がある


0

文字列は文字のベクトルです。文字列を形成する一連の文字が含まれ、その後に特殊な終了文字列が続きます: '\ 0'

例:char str [10] = {'H'、 'e'、 'l'、 'l'、 'o'、 '\ 0'};

例:次の文字ベクトルは '\ 0'で終わらないため、1つの文字列ではありません

char str [2] = {'h'、 'e'};


Cにはベクトルがないと思います。
Ajay Mishra
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.