关于字符串比较char*和数组字符串之间差异的说明
好吧,我想我知道指针和内存操作的一切,但有一件事我很好奇。到目前为止,我只将字符串与strcmp进行了比较,但是 这个表达式是正确的:关于字符串比较char*和数组字符串之间差异的说明,c,arrays,string,pointers,C,Arrays,String,Pointers,好吧,我想我知道指针和内存操作的一切,但有一件事我很好奇。到目前为止,我只将字符串与strcmp进行了比较,但是 这个表达式是正确的: #include <stdio.h> int main() { char* str1 = "I love StackOverflow"; // dram memory alocated char* str2 = "I love StackOverflow"; if(str1 == str2) printf("%s and
#include <stdio.h>
int main()
{
char* str1 = "I love StackOverflow"; // dram memory alocated
char* str2 = "I love StackOverflow";
if(str1 == str2) printf("%s and %s are equal", str1, str2);
else printf("%s and %s are not equal", str1, str2);
return 1;
}
相反,它不会输出它们是相等的。为什么?在第一个示例中,绝对不能保证两个指针相等。这是编译器利用字符串文本在C中是不可变的这一事实执行的优化 C99基本原理文件说: 此规范允许实现共享具有相同文本的字符串副本,将字符串文本放入只读内存,并执行某些优化
您不应该依赖于此,如果您想在第一个或第二个代码段中比较字符串,请使用
strcmp
/strncmp
函数。一些编译器试图通过存储相同字符串文本的单个副本来减少内存需求
在您的例子中,编译器可能会选择只存储一次
“I love StackOverflow”
,使str1
和str2
都指向它。因此,当比较str1==str2时,基本上是比较指向字符串文字的第一个元素(而不是字符串本身)的指针,该元素可能指向上述相同的位置,从而得出两个字符串文字相等的结果。你不能依赖它 在char*
变量的情况下,编译器可能会使用字符串“unification”(抱歉,我不确定它实际上是如何调用的),这意味着它检测相同的字符串常量,并且只分配其中的每个常量一次。这意味着第一个代码被编译为
char common_string_detected_1[] = "I love StackOverflow";
char* str1 = common_string_detected_1;
char* str2 = common_string_detected_1;
和str1
和str2
包含相同的指针,即数组中“I”的地址
在后一种情况下,您显式声明两个数组,编译器将它们分开。我可以向您展示在gcc上编译的程序集列表 c++ asm 现在使用
[]
LC0:
.ascii "%s and %s are not equal\0"
...
mov DWORD PTR [esp+43], 1869357129
mov DWORD PTR [esp+47], 1394632054
mov DWORD PTR [esp+51], 1801675124
mov DWORD PTR [esp+55], 1919252047
mov DWORD PTR [esp+59], 2003790950
mov BYTE PTR [esp+63], 0
mov DWORD PTR [esp+22], 1869357129
mov DWORD PTR [esp+26], 1394632054
mov DWORD PTR [esp+30], 1801675124
mov DWORD PTR [esp+34], 1919252047
mov DWORD PTR [esp+38], 2003790950
mov BYTE PTR [esp+42], 0
lea eax, [esp+22]
mov DWORD PTR [esp+8], eax
lea eax, [esp+43]
mov DWORD PTR [esp+4], eax
// loads the effective address off the stack of the data for both strings
// notice these two address are different, because both strings sit in different places on the stack
// it doesn't even bother comparing them and has removed the "is equal" string
mov DWORD PTR [esp], OFFSET FLAT:LC0
call _printf
是的,我一整天都在用strcmp。。当我意识到简单的比较是有效的。。我在思考时遇到了麻烦。@Edenia如果
str1==str2
然后str1+1==str2+1
,你怎么会感到惊讶呢?@Edenia确实如此,只要你取消引用它,否则它只是一个地址,在本例中是字符串中数据的第一个字节,添加另一个字节只会给出完全相同的地址加上另一个字节,这样它就指向从第二个字节开始的地址。。根据所有人的意见。。使用这种比较方法没有问题。可能是错误的做法。我没有说这是一个问题,我只是试图解释char*str1
和char*str2
即使单独定义和初始化也可能相等。如果这是真的。。我做了一个测试,其中我使用了:if(&str1[1]=&str2[1])
但是。。它给了我同样的结果——它们是相等的。@Edenia:是的,str1
等于str2
当且仅当&str1[1]
等于&str2[1]
。是的,如果str1
等于str2
,那么您可以相信字符串是相等的。但它不是反过来工作的:有可能,str1
不等于str2
,并且它们指向相同的字符串。@haccks我从指针地址中看到,测试情况如何。@Edenia;那有什么问题吗?@haccks没有问题。:)
char* str1 = "I love StackOverflow";
char* str2 = "I love StackOverflow";
if(str1 == str2) printf("%s and %s are equal", str1, str2);
else printf("%s and %s are not equal", str1, str2);
LC0: // LC0 - LC1 - LC2 these are labels
.ascii "I love StackOverflow\0"
LC1:
.ascii "%s and %s are equal\0"
LC2:
.ascii "%s and %s are not equal\0"
...
mov DWORD PTR [esp+28], OFFSET FLAT:LC0
mov DWORD PTR [esp+24], OFFSET FLAT:LC0 // moves exact same address into stack
mov eax, DWORD PTR [esp+28] // immediately moves one of them into eax
cmp eax, DWORD PTR [esp+24] // now compares the exact same addresses (LC0)
jne L2 // (jump if not equal)
// followed by code that prints if equal then L2 label(followed by code that prints if not equal)
LC0:
.ascii "%s and %s are not equal\0"
...
mov DWORD PTR [esp+43], 1869357129
mov DWORD PTR [esp+47], 1394632054
mov DWORD PTR [esp+51], 1801675124
mov DWORD PTR [esp+55], 1919252047
mov DWORD PTR [esp+59], 2003790950
mov BYTE PTR [esp+63], 0
mov DWORD PTR [esp+22], 1869357129
mov DWORD PTR [esp+26], 1394632054
mov DWORD PTR [esp+30], 1801675124
mov DWORD PTR [esp+34], 1919252047
mov DWORD PTR [esp+38], 2003790950
mov BYTE PTR [esp+42], 0
lea eax, [esp+22]
mov DWORD PTR [esp+8], eax
lea eax, [esp+43]
mov DWORD PTR [esp+4], eax
// loads the effective address off the stack of the data for both strings
// notice these two address are different, because both strings sit in different places on the stack
// it doesn't even bother comparing them and has removed the "is equal" string
mov DWORD PTR [esp], OFFSET FLAT:LC0
call _printf