Por que “a”! = “A” em C?

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

Por que é a saída No, not equal?

Javed Akram
fonte
100
void main??? Ew ...
Paul R
47
Compiladores C incorporados permitem void main () porque pode não haver nenhum sistema operacional ao qual fornecer um código de retorno.
Jeanne Pindar
26
Como uma pergunta como essa pode ser votada com tanta frequência? Realmente não é tão interessante ... Quero dizer, que strings são arrays e arrays são ponteiros é realmente um velho chapéu em C, não é?
Felix Dombek
64
@Felix, é uma pergunta escrita concisamente que aborda um ponto comum de confusão para os iniciantes na linguagem. O SO não é apenas para especialistas - é também para iniciantes, e perguntas direcionadas como esta são boas para indicar iniciantes no futuro.
bdonlan
37
@Felix: Você está errado. matrizes não são ponteiros
John Dibling

Respostas:

209

O que você está comparando são os dois endereços de memória para as diferentes strings, que são armazenadas em locais diferentes. Isso basicamente se parece com isto:

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

Use o seguinte código para comparar dois valores de string:

#include <string.h>

...

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

Além disso, "a" == "a"pode realmente retornar true, dependendo do seu compilador, que pode combinar strings iguais em tempo de compilação em uma para economizar espaço.

Quando você está comparando dois valores de caracteres (que não são ponteiros), é uma comparação numérica. Por exemplo:

'a' == 'a' // always true
Tim Cooper
fonte
12
GCC também tem as opções -fmerge-constantse -fno-merge-constantspara ativar / desativar corda e constante de ponto flutuante fusão entre as unidades de tradução, embora em alguns GCCs parece que fusão constante é sempre ativada, independentemente de essa opção.
Adam Rosenfield
2
Funcionaria se você usar 'a' em vez de "a". O primeiro é um char, que na verdade é um valor numérico.
GolezTrol
@GolezTrol: em C, o literal 'a' realmente tem inttipo. :-) Além disso, os ponteiros não precisam ser valores numéricos.
Bastien Léonard
inttambém é numérico, não é? Mas eu pensei que chars fossem Byte. Int tem 4 bytes. Os ponteiros em si também são inteiros. Eles contêm o endereço de um monte de dados (dados que de fato não precisam ser numéricos).
GolezTrol
'a' == 'A' // not true... O MySQL discorda.
Steven
52

Estou um pouco atrasado para a festa, mas vou atender mesmo assim; tecnicamente os mesmos bits, mas de uma perspectiva um pouco diferente (linguagem C abaixo):

Em C, a expressão "a"denota um literal de string , que é uma matriz estática não nomeada de const char, com um comprimento de dois - a matriz consiste em caracteres 'a'e '\0'- o caractere nulo de terminação sinaliza o fim da string.

Porém, em C, da mesma forma que você não pode passar arrays para funções por valor - ou atribuir valores a eles ( após a inicialização ) - não há operador sobrecarregado ==para arrays, então não é possível compará-los diretamente. Considerar

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 o ==não estiver comparando matrizes, o que ele realmente fará? Em C, em quase todos os contextos - incluindo este - os arrays decaem em ponteiros (que apontam para o primeiro elemento do array) - e a comparação de ponteiros para igualdade faz o que você esperaria. Tão eficazmente, ao fazer isso

"a" == "a"

na verdade, você está comparando os endereços dos primeiros caracteres em duas matrizes sem nome . De acordo com o padrão C, a comparação pode resultar em verdadeiro ou falso (ou seja, 1 ou 0) - "a"s pode na verdade denotar o mesmo array ou dois arrays completamente não relacionados. Em termos técnicos, o valor resultante não é especificado , o que significa que a comparação é permitida (ou seja, não é um comportamento indefinido ou um erro de sintaxe), mas qualquer um dos valores é válido e a implementação (seu compilador) não é necessária para documentar o que realmente acontecerá.

Como outros apontaram, para comparar "strings c" (ou seja, strings terminadas com um caractere nulo), você usa a função de conveniência strcmpencontrada no arquivo de cabeçalho padrão string.h. A função tem um valor de retorno de 0para strings iguais; é considerado uma boa prática comparar explicitamente o valor de retorno ao em 0vez de usar o operador `! ´, ou seja,

strcmp(str1, str2) == 0 // instead of !strcmp(str1, str2)
eq-
fonte
47

De acordo com C99 (Seção 6.4.5 / 6)

Literais de string

Não é especificado se essas matrizes são distintas, desde que seus elementos tenham os valores apropriados .

Portanto, neste caso, não é especificado se os dois "a"s são distintos. Um compilador otimizado pode manter um único "a"local somente leitura e ambas as referências podem se referir a ele.

Verifique a saída do gcc aqui

Prasoon Saurav
fonte
19

Porque são 2 const char*ponteiros separados , sem valores reais. Você está dizendo algo como o 0x019181217 == 0x0089178216que obviamente retorna NÃO

Use em strcmp()vez de==

Antwan van Houdt
fonte
7
Literais de string não são ponteiros, são matrizes. Eles decaem para indicadores de comparação, no entanto.
GManNickG
@Gman verdade, desculpe por não ter sido muito claro sobre isso, tende a esquecer :)
Antwan van Houdt
9

Simplificando, C não tem nenhum operador de comparação de string embutido. Ele não pode comparar strings dessa maneira.

Em vez disso, as strings são comparadas usando rotinas de biblioteca padrão, como strcmp () ou escrevendo código para percorrer cada caractere na string.

Em C, uma string de texto entre aspas duplas retorna um ponteiro para a string. Seu exemplo está comparando os ponteiros e, aparentemente, suas duas versões da string existem em endereços diferentes.

Mas não é comparar as próprias cordas, como você parece esperar.

Jonathan Wood
fonte
3

Ponteiros.

O primeiro "a"é um ponteiro para uma string ASCII terminada em nulo.

O segundo "a"é um ponteiro para outra string ASCII terminada em nulo.

Se você estiver usando um compilador de 32 bits, eu esperaria "a"=="a"-4. Acabei de experimentar com tcc / Win32, no entanto, e entendi "a"=="a"-2. Ah bem...

Nico57
fonte
6
Por que você esperaria que as strings fossem alinhadas ao limite de 4 bytes? Eles não são intentos. 2 é o que eu esperaria (se o compilador não os fundir), já que cada string tem dois bytes de comprimento, incluindo o terminador nulo.
Sergei Tachenov
Algum grau de alinhamento pode, por exemplo, permitir strcmpa execução de vários bytes de uma vez. Alguns compiladores fazem isso, outros não, alguns fazem isso apenas para strings maiores do que o mínimo ...
zwol
@Zack: como eles saberiam o comprimento da string antes de realmente compará-los?
Joachim Sauer
Quero dizer, alguns compiladores alinham strings mais longas do que o mínimo.
zwol
1

Você está comparando dois endereços de memória, então o resultado nem sempre será verdadeiro. Você tentou if('a' == 'a'){...}?

SK9
fonte
1

esta questão estabelece um caminho de explicação muito bom para todos os iniciantes ....
deixe-me também contribuir com isso .....

como todos explicaram acima, por que você está obtendo tal saída.

agora se você quiser seu prog. Para imprimir "sim igual" então

ou use

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

}

ou
não use "a" como strings, use-os como caracteres ....

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

em C os caracteres são um inteiro curto de 1 byte .......

N-JOY
fonte
Os caracteres ocupam apenas 1 byte, mas os literais de caracteres, como 'a', na verdade, são inteiros.
Spidey de
0

Alguns compiladores têm a opção 'merge strings' que você pode usar para forçar todas as strings constantes a terem o mesmo endereço. Se você usasse isso, "a" == "a"seria true.

Daniel Mošmondor
fonte
0

se a comparação entre os caracteres estiver sempre em aspas simples, por exemplo

if('a' == 'a')

e C não pode suportar comparação de strings como "abc" == "abc"

Acabou com strcmp("abc","abc")

Bhavin Patel
fonte
-5

Esse cara não usa variáveis. Em vez disso, ele usa matrizes de texto temporariamente: ae a. A razão porque

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

não funciona é claro, é que você não compara variáveis.
Se você criar variáveis ​​como:

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

então você pode comparar textcom text2, e deve ser verdade

Talvez você não deva se esquecer de usar {e }=)

void main() {
    if("a" == "a")
    {
      printf("Yes, equal");
    }
    else
    {
      printf("No, not equal");
    }
}
D. Ace
fonte
1
" e deve ser verdadeiro " - Não. Não é especificado se os literais de string serão armazenados no mesmo local de memória. Leia as outras respostas.
Spikatrix