c-为什么在应用strcpy()并用字符串文字初始化数组后,内存的行为会有所不同



如果我使用strcpy为数组分配字符串文字,我可以很容易地访问那些超出数组边界的字节:

char sequence[4];
strcpy(sequence, "String");
printf("&sequence == %pn", &sequence);
printf("&sequence[3] == %pn", &sequence[3]);
printf("The out-of-range values are '%c' and '%c'n", *(char*)0x000000000022FE50, *(char*)0x000000000022FE51);
&sequence == 000000000022FE4C
&sequence[3] == 000000000022FE4F
The out-of-range values are 'n' and 'g'

但是,如果我做同样的事情,只是在适当的位置初始化数组,这些内存字节是空的,或者有一些意外的值:

char sequence[4] = "String";    
printf("&sequence == %pn", &sequence);
printf("&sequence[3] == %pn", &sequence[3]);
printf("The out-of-range values are '%c' and '%c'n", *(char*)0x000000000022FE50, *(char*)0x000000000022FE51);
&sequence == 000000000022FE4C
&sequence[3] == 000000000022FE4F
The out-of-range values are ' ' and 'r'

为什么strcpy和直接存储有这样的区别?

免责声明:我知道这个节目是不正确的我知道什么是未定义的行为,我知道它很糟糕,永远不应该被视为解决方案。这个问题只涉及机制,只寻求教育目的。我从来不会把它应用到任何实际任务中(如果有人那么担心的话(。

如果我使用strcpy为数组分配字符串文字,我可以很容易地访问那些超出数组边界的字节:

不,不能。这是未定义的行为。它可能会起作用。可能不会。不要那样做。每当你"可以";访问越界元素,则表示您做错了什么。

使用strncpy(sequence, "String", sizeof(sequence))可以避免这种情况

为什么strcpy和直接存储之间有这样的区别?

strcpy不知道要传递给它的数组的大小,但编译器在编译过程中知道。strcpy的一个实现可以是这样的:

char * strcpy ( char * destination, const char * source ) {
char *ret = destination;
while(source) {
*destination = *source;
destination++;
source++;
}
return ret;
}

如果初始化一个数组,这就是C标准所说的:

字符类型的数组可以由字符串文字或UTF-8字符串文字初始化,也可以用大括号括起来。字符串文字的连续字节(如果有空间或数组大小未知,则包括终止的null字符(初始化数组的元素。

如果字符串文字太长,则将忽略其余字符。请注意,这很可能会导致字符串没有零终止。因此,这不是一个有效的字符串,打印它将调用未定义的行为。然而,这个代码是可以的,即使它会发出警告:

#include <stdio.h>
int main(void)
{
char str[8]="Hi!This initializer is too long";
printf("%sn", str);
for(int i=0; i<sizeof(str); i++)
putchar(str[i]);
putchar('n');
}

它将打印:

Hi!
Hi!This

最新更新