2016-04-30 9 views
54

Angeregt durch ein Programm auswertet:' 0' auswertet falsch " 0" in <em>K & R</em> Abschnitt 5.5 beschrieben wahre

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

C Programm

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

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

Drucke

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

Warum '\0' und "\0" in C anders bewerten?

Klirren version 3.8.0

+32

Die erste der ist * nul-Zeichen * ist die zweite * leeren string *. –

+5

weil sie verschiedene Dinge sind, warum würden sie identisch bewerten? – njzk2

+3

Und warum vergleichen Sie Strings/Zeichen mit booleans? –

Antwort

109

Recall wie Stringliterale in C arbeiten - "\0" ein Zeichenfeld ist mit zwei Null-Bytes (die Sie gebeten, und die impliziten eines am Ende). Wenn es für den Test if ausgewertet wird, zerfällt es in einem Zeiger auf seinem ersten Zeichen. Dieser Zeiger ist nicht NULL, daher wird er als wahr betrachtet, wenn er als Bedingung verwendet wird.

'\0' ist die Zahl Null, entspricht nur 0. Es ist eine ganze Zahl, die Null ist, daher wird sie als falsch betrachtet, wenn sie als Bedingung verwendet wird.

+0

Die vorgeschlagene Bearbeitung dieser Antwort ist falsch. Der Schrägstrich ist ein Escape-Zeichen und kein Zeichen an sich. I.e. 'echo 'int main() {printf ("% lu \ n ", Größevon (" \ 0 ")); zurückgeben 0; } '| gcc -x c -; ./a.out' ergibt "2". '\ 0' ist eine Ganzzahl, die einen NULL-Terminator darstellt. – tangrs

+20

'" \ 0 "' ist ein Array, kein Zeiger –

+4

@MM: es ist ein String-Literal;) – knittl

0

'\ 0' ist einnull Charakter, der den Wert von 0 hat. Es wird verwendet, um eine Zeichenkette zu beenden. Es ist also falsch.

"\ 0" ist ein null oder leerZeichenfolge. Das einzige Zeichen in der Zeichenfolge ist das Nullzeichen, das die Zeichenfolge beendet. Dies gilt als wahr.

+4

Es ist nicht nur so "wahr". Ein String-Literal in C ist nur ein Zeiger auf sein erstes Element, und das wird als wahr ausgewertet. – lemondrop

+2

@lemondrop Ein String-Literal ist kein Zeiger. Ein String-Literal kann in einigen Kontexten in einen Zeiger umgewandelt werden (z. B. OP-Code) –

+3

"* Das einzige Zeichen in der Zeichenfolge ist das Nullzeichen, das die Zeichenfolge beendet *" das ist nicht ganz richtig. Diese "Zeichenkette" ("0") enthält *** zwei *** "" Zeichen. – alk

3

Zuerst betrachtet man die beiden Bedingungen '\0' ist eine Konstante des Typs Integer, die das Nullzeichen C bezeichnet, das das gleiche wie 0 ist. Während ist ein String-Literal, das 2 Bytes enthält, die angegebene und das Null-Terminator-Byte implizit hinzugefügt. Als ein String-Literal kann der Zeiger nicht NULL sein.

Zweitens, in C, für die Bedingung if Anweisung wird alles ungleich Null als true ausgewertet, und Null wird als false ausgewertet.

Nach dieser Regel wird es klar sein, dass '\0' ist false und "\0" als true bewertet.

+0

Ja, das stimmt, ich habe es geändert. – fluter

+1

Ihre Antwort erklärt nicht, warum '" \ 0 "' als 'wahr' betrachtet wird. – alk

+0

@alk '" \ 0 "' wäre "wahr", nicht "falsch". – fluter

14

'\0' eine Zahl: 0, so wird es als falsch (0 = false, !0 = true) ausgewertet.

Aber "\0" ist ein Zeiger auf einen schreibgeschützten Abschnitt, wo die tatsächliche Zeichenfolge gespeichert wird, der Zeiger ist nicht NULL ergo es ist wahr.

+0

'" \ 0 "' ist kein Zeiger. Es ist ein String-Literal, dessen Wert ein Array ist (das implizit in den meisten, aber nicht allen Kontexten in einen Zeiger konvertiert wird). –

34

Zunächst einmal müssen Sie im Auge behalten, dass in C,

  • Zero ist falsch und nicht Null ist wahr.
  • Für Zeigertypen ist NULL falsch und nicht NULL ist wahr.

'\0', wie andere gesagt haben, ist das gleiche wie die Ganzzahlliteral 0 und damit falsch ist (siehe oben zuerst Aufzählungspunkt zu wissen, warum).

"\0" ist ein Zeichenfolgenliteral, das zwei \0 Zeichen enthält (Eines, das Sie explizit hinzugefügt haben und das andere, das implizit ist und vom Compiler hinzugefügt wird). Das Zeichenfolgenliteral wird irgendwo im Nur-Lese-Speicher gespeichert. Wenn Sie "\0" verwenden, wird es in einen Zeiger auf sein erstes Element konvertiert. Dies wird üblicherweise als "array decay" bezeichnet. (Dies ist der Grund, warum Sachen wie char* str = "string"; funktionieren).

So, überprüfen Sie effektiv die Adresse des ersten Zeichens der Zeichenfolge Literal. Da die Adresse des String-Literals immer nicht NULL ist, wird das if immer wahr sein (siehe zweiten Punkt oben, um zu wissen, warum).


: Dieses "Zerfall" von Arrays nicht immer der Fall. Siehe Exception to array not decaying into a pointer?

+0

Sie haben natürlich Recht, wenn der Wert 0 falsch ist. Ein Zeichen ist jedoch nicht notwendigerweise dasselbe wie eine Ganzzahl.Ein int wird immer signiert, wenn Sie nicht explizit unsigned angeben. Ob ein Zeichen signiert ist oder nicht, hängt von der Implementierung ab! –

+2

''\ 0'' ist ein' int', IIRC, obwohl es wie ein 'char' aussieht. –

+4

Ich bin mir auch nicht sicher, wie "unsigned" und "signed" hier relevant sind. Ich meine 'unsigned' oder' signed', 'char' oder' int', alle können 0 darstellen. –

0

Wir obiges Problem in zwei unterschiedlichen Konzepten von C

  1. Arbeiten von if (Bedingung) Löschen können in C
  2. Difference of Character & Zeichenfolgenliteralen in C

1. Arbeiten von if (Bedingung) in C if (Bedingung)

In C-Sprache, wenn Bedingung auf 0 (Null) und Nicht-Null-Basis funktioniert.

Wenn das Ergebnis der gegebenen Bedingung Null ist, dann ist C der Ansicht, dass die angegebene Bedingung falsch ist.

Wenn das Ergebnis der gegebenen Bedingung Nicht-Null ist, dann ist C der Ansicht, dass die angegebene Bedingung wahr ist.

2. Difference of Character & Zeichenfolgenliteralen in C

In C Stringliterale sind solche, die in doppelten Anführungszeichen ("") eingeschlossen, während Zeichenliterale diejenigen sind, die in Einzel Zitat eingeschlossen Marken ('') und minimale Länge ist ein Zeichen und maximale Länge ist zwei Zeichen.Ein weiterer wichtiger Punkt ist, dass in C, wenn wir '\ 0' (null) in int (Integer) umwandeln, wir 0 (Zero) erhalten, während wir "\ 0" nicht implizit oder explizit in int umwandeln können . Weil "\ 0" eine Zeichenkette ist, während "\ 0" ein Zeichen ist.

Und nach Bedingung der Arbeitslogik der Zeichenkette IF, wenn die Bedingung 0 oder false zurückgibt, bedeutet dies, dass die Bedingung falsch ist; Wenn die Bedingung nicht Null zurückgibt, bedeutet dies, dass die Bedingung wahr ist.

So, nach Punkt 1 und 2 schließlich können wir schließen, dass

if ('\ 0') printf ("\ '\ 0 \' = false! \ N"); // Bedingung wird falsch

if ("\ 0") printf ("\" \ 0 \ "! = false \ n"); // Bedingung wird wahr

1

Bitte beachten Sie, dass der hexadezimale Wert von False 0x00 und True ein anderer Wert als 0x00 ist.

"\0" ist eine Zeichenfolge mit einem Zeichen und Null Terminator '\0' am Ende. Es ist also ein Zeichenzeiger, der auf ein Array von 2 Bytes zeigt: ['\0', '\0']. In diesem Array ist der erste der Buchstabe und der andere der Nullabschluss.

Nach dem Kompilieren (ohne Optimierung) wird dieser Zeichenzeiger vorübergehend einer Adresse im Speicher zugewiesen, die auf das erste Byte dieser beiden Bytes zeigt. Diese Adresse könnte beispielsweise 0x18A6 in hexadezimaler Schreibweise sein. Daher schreibt der Compiler (die meisten von ihnen) diese beiden Werte tatsächlich in den Speicher. Da eine Zeichenfolge tatsächlich die Adresse des ersten Bytes dieser Zeichenfolge ist, wird unser Ausdruck als 0x18A6 != false interpretiert. So ist es klar 0x18A6 != 0x00 ist True.

'\0' ist einfach 0x00 in hexadezimal. 0x00 != 0x00 ist falsch.

Diese Antwort wurde für die 8-Bit-Datenarchitektur mit 16-Bit-Adressierung geschrieben. Ich hoffe das hilft.

0

'\ 0' ist ein Zeichen, das der Zahl Null entspricht. "\ 0" ist eine Zeichenkette und wir fügen am Ende einer Zeichenkette normalerweise '\ 0' hinzu. Verwenden Sie nicht '\ 0' oder '\ 0' in bedingten Anweisungen, weil es ziemlich verwirrend ist.

Die folgende Verwendung vorgeschlagen:

if (array[0] != 0) 
{ 

} 

if (p != 0) 
{ 

} 

if (p != NULL) 
{ 

} 
+0

Ich würde es immer bevorzugen, ''\ 0'' in Konditionalen zu sehen, weil es anzeigt, dass Sie das' Ding 'als String behandeln, nicht als Array von Zahlen. – Attie

0

Schauen Sie sich diese mit Beispielen ..

#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; 
}