strcmp
会比较字符串的内容,因此比if (str1 == str2)
会比较字符串的基地址。
如果是,为什么在下面的C代码中满足if
条件:
char *p2="sample1";
char* str[2]={"sample1","sample2"};
if(p2==str[0])
{
printf("if condition satisfied\n");
}
GDB:
(gdb) p p2
$1 = 0x4005f8 "sample1"
(gdb) p str[0]
$2 = 0x4005f8 "sample1"
(gdb) p &p2
$3 = (char **) 0x7fffffffdb38
(gdb) p &str[0]
$4 = (char **) 0x7fffffffdb20
(gdb) p *p2
$5 = 115 's'
0x4005f8
到底是什么,我该如何打印?
答案 0 :(得分:4)
未指定是否为相同的字符串文字分配不同的存储空间,或者是否将相同的存储空间用于指示字符串文字的所有用法。
在这种情况下,字符串文字"Sample1"
仅具有一个副本,并且为p2
和str[0]
分配了相同的地址。但是,标准并不能保证这一点。
引用C11
,第6.4.5章
不确定这些数组是否不同,只要它们的元素具有 适当的值。 [...]
答案 1 :(得分:2)
C语言允许静态字符串在程序中唯一。这意味着编译器可以决定是否优化静态字符串“ sample1”的分配(一次而不是一次)。
您初始化p使其指向要存放的区域,并且str [0]也是指向相同静态字符串的指针。因此,它们是否相等取决于实现方式,并且检查相等性的结果不确定。
引用6.4.5p6,字符串文字
如果这些数组的元素具有适当的值,则不确定这些数组是否不同。
答案 2 :(得分:2)
您已经声明了三个字符串:
sample1
指向的p2
sample1
指向的str[0]
sample2
指向的str[1]
这些都是“ 字符串文字”,因此无法更改,并且以只读方式存储。
允许编译器识别出您实际上只有两个唯一的字符串,因此仅存储了两个字符串(取决于实现)。
0x4005f8
到底是什么?
您在内存中发现的可能是这样的:
0x0000004005f8 's'
0x0000004005f9 'a'
0x0000004005fa 'm'
0x0000004005fb 'p'
0x0000004005fc 'l'
0x0000004005fd 'e'
0x0000004005fe '1'
0x0000004005ff '\0'
0x000000400600 's'
0x000000400601 'a'
0x000000400602 'm'
0x000000400603 'p'
0x000000400604 'l'
0x000000400605 'e'
0x000000400606 '2'
0x000000400607 '\0'
...
0x7fffffffdb20 0xf8
0x7fffffffdb21 0x05
0x7fffffffdb22 0x40
0x7fffffffdb23 0x00
0x7fffffffdb24 0x00
0x7fffffffdb25 0x00
0x7fffffffdb26 0x00
0x7fffffffdb27 0x00
...
0x7fffffffdb38 0xf8
0x7fffffffdb39 0x05
0x7fffffffdb3a 0x40
0x7fffffffdb3b 0x00
0x7fffffffdb3c 0x00
0x7fffffffdb3d 0x00
0x7fffffffdb3e 0x00
0x7fffffffdb3f 0x00
也就是说:
p2
变量:
0x7fffffffdb38
0x4005f8
str[0]
变量:
0x7fffffffdb20
0x4005f8
0x4005f8
是sample1
字符串的开头,即s
字符0x4005f9
是sample1
字符串的下一个字符,即a
字符0x4005fa
是m
0x4005fb
是p
0x4005fc
是l
0x4005fd
是e
0x4005fe
是1
0x4005ff
是\0
或“ nul ”,它终止字符串测试p2 == str[0]
时,将测试两个变量中存储的值是否相同。值是字符串的基地址。它们具有“ 相同”字符串,因此具有相同的值。
将“ 相同”字符串(即相同的文本)存储在两个不同的内存位置中是完全可行的,在这种情况下,该测试将失败。
您实际上在说两个字符串是“ 相同实例”,它们位于内存中的同一位置,因此必须具有相同的内容。
...以及如何打印?
您可以使用x/1c
一次打印为单个字符,也可以使用x/1s
打印为以n终止的字符串(gdb
可以正确处理C字符串)。
main.c
:
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[]) {
char *p2 = "sample1";
char *str[2] = { "sample1", "sample2" };
if (p2 == str[0]) {
printf("true\n");
}
return 0;
}
编译:
gcc main.c -o main -g
运行:
$ gdb ./main
[...]
(gdb) start
Temporary breakpoint 1 at 0x4005a5: file main.c, line 4.
Starting program: /home/attie/stackoverflow/56475101/main
Temporary breakpoint 1, main (argc=1, argv=0x7fffffffe418) at main.c:4
4 int main(int argc, char *argv[]) {
(gdb) list
1 #include <stdio.h>
2 #include <stdlib.h>
3
4 int main(int argc, char *argv[]) {
5 char *p2 = "sample1";
6 char *str[2] = { "sample1", "sample2" };
7
8 if (p2 == str[0]) {
9 printf("true\n");
10 }
(gdb) b 8
Breakpoint 2 at 0x4005cc: file main.c, line 8.
(gdb) c
Continuing.
Breakpoint 2, main (argc=1, argv=0x7fffffffe418) at main.c:8
8 if (p2 == str[0]) {
(gdb) print p2
$1 = 0x400684 "sample1"
(gdb) print str[0]
$2 = 0x400684 "sample1"
(gdb) print str[1]
$3 = 0x40068c "sample2"
从地址0x400684
打印三个“ 字符串”:
(gdb) x/3s 0x400684
0x400684: "sample1"
0x40068c: "sample2"
0x400694: "true"
从地址0x400684
打印16个字符:
(gdb) x/16c 0x400684
0x400684: 115 's' 97 'a' 109 'm' 112 'p' 108 'l' 101 'e' 49 '1' 0 '\000'
0x40068c: 115 's' 97 'a' 109 'm' 112 'p' 108 'l' 101 'e' 50 '2' 0 '\000'
打印存储在p2
,str[0]
和str[1]
上的地址:
(gdb) x/1a &p2
0x7fffffffe308: 0x400684
(gdb) x/1a &str[0]
0x7fffffffe310: 0x400684
(gdb) x/1a &str[1]
0x7fffffffe318: 0x40068c
答案 3 :(得分:1)
其他问题涵盖了为什么您的字符串相等(从==
运算符的角度来看),在这里我想直接解决您的问题。
0x4005f8
是存储字符串常量的地址。您可以使用printf
类型转换"%p"
打印它,该转换需要一个void*
参数,您的完整语句为:
printf("p2 = %p\n", (void*)p2);
printf("str[0] = %p\n", (void*)str[0]);
在GCC中,对void*
的强制转换不是必需的,但是可以包含它们以删除警告。是必需的,因为当您将指针作为变量参数列表的一部分传递时,编译器不会像使用原型void *
参数的函数那样将其隐式转换为void *
。