没有 strcmp() 的字符串比较

String comparision without strcmp()

strcmp 比较字符串内容,因此它优于 if (str1 == str2),后者比较字符串的基地址。

如果是这样,为什么 if 条件在下面的 C 代码中得到满足:

    char *p2="sample1";
    char* str[2]={"sample1","sample2"};


    if(p2==str[0])
    {
            printf("if condition satisfied\n");
    }

GDB:

(gdb) p p2
 = 0x4005f8 "sample1"
(gdb) p str[0]
 = 0x4005f8 "sample1"
(gdb) p &p2
 = (char **) 0x7fffffffdb38
(gdb) p &str[0]
 = (char **) 0x7fffffffdb20
(gdb) p *p2
 = 115 's'

0x4005f8 到底是什么,我该如何打印它?

是否将相同的字符串文字分配不同的存储空间,或者使用相同的存储空间来指示字符串文字的所有用法,未指定。

在你的例子中,字符串文字 "Sample1" 只有一个副本,并且相同的地址分配给 p2str[0]。但是,标准并不能保证这一点。

引用 C11,第 6.4.5 章

It is unspecified whether these arrays are distinct provided their elements have the appropriate values. [...]

C 语言允许静态字符串在程序中是唯一的。这意味着,允许编译器决定是否优化静态字符串 "sample1".

的分配(一次而不是两次)

您将 p 初始化为指向它存放的区域,并且 str[0] 也是指向同一静态字符串的指针。因此,它们是否相等取决于实现,并且检查是否相等的结果是不确定的。

引自 6.4.5p6,字符串文字

It is unspecified whether these arrays are distinct provided their elements have the appropriate values.

其他问题已经涵盖了为什么你的字符串相等(在==运算符意义上),这里我想直接解决你的问题。

0x4005f8是存放字符串常量的地址。您可以使用 printf 类型转换 "%p" 打印它,它需要一个 void* 参数,您的完整语句将是:

printf("p2 = %p\n", (void*)p2);
printf("str[0] = %p\n", (void*)str[0]);

void* 的转换对于 GCC 不是必需的,但您可以包含它们以删除警告。 是必要的,因为当您将指针作为一个变量参数列表,编译器不会隐式地将它转换为 void *,就像对于采用原型 void * 参数的函数那样。

您已经声明了三个字符串:

  • sample1,由 p2
  • 指向
  • sample1,由 str[0]
  • 指向
  • sample2,由 str[1]
  • 指向

因为这些都是“字符串字面值”,所以无法更改,存储在read-only.

允许编译器识别您实际上只有两个唯一的字符串,因此只存储这两个字符串(这取决于实现)。


What exactly is 0x4005f8?

你会在记忆中找到的大概是这样的:

0x0000004005f8  's'
0x0000004005f9  'a'
0x0000004005fa  'm'
0x0000004005fb  'p'
0x0000004005fc  'l'
0x0000004005fd  'e'
0x0000004005fe  '1'
0x0000004005ff  '[=10=]'
0x000000400600  's'
0x000000400601  'a'
0x000000400602  'm'
0x000000400603  'p'
0x000000400604  'l'
0x000000400605  'e'
0x000000400606  '2'
0x000000400607  '[=10=]'
...
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
  • 内存地址0x4005f8sample1字符串的开始,即:s字符
  • 内存地址0x4005f9sample1字符串的下一个字符,即:a字符
  • ...0x4005fam
  • ...0x4005fbp
  • ...0x4005fcl
  • ...0x4005fde
  • ...0x4005fe1
  • ...0x4005ff[=47=] 或“nul”,它终止字符串

当你测试p2 == str[0]时,你测试两个变量中存储的值是否相同。这些值是字符串的基地址。它们持有“相同的字符串,因此持有相同的值。

将“相同”字符串(即:相同的文本)存储在两个不同的内存位置是完全可行的,在这种情况下,此测试将失败。

你在这里实际上是在说这两个字符串是“相同的实例”,它们驻留在内存中的相同位置,因此必须具有相同的内容。

... and how do I print it?

您可以使用 x/1c 一次打印单个字符,或者使用 x/1s 作为 nul-terminated 字符串打印(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/Whosebug/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
 = 0x400684 "sample1"
(gdb) print str[0]
 = 0x400684 "sample1"
(gdb) print str[1]
 = 0x40068c "sample2"

从地址 0x400684:

打印三个“strings
(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 '[=15=]0'
0x40068c:       115 's' 97 'a'  109 'm' 112 'p' 108 'l' 101 'e' 50 '2'  0 '[=15=]0'

打印存储在p2str[0]str[1]的地址:

(gdb) x/1a &p2
0x7fffffffe308: 0x400684
(gdb) x/1a &str[0]
0x7fffffffe310: 0x400684
(gdb) x/1a &str[1]
0x7fffffffe318: 0x40068c