看到一个之前一直没有意识到的问题,代码如下:
#include <stdio.h>
#include <string.h>
typedef struct helloTest {
char a[4];
char b[24];
}helloTest_t;
int main (void)
{
helloTest_t t1;
printf("address,a:%p, b:%p\n", &t1.a, &t1.b);
strcpy(t1.b, "hello world!");
strcpy(t1.a, "hello");
printf("%s\n", t1.b);
return 0;
}
思考printf输出的是什么,如果你的答案是“hello world!”,那这篇文章请接着往下看。
答案是:o
address,a:0x7fff1219ddc0, b:0x7fff1219ddc4
o
为什么呢?
看结构体中的a,b变量,其内存分布是连续的,那也就是,当我从b的首地址先拷贝“hello world!”字符串,也就是从c4地址开始,模型如下:
然后从a的首地址c0开始拷贝“hello”,内存分布则变成:
所以打印t1.b时,即从c4地址开始,遇到'\0'停止,输出:o。
#include <stdio.h>
#include <string.h>
typedef struct helloTest {
char a[4];
char b[24];
}helloTest_t;
int main (void)
{
helloTest_t t1;
printf("address,a:%p, b:%p\n", &t1.a, &t1.b);
strcpy(t1.a, "hello");
printf("%c\n", t1.a[4]);
return 0;
}
可以看到上面程序对数组a的访问,有越界行为,猜一下能编译并运行成功吗?
答案是可以,输出:o
因为结构体的内存分配是连续的,所以从数组a的首地址开始拷贝,“hello” 加上'\0'总共6个字节,是没有超过结构体总的长度的(28Byte),所以该程序不会报错,且能正常运行。
有人问,a[4]不是越界了嘛
a[4] 可以理解为:以a的首地址,也就是c0开始偏移4Byte,也就是*(t1.a+4);
这里有点离谱,在linux中编译的,竟然没有报错,且能正常运行,可能是gcc版本有点低。从而能看出strcpy这个函数有多危险,慎用!!!
请用strncpy_s(char * str2, int size2, char * str1, int size1);代替