c语言 gets函数 puts函数
char c[3]
gets (c);
puts(c);
我输入了好几十个字符,本来以为会出现溢出之类的错误,但是还是可以原样输出,难道数组的长度没有用吗?不会溢出吗? 展开
数组的长度当然有用了。你给数组指定多大,这里就的字符串长度容纳量就是多大。
越界访问是语言的未定义行为,不能依赖于这种行为。(即使看起来有时候它不出错)
你这里程序没有出现问题,仅仅是巧合而已。具体什么时候溢出会影响程序执行,取决于平台和编译器实现。
打个比方,如果有个变量紧跟在数组后面,数组越界了,那么这个变量就会被改变。
我给一个例子:
#include <stdio.h>
int main(int argc, char *argv[])
{
char str[3];
char c = 'x';
printf("Key in str: ");
gets(str);
printf("str = %s, c = %c\n", str, c);
return 0;
}
我使用 64 位 Linux 编译运行的结果如图。若看不清楚请右键点开原图。
左下角窗口显示了执行情况:
第一次,我输入了16个字符,结果和 str 无关的 c 变成了 我输入末尾的 'F',这正是我输入的第 16 个字符(从零算是15)
第二次,我输入了15个字符,结果 c 变成了 '\0',而C语言数组末尾的 '\0' 也是正是 str 的第 16 位,即 str[15] (下标从零开始)
第三次,我输了 14 个字符,加上末尾的 \0 是 15 个。此时 c 没有被改变,仍然是 ‘x'.
可以猜想。str 和 c 在内存上相差 15 个字节(因为 sizeof(char) 正好 1 字节)。
把程序用 objdump 反汇编(右上窗口)。可以看出:
movb $0x78, -0x1(%rbp) 这一句对应的就是 C 语言的 char c = 'x', 字符x 的 ascii 码是十六进制 78. 所以可以看出,c 的地址是 %rbp 寄存器储存量左移 0x1 字节,你可以理解成坐标为 -1;
从 gets(str) 调用下面的汇编代码可以找到, 而 str 的地址为 %rbp 寄存器储存量左移 0x10 字节,也就是十进制的 -16。
这二者正好相差 15, 验证了我们的猜想。
纯手工码字截图,望采纳。