C 语言中"=="的用法的几个问题?

2015-04-02 09:51:28 +08:00
 herozem

先看测试用例:

#include <stdio.h>

int main(int argc, char *argv[])
{
  char *s = "hello";
  char *str = "hello";

  printf("compare pointers: ");
  s == str ? printf("y") : printf("n"); #(1)
  printf("\ncompare arguments: ");
  argv[1] == argv[2] ? printf("y") : printf("n"); #(2)
  printf("\nuse strcmp :");
  strcmp(&argv[1], &argv[2]) ? printf("y") : printf("n"); #(3)

  return 0;
}

运行结果:

$ ./a.out tmp tmp
compare pointers: y
compare arguments: n
use strcmp :y

确切的来说是想解决一些关于C和内存知识的问题:

在代码中, (1)比较的两个字符串, s和str在内存中是不同的指向char的指针, 但是他们指向的内容实际上是同一处?

(2)中比较的内容结果是不相等, "=="号比较的是所给参数的内存地址吗?
(3)的输出结果为y, 所以strcmp比较的是指针所指向的内容?

1844 次点击
所在节点    C
30 条回复
Andiry
2015-04-02 10:00:00 +08:00
1) s 和 str是常量指针,指向同一个地址,所以s == str
2) Yes
3) Yes
zhicheng
2015-04-02 10:01:01 +08:00
1,是
2,是
3,是
herozem
2015-04-02 10:03:06 +08:00
g5tf87
2015-04-02 10:03:08 +08:00
(1)里两个hello被编译在全局数据区,应该是被编译器优化为同一个地址,所以s和str两个指针指向的内容是一样的,输出为y。
(2)里面两个参数由于函数调用,其内容先后被存入栈上,所以argv[1]和arg[2]也是指针,指向的内容是不一样的,输出为n。
(3)通过字符串比较函数,比较字符串的内容,argv[1]和arg[2]指向的内容是一样的,所以输出为y。

一点粗浅见解,如有错误,希望高手指导交流~~~
wartime
2015-04-02 10:13:59 +08:00
1. s 和 str 指向同一字符串常量, 地址值相等 (编译时确定);
2. 命令行参数不同,内存地址不同;
3. strcmp 比较两块内存里从第一个字节开始,到值为'\0'结束的字符串是否相等, 有可能溢出;

如果定义成:
char s[] = "hello";
char str[] = "hello";
s != str, 此时s和str会被分配size为strlen("hello") + 1的新内存地址。
liuhaotian
2015-04-02 10:19:54 +08:00
是的。比较的是指向内容。
The C library function int strcmp(const char *str1, const char *str2) compares the string pointed to by str1 to the string pointed to by str2.

顺便问一下 markdown这个代码高亮是怎么做到的?
herozem
2015-04-02 10:28:49 +08:00
@liuhaotian 三个反单引号(数字键1左边那个), 后接bash、c、java之类的, 代码完以后另起一行再接三个反单引号

```bash
```bash
#不知道嵌套会被解析成什么样子?
```
```
mcone
2015-04-02 10:32:11 +08:00
如果我没记错的话,你在(1)里面的这种比较是很危险的,不同编译器在不同优化等级下面输出的结果很可能不一样(undefined behavior?)

好久没用过这个了,如有错误望楼下指出!
herozem
2015-04-02 10:34:57 +08:00
@wartime 我试了一下,对于

```c
char s1[] = "hello";
char s2[] = "hello";
```

无论是使用s1 == s2 还是 strcmp(s1, s2) 结果都是n, 这其中的原因是?
herozem
2015-04-02 10:38:07 +08:00
@herozem 不过回复好像不支持Markdown, 或者是我打开方式不正确 :(
herozem
2015-04-02 10:38:54 +08:00
@mcone 这个我不太清楚, 不知道有没有相关的讲解的书籍或资料
bugeye
2015-04-02 10:44:38 +08:00
用gcc -S xxx.c 生成汇编,然后看汇编就明白了
$ cat test.s
.file "test.c"
.section .rodata
.LC0:
.string "hello"
.LC1:
.string "compare pointers: "
.LC2:
.string "y"
.LC3:
.string "n"
.LC4:
.string "\ncompare arguments: "
.LC5:
.string "\nuse strcmp :"
.text
.globl main
.type main, @function
main:

看吧,只有一个"hello",所以两个指针的内容是一样的。但这种比较方法是危险的。如果生成的汇编很傻,那么结果就变了。
herozem
2015-04-02 10:49:56 +08:00
@bugeye 不懂汇编, 没想到可以这样看 :(
walleL
2015-04-02 11:04:37 +08:00
strcmp(&argv[1], &argv[2]) ? printf("y") : printf("n");

大家都没发现这一行有问题吗?
1. argv[1] 已经是指向第一个参数字符串的指针了,&argv[1] 是干嘛呢
2. strcmp() 的返回值为0时才表示相等啊

所以这样才对吧:
strcmp(argv[1], argv[2]) == 0 ? printf("y") : printf("n");
walleL
2015-04-02 11:06:38 +08:00
@herozem 所以9楼的问题也是 strcmp() 返回值判断的原因吧
hualuogeng
2015-04-02 11:10:27 +08:00
@herozem 请注意strcmp在字符串相等时,返回值是0,所以你用strcmp作为条件表达式的条件时,结果和你要的是相反的。
原文中的3,之所以相等,是因为还是比较的指针本身的值,因为不相等,所以才printf("y")
这也就能够解释你在9楼的疑问了。
hualuogeng
2015-04-02 11:11:54 +08:00
上一条回复中 "原文中的3,之所以相等" 应表述为”原文中的3,之所以输出y"
herozem
2015-04-02 11:12:12 +08:00
@walleL :) thank you so much! &argv[1]确实是不对的
herozem
2015-04-02 11:13:34 +08:00
@hualuogeng 嗯, 是这样的, 谢谢
hualuogeng
2015-04-02 11:18:36 +08:00
@walleL 你也发现这个问题了。

@herozem 另外,关于C的内存和指针,我记得有一本《C缺陷和陷阱》还不错。还有《专家编程》《C和指针》也不错

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/181027

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX