在C语言中使用"=="运算符比较字符数组

4

我知道在C语言中比较“字符串”的正确方法是使用strcmp,但现在我尝试使用==运算符来比较一些字符数组,结果得到了一些奇怪的结果。

请看下面的代码:

int main()
{
    char *s1 = "Andreas";
    char *s2 = "Andreas";

    char s3[] = "Andreas";
    char s4[] = "Andreas";

    char *s5 = "Hello";

    printf("%d\n", s1 == s2); //1
    printf("%d\n", s3 == s4); //0
    printf("%d\n", s1 == s5); //0
}

请问为什么第一个printf返回了1(即它们相等),但是比较字符数组时,==返回了0?请有人解释一下。

你应该将比较的结果显式地转换为int类型。由于你使用了%d,printf会在栈上查找int的大小(通常为4个字节),但bool通常只有1个字节。 - Richard Simões
双足机器人:C语言的可变参数函数推广规则可以很好地处理这个问题,而且你为什么认为“==”会产生布尔值而不是整数呢? :P - Roger Pate
根据变长参数转换规则,当bool作为变长参数时,将隐式提升为int - 参见5.2.2[expr.call]/7和4.5[conv.prom]/4。 - Pavel Minaev
7个回答

20

双等号比较的是内存地址。
很可能你的编译器为了节省空间而使s1和s2指向相同的静态数据。

例如,在代码的前两行中,“Andreas”存储在可执行文件的数据中。C标准表示这些字符串是常量,因此已经优化了这两个指针以指向相同的存储空间。

char[]行通过将数据复制到变量中创建变量,因此在执行过程中存储于不同的堆栈地址中。


这都是编译器优化导致的吗? - Andreas Grech
2
我非常确定这是标准的要求,即在同一翻译单元(标准术语中的“文件”)中相同的字符串字面量必须具有相同的存储位置。 - Andy Ross
2
安迪:不需要,6.4.5/6(C99):“这些数组是否不同是未指定的…” - Roger Pate
+1 感谢您解释比较字符数组与比较指针时结果不一致的差异。 - Andreas Grech
这些字符串是否需要符合标准,是只读的吗? - Martin Beckett
显示剩余2条评论

4

嗯...当==打印出1时,它表示它们是相等的。这与strcmp不同,后者返回字符串的相对顺序。


2

您正在比较地址而不是字符串。前两个是常量,只会被创建一次。

int main()
{
    char *s1 = "Andreas";
    char *s2 = "Andreas";

    char s3[] = "Andreas";
    char s4[] = "Andreas";

    char *s5 = "Hello";

    printf("%d\n", s1 == s2); //1
    printf("%p == %p\n", s1, s2);
    printf("%d\n", s3 == s4); //0
    printf("%p != %p\n", s3, s4);
    printf("%d\n", s1 == s5); //0
    printf("%p != %p\n", s1, s5);
}

在我的电脑上输出,但你可以理解这个想法:

1
0x1fd8 == 0x1fd8
0
0xbffff8fc != 0xbffff8f4
0
0x1fd8 != 0x1fe0

1

从s1到s5的所有值都不是char本身,它们是指向char的指针。因此,您比较的是每个字符串的内存地址,而不是字符串本身。

如果您这样显示地址,就可以看到比较运算符实际上正在处理什么:

#include <stdio.h>

int main() {
  char *s1 = "Andreas";
  char *s2 = "Andreas";

  char s3[] = "Andreas";
  char s4[] = "Andreas";

  char *s5 = "Hello";

  printf("%p\n", s1); // 0x80484d0
  printf("%p\n", s2); // 0x80484d0
  printf("%p\n", s3); // 0xbfef9280
  printf("%p\n", s4); // 0xbfef9278
  printf("%p\n", s5); // 0x80484d8
}

字符串在内存中的分配位置是与实现相关的。在这种情况下,s1和s2指向同一个静态内存块,但我不希望这种行为具有可移植性。


是的,那是一个字符串池优化。我不会指望它。 - Nosredna

1

等一下... 1 表示真,0 表示假。所以你的解释部分是相反的。至于为什么前两个字符串看起来相等:编译器只构建了常量字符串(s1/2)一次。


哦对了,你是正确的;我还在想着 strcmp,并且我反转了值! - Andreas Grech

1

s1 == s2 表示 "(char*) == (char*)" 或者地址相同。

s3 == s4 也是一样的。这就是 "数组衰变为指针" 的作用。

而且你对比较结果的含义理解有误:

0 == 0; /* true; 1 */
42 == 0; /* false; 0 */
"foo" == "bar"; /* false (the addresses are different); 0 */

0

你不能比较字符串,但可以比较指针。


是的,我知道。 :-) 我的意思是使用比较运算符。 :-) - Nosredna

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接