前言:
那是在我一个日常写代码的过程中,我先写了如下的代码:
char string[16] = { 0 };
int* strlen = (int*)malloc(sizeof(int));
*strlen = 0;
然后在我使用scanf()函数并打算输出结果时
scanf("%s",string);
while(string[(*strlen)])
(*strlen)++;
printf("输入的字符串长度为%d",*strlen);
free(strlen);
突然一个奇怪的数字出现了。
思考:
我是输入较短的字符串时问题就没有出现,但当输入字符串过长就出现bug了。很明显就是过长导致的问题,不过我在输入二十多个字节的字符串是,却是正常显示了。
查看内存和反汇编:
比如我输入二十一个'd'(在二进制的ascii码为100,也就是0x64)(并且地址为该次string字符串的首地址)
可以看到,而且scanf函数接收字符串时,是完全接收了字符串然后再接收完成之后加个0('\0'),但分配给字符串string的大小有30字节(不知道为什么不是16,不过这也在某种程度上提高了scanf的容错率)。
可能的危险:
这种一股脑全吸收字符串的行为十分危险,因为它可能会覆盖掉该栈空间(甚至超出)以下的数据,甚至在使用堆的时候不仅会把记录堆数据的地址的指针覆盖掉,还会因为覆盖掉地址的堆数据泄露。而我在前言的时候使用堆的分配也正是展现了这一风险
最后:
这种scanf函数的隐患想必一定是有人指出来了(不然也不会有scanf_s()函数的存在),不过我在这记录下来。一来是为了提醒为了可能犯错的我,二来也是希望更多人知道scanf函数的隐患(在我上c语言课的时候老师一次也没有提到这种隐患)。
PS:
这里我举例我的环境所在(Windows 11,Microsoft Visual Studio)的标准库scanf函数,因为不同操作系统的标准库实现可能是不同的,所以在别的操作系统中的scanf就很安全。这也就是我为什么标题会写“window中的<stdio.h>中scanf()函数的隐患”了