Warum ist "a"! = "A" in C?

110
void main() {
    if("a" == "a")
      printf("Yes, equal");  
    else
      printf("No, not equal");
}

Warum ist die Ausgabe No, not equal?

Javed Akram
quelle
100
void main??? Ew ...
Paul R
47
Embedded C-Compiler ermöglichen void main (), da möglicherweise kein Betriebssystem vorhanden ist, dem ein Rückkehrcode zugewiesen werden kann.
Jeanne Pindar
26
Wie kann eine solche Frage so oft bewertet werden? Es ist wirklich nicht so interessant ... Ich meine, dass Strings Arrays und Arrays Zeiger sind, ist wirklich ein alter Hut in C, nicht wahr?
Felix Dombek
64
@Felix, es ist eine präzise geschriebene Frage, die einen häufigen Verwirrungspunkt für Sprachanfänger anspricht. SO ist nicht nur für Experten gedacht, sondern auch für Anfänger, und gezielte Fragen wie diese sind gut, um Anfänger in Zukunft darauf hinzuweisen.
Bdonlan
37
@ Felix: Du liegst falsch. Arrays sind keine Zeiger
John Dibling

Antworten:

209

Was Sie vergleichen, sind die beiden Speicheradressen für die verschiedenen Zeichenfolgen, die an verschiedenen Orten gespeichert sind. Dies sieht im Wesentlichen so aus:

if(0x00403064 == 0x002D316A) // Two memory locations
{
    printf("Yes, equal");
}

Verwenden Sie den folgenden Code, um zwei Zeichenfolgenwerte zu vergleichen:

#include <string.h>

...

if(strcmp("a", "a") == 0)
{
    // Equal
}

"a" == "a"Abhängig von Ihrem Compiler, der zur Kompilierungszeit gleiche Zeichenfolgen zu einer kombinieren kann , kann dies tatsächlich true zurückgeben, um Platz zu sparen.

Wenn Sie zwei Zeichenwerte (die keine Zeiger sind) vergleichen, handelt es sich um einen numerischen Vergleich. Beispielsweise:

'a' == 'a' // always true
Tim Cooper
quelle
12
GCC hat auch die Optionen -fmerge-constantsund -fno-merge-constantsaktivieren / deaktivieren String und Floating-Point - Konstante über Übersetzungseinheiten verschmelzen, obwohl auf einigen GCCs scheint es , dass konstante Verschmelzung immer aktiviert , unabhängig von dieser Option.
Adam Rosenfield
2
Es würde funktionieren, wenn Sie 'a' anstelle von "a" verwenden. Das erste ist ein Zeichen, das eigentlich ein numerischer Wert ist.
GolezTrol
@GolezTrol: In C hat das Literal 'a' tatsächlich den intTyp. :-) Außerdem müssen Zeiger keine numerischen Werte sein.
Bastien Léonard
intist auch numerisch, nicht wahr? Aber ich dachte, Zeichen wären Byte. Int ist 4 Bytes. Die Zeiger selbst sind ebenfalls ganzzahlig. Sie enthalten die Adresse einer Reihe von Daten (Daten, die tatsächlich nicht numerisch sein müssen).
GolezTrol
'a' == 'A' // not true... MySQL unterscheidet sich.
Steven
52

Ich bin etwas spät zur Party, aber ich werde trotzdem antworten. technisch die gleichen Bits, aber aus einer etwas anderen Perspektive (C-Sprache unten):

In C bezeichnet der Ausdruck "a"ein Zeichenfolgenliteral , bei dem es sich um ein statisches unbenanntes Array const charmit einer Länge von zwei handelt. Das Array besteht aus Zeichen, 'a'und '\0'das abschließende Nullzeichen signalisiert das Ende der Zeichenfolge.

In C gibt es jedoch auf die gleiche Weise, wie Sie Arrays nicht nach Wert an Funktionen übergeben oder ihnen Werte zuweisen können ( nach der Initialisierung ), keinen überladenen Operator ==für Arrays, sodass es nicht möglich ist, sie direkt zu vergleichen. Erwägen

int a1[] = {1, 2, 3};
int a2[] = {3, 4, 5};
a1 == a2 // is this meaningful? Yes and no; it *does* compare the arrays for
         // "identity", but not for their values. In this case the result
         // is always false, because the arrays (a1 and a2) are distinct objects

Wenn das ==Arrays nicht vergleicht, was macht es dann tatsächlich? In C zerfallen Arrays in fast allen Kontexten - einschließlich dieses - in Zeiger (die auf das erste Element des Arrays zeigen) - und der Vergleich von Zeigern auf Gleichheit bewirkt, was Sie erwarten. So effektiv, wenn Sie das tun

"a" == "a"

Sie vergleichen tatsächlich die Adressen der ersten Zeichen in zwei unbenannten Arrays . Gemäß dem C-Standard kann der Vergleich entweder wahr oder falsch ergeben (dh 1 oder 0) - "a"s können tatsächlich dasselbe Array oder zwei völlig unabhängige Arrays bezeichnen. In technischer Hinsicht ist der resultierende Wert nicht angegeben , was bedeutet, dass der Vergleich zulässig ist (dh es ist kein undefiniertes Verhalten oder ein Syntaxfehler), aber jeder Wert ist gültig und die Implementierung (Ihr Compiler) ist nicht erforderlich, um zu dokumentieren, was tatsächlich passieren wird.

Wie andere bereits betont haben, verwenden Sie zum Vergleichen von "c-Zeichenfolgen" (dh Zeichenfolgen, die mit einem Nullzeichen abgeschlossen sind) strcmpdie in der Standard-Header-Datei enthaltene Komfortfunktion string.h. Die Funktion hat einen Rückgabewert von 0für gleiche Zeichenfolgen. Es wird als bewährte Methode angesehen, den Rückgabewert explizit mit zu vergleichen, 0anstatt den Operator `! ´ zu verwenden, d. h

strcmp(str1, str2) == 0 // instead of !strcmp(str1, str2)
Gl.
quelle
47

Gemäß C99 (Abschnitt 6.4.5 / 6)

String-Literale

Es ist nicht spezifiziert, ob diese Arrays unterschiedlich sind, vorausgesetzt, ihre Elemente haben die entsprechenden Werte .

In diesem Fall ist also nicht spezifiziert, ob beide "a"s verschieden sind. Ein optimierter Compiler könnte eine einzelne "a"an der schreibgeschützten Stelle behalten, und beide Referenzen könnten darauf verweisen.

Überprüfen Sie die Ausgabe auf gcc hier

Prasoon Saurav
quelle
19

Da es sich um zwei separate const char*Zeiger handelt, keine tatsächlichen Werte. Sie sagen so etwas wie das, 0x019181217 == 0x0089178216was natürlich NEIN zurückgibt

Verwenden Sie strcmp()anstelle von==

Antwan van Houdt
quelle
7
String-Literale sind keine Zeiger, sondern Arrays. Beim Vergleich verfallen sie jedoch zu Zeigern.
GManNickG
@ Gman wahr, tut mir leid, dass ich nicht wirklich klar darüber bin, neige dazu, es zu vergessen :)
Antwan van Houdt
9

Einfach ausgedrückt hat C keinen eingebauten String-Vergleichsoperator. Auf diese Weise können Zeichenfolgen nicht verglichen werden.

Stattdessen werden Zeichenfolgen mithilfe von Standardbibliotheksroutinen wie strcmp () oder durch Schreiben von Code zum Durchlaufen jedes Zeichens in der Zeichenfolge verglichen.

In C gibt eine Textzeichenfolge in doppelten Anführungszeichen einen Zeiger auf die Zeichenfolge zurück. In Ihrem Beispiel werden die Zeiger verglichen, und anscheinend sind Ihre beiden Versionen der Zeichenfolge an unterschiedlichen Adressen vorhanden.

Aber es geht nicht darum, die Saiten selbst zu vergleichen, wie Sie zu erwarten scheinen.

Jonathan Wood
quelle
3

Zeiger.

Der erste "a"ist ein Zeiger auf eine nullterminierte ASCII-Zeichenfolge.

Der zweite "a"ist ein Zeiger auf eine andere nullterminierte ASCII-Zeichenfolge.

Wenn Sie einen 32-Bit-Compiler verwenden, würde ich erwarten "a"=="a"-4. Ich habe es gerade mit tcc / Win32 versucht, und ich verstehe "a"=="a"-2. Naja...

Nico57
quelle
6
Warum sollten Sie erwarten, dass Zeichenfolgen an der 4-Byte-Grenze ausgerichtet werden? Sie sind keine Ints. 2 ist das, was ich erwarten würde (wenn der Compiler sie nicht zusammenführt), da jede Zeichenfolge zwei Bytes lang ist, einschließlich des Null-Terminators.
Sergei Tachenov
Ein gewisser Grad an Ausrichtung kann beispielsweise die gleichzeitige strcmpAusführung mehrerer Bytes ermöglichen. Einige Compiler tun es, andere nicht, andere nur für Strings, die länger als ein Minimum sind ...
zwol
@Zack: Wie würden sie die Länge der Zeichenfolge kennen, bevor sie sie tatsächlich vergleichen?
Joachim Sauer
Ich meinte, einige Compiler richten Strings länger als ein Minimum aus.
zwol
1

Sie vergleichen zwei Speicheradressen, sodass das Ergebnis nicht immer wahr ist. Hast du es versucht if('a' == 'a'){...}?

SK9
quelle
1

Diese Frage ist für alle Anfänger eine sehr gute Erklärung.
Lassen Sie mich auch dazu beitragen.

Wie alle oben erklärt haben, warum Sie eine solche Ausgabe erhalten.

Jetzt, wenn du deinen Prog willst. Dann "Ja gleich" drucken

entweder verwenden

if(strcmp("a", "a") == 0)
{

}

oder verwenden
Sie nicht "a" als Zeichenfolgen, verwenden Sie sie als Zeichen ....

if('a'=='a')  
{  
printf ("yes Equal");  
}  

in C Zeichen sind 1 Byte kurze Ganzzahl .......

N-FREUDE
quelle
Zeichen belegen nur 1 Byte, aber Zeichenliterale wie z. B. 'a'sind tatsächlich Ganzzahlen.
Spidey
0

Einige Compiler verfügen über die Option "Zeichenfolgen zusammenführen", mit der Sie erzwingen können, dass alle konstanten Zeichenfolgen dieselbe Adresse haben. Wenn Sie das nutzen "a" == "a"würden , wäre true.

Daniel Mošmondor
quelle
0

wenn der Vergleich zwischen Zeichen immer in einfachen Anführungszeichen steht, z

if('a' == 'a')

und C kann den String-Vergleich nicht unterstützen "abc" == "abc"

Es ist erledigt mit strcmp("abc","abc")

Bhavin Patel
quelle
-5

Dieser Typ verwendet keine Variablen. Stattdessen verwendet er vorübergehend Textarrays: aund a. Der Grund warum

void main() 
{
    if("a" == "a")
      printf("Yes, equal");  
    else
      printf("No, not equal");
}

funktioniert natürlich nicht, ist, dass man keine variablen vergleicht.
Wenn Sie Variablen erstellen würden wie:

char * text = "a";
char * text2 = "a";

dann könnte man vergleichen textmit text2, und es sollte wahr

Vielleicht solltest du nicht vergessen zu verwenden {und }=)

void main() {
    if("a" == "a")
    {
      printf("Yes, equal");
    }
    else
    {
      printf("No, not equal");
    }
}
D. Ace
quelle
1
" und es sollte wahr sein " - Nein. Es ist nicht angegeben, ob die Zeichenfolgenliterale am selben Speicherort gespeichert werden. Lesen Sie die anderen Antworten.
Spikatrix