为什么在C中出现“ a”!=“ a”?


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

为什么输出No, not equal


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

47
嵌入式C编译器允许void main(),因为可能没有任何操作系统可以提供返回代码。
珍妮·平达

26
这样的问题怎么会如此频繁地受到反对?确实不是那么有趣……我的意思是,字符串是数组,数组是指针,这在C语言中确实是一顶旧帽子,不是吗?
菲利克斯·唐贝克

64
@Felix,这是一个简洁的问题,旨在解决该语言新手的常见困惑。SO不仅适合专家,还适合初学者,诸如此类的针对性问题对于将来推荐初学者很有用。
bdonlan

37
@Felix:你错了。 数组不是指针
John Dibling 2011年

Answers:


209

您正在比较的是不同字符串的两个内存地址,它们存储在不同的位置。这样做基本上是这样的:

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

使用以下代码比较两个字符串值:

#include <string.h>

...

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

此外,"a" == "a"可能确实返回true,具体取决于您的编译器,它可以在编译时将相等的字符串合并为一个以节省空间。

比较两个字符值(不是指针)时,这是一个数字比较。例如:

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

12
GCC还提供了一些选项-fmerge-constants-fno-merge-constants可以启用/禁用跨翻译单元的字符串和浮点常量合并,尽管在某些GCC上,无论使用哪种选项,似乎始终启用了常量合并。
亚当·罗森菲尔德

2
如果您使用“ a”而不是“ a”,它将起作用。第一个是字符,实际上是一个数字值。
GolezTrol 2011年

@GolezTrol:在C语言中,文字“ a”实际上具有int类型。:-)而且,指针不必一定是数字值。
BastienLéonard

int也是数字,不是吗?但是我以为char是Byte。Int是4个字节。指针本身也是整数。它们包含一堆数据的地址(实际上不必是数字的数据)。
GolezTrol

'a' == 'A' // not true... MySQL希望有所不同。
史蒂文

52

我参加聚会有点晚了,但是我还是要回答。技术上相同的比特,但是从一个不同的角度(C用语如下):

在C中,表达式"a"表示字符串文字,它是的静态未命名数组const char,长度为2-数组由字符组成,'a'并且'\0'-终止的空字符表示字符串的结尾。

但是,在C语言中,您无法通过值将数组传递给函数的方式(或在初始化后为它们赋值)的方式相同,==因为数组没有重载运算符,因此无法直接比较它们。考虑

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

如果==没有比较数组,那么它实际上是做什么的?在C语言中,几乎在所有情况下(包括该情况),数组都会衰减为指针(指向数组的第一个元素),并且比较指针的相等性符合您的期望。如此有效,在执行此操作时

"a" == "a"

您实际上是在比较两个未命名数组中的第一个字符的地址。根据C标准,比较可能会得出true或false(即1或0)"a"-s实际上可能表示相同的数组或两个完全不相关的数组。用技术术语来说,结果值是不确定的,这意味着可以进行比较(即,它不是未定义的行为或语法错误),但是其中一个值都是有效的,并且不需要实现(您的编译器)来记录实际情况。

正如其他人指出的那样,要比较“ c字符串”(即以空字符结尾的字符串),可以使用strcmp标准头文件中的便捷函数string.h。该函数的返回值为0相等的字符串。最好明确地将返回值与进行比较,0而不要使用运算符“!”,即

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

47

根据C99(第6.4.5 / 6节)

字符串文字

如果这些数组的元素具有适当的值,则不确定这些数组是否不同

因此,在这种情况下,尚不确定两个"a"s 是否都不同。经过优化的编译器可以"a"在只读位置中保留一个,而两个引用都可以引用该位置。

这里查看gcc的输出


19

因为它们是2个单独const char*的指针,所以没有实际值。你说的是这样0x019181217 == 0x0089178216,当然返回否

使用strcmp()代替==


7
字符串文字不是指针,而是数组。但是,它们在比较时会变成指针。
GManNickG 2011年

@Gman是的,很抱歉,因为不清楚这一点,所以往往会忘记:)
Antwan van Houdt 2011年

9

简而言之,C没有内置的字符串比较运算符。它不能以这种方式比较字符串。

而是使用标准库例程(例如strcmp())或通过编写代码以遍历字符串中的每个字符来比较字符串。

在C语言中,带双引号的文本字符串返回指向该字符串的指针。您的示例正在比较指针,显然您的字符串的两个版本存在于不同的地址。

但是它并没有像您期望的那样比较字符串本身。


3

指针。

第一个"a"是指向以空值结尾的ASCII字符串的指针。

第二个"a"是指向另一个以空值终止的ASCII字符串的指针。

如果您使用的是32位编译器,我会期望的"a"=="a"-4。我只是用tcc / Win32尝试过,然后得到了"a"=="a"-2。那好吧...


6
为什么会期望字符串与4字节边界对齐?他们不是整数。2是我所期望的(如果编译器不合并它们),因为每个字符串都有两个字节长,包括空终止符。
Sergei Tachenov 2011年

例如,某种程度的对齐可能允许strcmp一次运行几个字节。有些编译器会这样做,有些则不会,有些只对长度超过某些最小值的字符串进行处理……
zwol 2011年

@Zack:在实际比较它们之前,他们如何知道字符串的长度?
约阿希姆·绍尔

我的意思是,有些编译器将字符串对齐的长度大于某些最小值。
zwol 2011年

1

您正在比较两个内存地址,因此结果并不总是正确的。你尝试了if('a' == 'a'){...}吗?


1

这个问题为所有初学者设置了很好的解释路径。...
让我也为它做贡献.....

正如以上每个人所解释的,为什么会得到这样的输出。

现在,如果您想要您的编。要打印“是等于”,则

要么使用

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

}


不要将“ a”用作字符串,而应将它们用作字符。

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

在C字符中是1个字节的短整数……。


字符仅占用1个字节,但是字符文字(例如)'a'实际上是整数。
Spidey 2013年

0

一些编译器具有“合并字符串”选项,可用于强制所有常量字符串具有相同的地址。如果您将使用,"a" == "a"将为true


0

如果字符之间的比较总是用单引号引起来,例如

if('a' == 'a')

和C不能像这样支持字符串比较 "abc" == "abc"

完成了 strcmp("abc","abc")


-5

这个家伙不使用变量。相反,他使用了临时文本数组:aa。之所以

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

当然行不通,是您不比较变量。
如果要创建如下变量:

char * text =“ a”;
char * text2 =“ a”;

那么你可以比较text使用text2,它应该是真实的

也许您不应该忘记使用{}=)

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

1
,并且应该为true ”-不。未指定字符串文字是否将存储在相同的存储位置。阅读其他答案。
Spikatrix
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.