¿Por qué “a”! = “A” en C?

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

¿Por qué es la salida No, not equal?

Javed Akram
fuente
100
void main??? Ew ...
Paul R
47
Los compiladores de C integrados permiten void main () porque puede que no haya ningún sistema operativo al que dar un código de retorno.
Jeanne Pindar
26
¿Cómo se puede votar a favor una pregunta como esta con tanta frecuencia? Realmente no es tan interesante ... quiero decir, que las cadenas son matrices y las matrices son punteros es realmente un viejo sombrero en C, ¿no?
Felix Dombek
64
@Felix, es una pregunta escrita de manera concisa que aborda un punto común de confusión para los recién llegados al idioma. SO no es solo para expertos, también es para principiantes, y preguntas específicas como esta son buenas para recomendar a los principiantes en el futuro.
bdonlan
37
@Felix: Estás equivocado. las matrices no son punteros
John Dibling

Respuestas:

209

Lo que está comparando son las dos direcciones de memoria para las diferentes cadenas, que se almacenan en diferentes ubicaciones. Hacerlo esencialmente se ve así:

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

Utilice el siguiente código para comparar dos valores de cadena:

#include <string.h>

...

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

Adicionalmente, "a" == "a" puede devolver verdadero, dependiendo de su compilador, que puede combinar cadenas iguales en tiempo de compilación en una para ahorrar espacio.

Cuando está comparando dos valores de caracteres (que no son punteros), es una comparación numérica. Por ejemplo:

'a' == 'a' // always true
Tim Cooper
fuente
12
GCC también tiene las opciones -fmerge-constantsy -fno-merge-constantspara habilitar / deshabilitar la fusión constante de cadena y punto flotante entre unidades de traducción, aunque en algunas GCC parece que la fusión constante siempre está habilitada independientemente de esa opción.
Adam Rosenfield
2
Funcionaría si usa 'a' en lugar de "a". El primero es un char, que en realidad es un valor numérico.
GolezTrol
@GolezTrol: en C, el literal 'a' en realidad tiene inttipo. :-) Además, los punteros no tienen que ser valores numéricos.
Bastien Léonard
inttambién es numérico, ¿no? Pero pensé que los caracteres eran Byte. Int es 4 bytes. Los punteros en sí mismos también son números enteros. Contienen la dirección de un montón de datos (datos que de hecho no tienen que ser numéricos).
GolezTrol
'a' == 'A' // not true... MySQL pide diferir.
Steven
52

Llego un poco tarde a la fiesta, pero voy a responder de todos modos; técnicamente los mismos bits, pero desde una perspectiva un poco diferente (lenguaje C a continuación):

En C, la expresión "a"denota un literal de cadena , que es una matriz estática sin nombre de const char, con una longitud de dos: la matriz consta de caracteres 'a'y'\0' - el carácter nulo de terminación señala el final de la cadena.

Sin embargo, en C, de la misma manera que no puede pasar matrices a funciones por valor, o asignarles valores ( después de la inicialización ), no hay un operador sobrecargado ==para matrices, por lo que no es posible compararlas directamente. 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

Si ==no está comparando matrices, ¿qué hace realmente, entonces? En C, en casi todos los contextos, incluido este, las matrices se descomponen en punteros (que apuntan al primer elemento de la matriz), y comparar punteros para la igualdad hace lo que cabría esperar. Tan efectivamente, al hacer esto

"a" == "a"

en realidad, está comparando las direcciones de los primeros caracteres en dos matrices sin nombre . De acuerdo con el estándar C, la comparación puede dar como resultado verdadero o falso (es decir, 1 o 0); "a"s en realidad puede denotar la misma matriz o dos matrices completamente no relacionadas. En términos técnicos, el valor resultante no está especificado , lo que significa que la comparación está permitida (es decir, no es un comportamiento indefinido o un error de sintaxis), pero cualquiera de los valores es válido y la implementación (su compilador) no es necesaria para documentar lo que realmente sucederá.

Como han señalado otros, para comparar "cadenas c" (es decir, cadenas terminadas con un carácter nulo) se utiliza la función de conveniencia que se strcmpencuentra en el archivo de encabezado estándar string.h. La función tiene un valor de retorno de 0para cadenas iguales; se considera una buena práctica comparar explícitamente el valor de retorno en 0lugar de usar el operador `! ´, es decir

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

Según C99 (Sección 6.4.5 / 6)

Literales de cadena

No se especifica si estas matrices son distintas siempre que sus elementos tengan los valores adecuados .

Entonces, en este caso, no se especifica si ambos "a"son distintos. Un compilador optimizado podría mantener un solo"a" en la ubicación de solo lectura y ambas referencias podrían hacer referencia a eso.

Mira el resultado en gcc aquí

Prasoon Saurav
fuente
19

Porque son 2 const char*punteros separados , sin valores reales. Estás diciendo algo como 0x019181217 == 0x0089178216que por supuesto devuelve NO

Usar en strcmp()lugar de==

Antwan van Houdt
fuente
7
Los literales de cadena no son punteros, son matrices. Sin embargo, se convierten en indicadores en comparación.
GManNickG
@Gman es cierto, lo siento por no ser muy claro en eso, tienden a olvidarlo :)
Antwan van Houdt
9

En pocas palabras, C no tiene un operador de comparación de cadenas incorporado. No puede comparar cadenas de esta manera.

En su lugar, las cadenas se comparan usando rutinas de biblioteca estándar como strcmp () o escribiendo código para recorrer cada carácter de la cadena.

En C, una cadena de texto entre comillas dobles devuelve un puntero a la cadena. Su ejemplo es comparar los punteros y, aparentemente, sus dos versiones de la cadena existen en diferentes direcciones.

Pero no se trata de comparar las cadenas en sí, como parece esperar.

Jonathan Wood
fuente
3

Punteros.

El primero "a"es un puntero a una cadena ASCII terminada en nulo.

El segundo "a"es un puntero a otra cadena ASCII terminada en nulo.

Si está utilizando un compilador de 32 bits, lo esperaría "a"=="a"-4. Sin embargo, acabo de probarlo con tcc / Win32 y lo tengo "a"=="a"-2. Oh bien...

Nico57
fuente
6
¿Por qué esperaría que las cadenas se alineen con el límite de 4 bytes? No son ints. 2 es lo que esperaría (si el compilador no los combina), ya que cada cadena tiene dos bytes de longitud, incluido el terminador nulo.
Sergei Tachenov
Algún grado de alineación puede permitir, por ejemplo, strcmpejecutar varios bytes a la vez. Algunos compiladores lo hacen, otros no, algunos lo hacen solo para cadenas más largas que un mínimo ...
zwol
@Zack: ¿cómo sabrían la longitud de la cadena antes de compararlos?
Joachim Sauer
Quiero decir, algunos compiladores alinean cadenas más largas que un mínimo.
zwol
1

Estás comparando dos direcciones de memoria, por lo que el resultado no siempre será cierto. Lo intentaste if('a' == 'a'){...}?

SK9
fuente
1

esta pregunta establece un muy buen rastro de explicación para todos los principiantes ...
permítanme contribuir también .....

como explicaron todos los anteriores, por qué obtiene tal salida.

ahora si quieres tu prog. Para imprimir "sí igual" entonces

o use

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

}

o
no use "a" como cadenas, úselas como caracteres ....

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

en C los caracteres son un entero corto de 1 byte .......

N-ALEGRIA
fuente
Los caracteres ocupan solo 1 byte, pero los literales de caracteres, como 'a', son en realidad números enteros.
Spidey
0

Algunos compiladores tienen la opción 'fusionar cadenas' que puede usar para forzar que todas las cadenas constantes tengan la misma dirección. Si usaras eso, "a" == "a"lo sería true.

Daniel Mošmondor
fuente
0

si la comparación entre caracteres está siempre entre comillas simples, p. ej.

if('a' == 'a')

y C no puede soportar la comparación de cadenas como "abc" == "abc"

Esta hecho con strcmp("abc","abc")

Bhavin Patel
fuente
-5

Este tipo no usa variables. En su lugar, usa matrices de texto temporalmente: ay a. La razón por la cual

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

Por supuesto que no funciona, es que no se comparan variables.
Si crea variables como:

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

entonces podrías comparar textcon text2, y debería ser cierto

Quizás no deberías olvidarte de usar {y }=)

void main() {
    if("a" == "a")
    {
      printf("Yes, equal");
    }
    else
    {
      printf("No, not equal");
    }
}
D. Ace
fuente
1
" y debería ser verdadero " - No. No se especifica si los literales de cadena se almacenarán en la misma ubicación de memoria. Lea las otras respuestas.
Spikatrix