web-dev-qa-db-ja.com

「\ 0」は偽と評価し、「\ 0」は真と評価します

K&Rセクション5.5で説明されているプログラムに触発された:

void strcpy(char *s, char *t)
{
    while(*s++ = *t++);
}

Cプログラム

if ('\0') { printf("\'\\0\' -> true \n"); }
else      { printf("\'\\0\' -> false\n"); }

if ("\0") { printf("\"\\0\" -> true \n"); }
else      { printf("\"\\0\" -> false\n"); }

プリント

'\0' -> false
"\0" -> true

なぜか '\0'および"\0" Cで異なる評価をしますか?

clangバージョン3.8.0

55
Rahn

Cでの文字列リテラルの動作を思い出してください-"\0"は、2つのゼロバイト(要求されたバイトと最後の暗黙的なバイト)を含む文字配列です。 ifテストで評価されると、最初の文字へのポインターに減衰します。このポインターはNULLではないため、条件として使用すると真と見なされます。

'\0'は数字のゼロで、0と同等です。これはゼロの整数であるため、条件として使用する場合はfalseと見なされます。

112
immibis

まず、Cでは、

  • ゼロは偽であり、ゼロ以外は真です。
  • ポインター型の場合、NULLはfalseで、_NULL以外はtrueです。

'\0'は、他の人が言っているように、整数リテラル0と同じであり、したがってfalseです(理由については、上記の最初の箇条書きを参照してください)。

"\0"は、2つの\0文字(明示的に追加した文字と、暗黙的でコンパイラによって追加される他の文字)を含む文字列リテラルです。文字列リテラルは、読み取り専用メモリのどこかに保存されます。 "\0"を使用すると、最初の要素へのポインターに変換されます。これは一般に「 array decay 」と呼ばれます。 (これがchar* str = "string";のようなものが機能する理由です)。

したがって、文字列リテラルの最初の文字のアドレスを効果的に確認しています。文字列リテラルのアドレスは常にNULLでないため、ifは常にtrueになります(上記の2番目の箇条書きを参照して理由を確認してください)。


:配列のこの「崩壊」は常に発生するとは限りません。 ポインタに減衰しない配列の例外? を参照してください

34
Spikatrix

'\0'は数値です:0、つまりfalse(0 = false、!0 = true)。

しかし、"\0"は、実際の文字列が格納されている読み取り専用セクションへのポインタです。ポインタはNULLではなく、本当です。

15
FedeWar

まず、2つの条件を見ると、'\0'は整数型の定数であり、0と同じヌル文字Cを示します。 "\0"は2バイトを含む文字列リテラルですが、指定された1バイトとNULLターミネーターバイトが暗黙的に追加されます。文字列リテラルであるため、ポインターをNULLにすることはできません。

次に、Cでは、ifステートメントの条件に対して、ゼロ以外のすべてがtrueとして評価され、ゼロはfalseとして評価されます。

このルールによれば、'\0'falseであり、"\0"trueとして評価されることが明らかです。

3
fluter

まず、Falseの16進値は0x00およびTrueは、0x00以外の値です。

"\0"は、文字とヌルターミネータ'\0' 最後に。したがって、これは2バイトの配列を指す文字ポインターです:['\0', '\0']。この配列では、最初の文字が文字で、もう1つの文字がヌルターミネータです。

(最適化せずに)コンパイルした後、この文字ポインタは一時的にこれら2バイトの最初のバイトを指すメモリ内のアドレスに割り当てられます。このアドレスは、たとえば0x18A6は16進数です。そのため、コンパイラ(それらのほとんど)は実際にこれら2つの値をメモリに書き込みます。文字列は実際にはその文字列の最初のバイトのアドレスであるため、式は0x18A6 != false。したがって、それは明らかです0x18A6 != 0x00はTrueです。

'\0'は単に0x00は16進数です。 0x00 != 0x00はFalseです。

この回答は、16ビットアドレッシングを備えた8ビットデータアーキテクチャ向けに書かれています。それがお役に立てば幸いです。

1
Bora

例でこれを確認してください。

#include <stdio.h> 

int main() 
{ 
printf( "string value\n" ); 

//the integer zero 
printf( "0.........%d\n" , 0 ); 

//the char zero, but chars are very small ints, so it is also an int 
//it just has some special syntax and conventions to allow it to seem 
//like a character, it's actual value is 48, this is based on the 
//ASCII standard, which you can look up on Wikipedia 
printf( "'0'.......%d\n" , '0' ); 

//because it is an integer, you can add it together, 
//'0'+'0' is the same as 48+48 , so it's value is 96 
printf( "'0'+'0'...%d\n" , '0'+'0' ); 

//the null terminator, this indicates that it is the end of the string 
//this is one of the conventions strings use, as a string is just an array 
//of characters (in C, at least), it uses this value to know where the array 
//ends, that way you don't have to lug around another variable to track 
//how long your string is. The actual integer value of '\0' is zero. 
printf( "'\\0'......%d\n" , '\0' ); 

//as stated, a string is just an array of characters, and arrays are tracked 
//by the memory location of their first index. This means that a string is 
//actually a pointer to the memory address that stores the first element of 
//the string. We should get some large number, a memory address 
printf( "\"0\".......%d\n" , "0" ); 

//a string is just an array of characters, so lets access the character 
//in position zero of the array. it should be the character zero, which 
//has an integer value of 48 
printf( "\"0\"[0]....%d\n" , "0"[0] ); 

//and the same thing for the empty string 
printf( "\"\\0\"[0]...%d\n" , "\0"[0] ); //equal to '\0' 

//we also said a string is just a pointer, so we should be able to access 
//the value it is pointing to (the first index of the array of characters) 
//by using pointers 
printf( "*\"0\"......%d\n" , *"0" ); 

return 0; 
}
0
Krishna

'\ 0'null文字で、値はです。文字列を終了するために使用されます。したがって、それは偽と見なされます。

"\ 0"nullまたはemptystringです。文字列内の唯一の文字は、文字列を終了するヌル文字です。したがって、trueと見なされます。

0
msc

「\ 0」は数字のゼロに等しい文字です。 「\ 0」は文字列であり、通常は文字列の末尾に「\ 0」を追加します。条件ステートメントで「\ 0」または「\ 0」を使用しないでください。混乱を招く可能性があります。

次の使用方法が推奨されます。

if (array[0] != 0)
{

}

if (p != 0)
{

}

if (p != NULL)
{

}
0
G.Mather

上記の問題は、Cの2つの異なる概念で解決できます。

  1. Cでのif(condition)の動作
  2. Cの文字リテラルと文字列リテラルの違い

1。 Cif(condition)でのif(condition)の動作

C言語では、条件が0(Zero)およびNon-Zero base。

指定された条件の結果がゼロの場合、Cは指定された条件が偽であると見なします。

指定された条件の結果が非ゼロの場合、Cは指定された条件が真であると見なします。

2。 Cの文字リテラルと文字列リテラルの違い

Cでは、文字列リテラルは二重引用符( "")で囲まれたものであり、文字リテラルは単一引用符( '')で囲まれたものであり、最小長は1文字、最大長は2文字です。

もう1つの重要な点は、Cでは、「\ 0」(null)をint(Integer)に変換すると0(Zero)になりますが、「\ 0」を暗黙的または明示的にintに変換できないことです。 「\ 0」は文字列であり、「\ 0」は文字であるためです。

文字列IF条件の動作ロジックによると、条件が0またはfalseを返す場合、条件がfalseであることを意味します。条件がゼロ以外を返す場合、条件が真であることを意味します。

したがって、ポイント1および2によれば、最終的に次のように結論付けることができます。

if( '\ 0')printf( "\ '\ 0 \'!= false\n"); //条件が偽になる

if( "\ 0")printf( "\"\0\"!= false\n"); //条件が真になる

0
Ravi

単純なことは、ATLEAST 0(int)と0.0(floatまたはdouble)がCでFALSE値を持つことです。

'\ 0'は整数0です。

「\ 0」は文字の配列です。配列内に存在するCharactersの数や、それらのキャラクタが何であるかは関係ありません。

したがって、77-77が0と評価されるように、「\ 0」は0と評価されます。0はfalseです。

int x; x = '\0'; printf("X has a value : %d");出力:


xの値は0です

そしてコード:

if(0){printf("true");}

else{printf("false");}

出力:


false

0
Bhartendu Kumar