Perché "a"! = "A" in C?


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

Perché l'output No, not equal?


100
void main??? Ew ...
Paul R

47
I compilatori C incorporati consentono void main () perché potrebbe non esserci alcun sistema operativo a cui fornire un codice di ritorno.
Jeanne Pindar

26
Come può una domanda come questa essere votata così spesso? Non è davvero così interessante ... Voglio dire, che le stringhe siano array e gli array siano puntatori è davvero un vecchio cappello in C, non è vero?
Felix Dombek

64
@Felix, è una domanda scritta in modo conciso che affronta un punto comune di confusione per i nuovi arrivati ​​nella lingua. SO non è solo per esperti, è anche per principianti e domande mirate come questa sono utili per indirizzare i principianti in futuro.
bdonlan

37
@Felix: ti sbagli. gli array non sono puntatori
John Dibling

Risposte:


209

Ciò che stai confrontando sono i due indirizzi di memoria per le diverse stringhe, che sono archiviate in posizioni diverse. In questo modo essenzialmente assomiglia a questo:

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

Usa il codice seguente per confrontare due valori di stringa:

#include <string.h>

...

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

Inoltre, "a" == "a"può effettivamente restituire true, a seconda del compilatore, che può combinare stringhe uguali in fase di compilazione in una sola per risparmiare spazio.

Quando si confrontano due valori di caratteri (che non sono puntatori), si tratta di un confronto numerico. Per esempio:

'a' == 'a' // always true

12
GCC ha anche le opzioni -fmerge-constantse -fno-merge-constantsper abilitare / disabilitare l'unione di stringhe e costanti in virgola mobile tra le unità di traduzione, sebbene su alcuni GCC sembra che l'unione costante sia sempre abilitata indipendentemente da tale opzione.
Adam Rosenfield,

2
Funzionerebbe se si utilizza "a" invece di "a". Il primo è un carattere, che in realtà è un valore numerico.
GolezTrol

@GolezTrol: in C, la "a" letterale ha effettivamente un inttipo. :-) Inoltre, i puntatori non devono essere valori numerici.
Bastien Léonard

intè anche numerico, non è vero? Ma pensavo che i caratteri fossero Byte. Int è di 4 byte. Anche i puntatori stessi sono interi. Contengono l'indirizzo di una serie di dati (dati che in effetti non devono essere numerici).
GolezTrol

'a' == 'A' // not true... MySQL chiede di essere diverso.
Steven

52

Sono un po 'in ritardo alla festa, ma risponderò comunque; tecnicamente gli stessi bit, ma da una prospettiva leggermente diversa (linguaggio C sotto):

In C, l'espressione "a"denota una stringa letterale , che è un array statico senza nome di const char, con una lunghezza di due - l'array è composto da caratteri 'a'e '\0'- il carattere null di terminazione segnala la fine della stringa.

Tuttavia, in C, allo stesso modo in cui non è possibile passare array a funzioni in base al valore o assegnare loro valori ( dopo l'inizializzazione ), non esiste un operatore sovraccarico ==per gli array, quindi non è possibile confrontarli direttamente. Tener conto di

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

Se ==non sta confrontando gli array, cosa fa effettivamente? In C, in quasi tutti i contesti, incluso questo, gli array decadono in puntatori (che puntano al primo elemento dell'array) e il confronto dei puntatori per l'uguaglianza fa quello che ti aspetteresti. Così efficacemente, quando lo fai

"a" == "a"

stai effettivamente confrontando gli indirizzi dei primi caratteri in due array senza nome . Secondo lo standard C, il confronto può restituire vero o falso (cioè 1 o 0) - i "a"s possono effettivamente denotare lo stesso array o due array completamente non correlati. In termini tecnici, il valore risultante non è specificato , il che significa che il confronto è consentito (cioè non è un comportamento indefinito o un errore di sintassi), ma entrambi i valori sono validi e l'implementazione (il compilatore) non è richiesta per documentare ciò che accadrà effettivamente.

Come altri hanno sottolineato, per confrontare le "stringhe c" (cioè le stringhe che terminano con un carattere nullo) si utilizza la comoda funzione strcmptrovata nel file di intestazione standard string.h. La funzione ha un valore di ritorno di 0per stringhe uguali; è considerata buona pratica confrontare esplicitamente il valore restituito 0invece di utilizzare l'operatore `! ´, es

strcmp(str1, str2) == 0 // instead of !strcmp(str1, str2)

47

Secondo C99 (Sezione 6.4.5 / 6)

Valori letterali stringa

Non è specificato se questi array siano distinti a condizione che i loro elementi abbiano i valori appropriati .

Quindi in questo caso non è specificato se entrambi "a"sono distinti. Un compilatore ottimizzato potrebbe mantenerne uno "a"nella posizione di sola lettura ed entrambi i riferimenti potrebbero fare riferimento a quello.

Controlla l'output su gcc qui


19

Perché sono 2 separati const char*, puntatori, nessun valore effettivo. Stai dicendo qualcosa del genere 0x019181217 == 0x0089178216che ovviamente restituisce NO

Usa strcmp()invece di==


7
I letterali stringa non sono puntatori, sono array. Decadono a suggerimenti sul confronto, però.
GManNickG

@Gman vero, scusa per non essere stato molto chiaro su questo, tendo a dimenticarlo :)
Antwan van Houdt

9

In poche parole, C non ha un operatore di confronto di stringhe incorporato. Non è possibile confrontare le stringhe in questo modo.

Invece, le stringhe vengono confrontate utilizzando routine di libreria standard come strcmp () o scrivendo codice per eseguire il ciclo attraverso ogni carattere nella stringa.

In C, una stringa di testo tra virgolette doppie restituisce un puntatore alla stringa. Il tuo esempio sta confrontando i puntatori e apparentemente le tue due versioni della stringa esistono a indirizzi diversi.

Ma non sta confrontando le stringhe stesse, come ti aspetti.


3

Puntatori.

Il primo "a"è un puntatore a una stringa ASCII con terminazione null.

Il secondo "a"è un puntatore a un'altra stringa ASCII con terminazione null.

Se stai usando un compilatore a 32 bit, mi aspetto "a"=="a"-4. L'ho appena provato con tcc / Win32 e ottengo "a"=="a"-2. Oh bene...


6
Perché ti aspetti che le stringhe siano allineate al limite di 4 byte? Non sono int. 2 è quello che mi aspetterei (se il compilatore non li unisce), poiché ogni stringa è lunga due byte, incluso il terminatore nullo.
Sergei Tachenov

Un certo grado di allineamento può, ad esempio, consentire strcmpl'esecuzione di più byte alla volta. Alcuni compilatori lo fanno, altri no, alcuni lo fanno solo per stringhe più lunghe di un minimo ...
zwol

@ Zack: come farebbero a conoscere la lunghezza della stringa prima di confrontarli effettivamente?
Joachim Sauer

Voglio dire, alcuni compilatori allineano stringhe più lunghe di un minimo.
zwol

1

Stai confrontando due indirizzi di memoria, quindi il risultato non sarà sempre vero. Hai provato if('a' == 'a'){...}?


1

questa domanda costituisce un'ottima scia di spiegazione per tutti i principianti ....
lasciate che anche io vi contribuisca .....

come tutti sopra hanno spiegato, perché si ottengono tali risultati.

ora se vuoi il tuo prog. Quindi stampare "sì uguale"

entrambi gli usi

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

}

oppure
non usare "a" come stringhe, usale come caratteri ....

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

in C i caratteri sono un numero intero corto di 1 byte .......


I caratteri occupano solo 1 byte, ma i caratteri letterali, come 'a', sono in realtà numeri interi.
Spidey

0

Alcuni compilatori hanno l'opzione "merge strings" che puoi usare per forzare tutte le stringhe costanti ad avere lo stesso indirizzo. Se lo usassi, "a" == "a"sarebbe true.


0

se il confronto tra i caratteri è sempre in virgolette singole, es

if('a' == 'a')

e C non può supportare il confronto di stringhe come "abc" == "abc"

È fatto con strcmp("abc","abc")


-5

Questo ragazzo non usa le variabili. Invece, utilizza temporaneamente array di testo: ae a. La ragione per cui

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

non funziona ovviamente, è che non si confrontano le variabili.
Se crei variabili come:

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

allora potresti confrontarti textcon text2, e dovrebbe essere vero

Forse non dovresti dimenticare di usare {e }=)

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

1
" e dovrebbe essere vero " - No. Non è specificato se i valori letterali stringa verranno archiviati nella stessa posizione di memoria. Leggi le altre risposte.
Spikatrix
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.