int main(void)
{
char name1[5];
int count;
printf("Please enter names\n");
count = scanf("%s",name1);
printf("You entered name1 %s\n",name1);
return 0;
}
当我输入超过5个字符时,它打印出我输入的字符,它超过5,但char数组声明为:
char name1[5];
为什么会这样?
答案 0 :(得分:12)
因为字符存储在“存储空间”之后的地址上。这非常危险,可能导致崩溃。
E.g。假设您输入名称:Michael,name1变量从0x1000开始。
name1: M i c h a e l \0
0x1000 0x1001 0x1002 0x1003 0x1004 0x1005 0x1006 0x1007
[................................]
分配的空间显示为[...] 这意味着从0x1005内存被覆盖。
<强>解决方案:强>
仅复制5个字符(包括末尾的\ 0)或在复制之前检查输入字符串的长度。
答案 1 :(得分:6)
这是undefined behavior,您正在编写超出已分配内存的范围。任何事情都可能发生,包括似乎正常工作的程序。
C99标准草案部分J.2
未定义行为说:
在以下情况下,行为未定义:
并包含以下项目符号:
数组下标超出范围,即使某个对象显然可以使用 给定下标(如左边的表达式a [1] [7]给出声明int [4] [5])(6.5.6)。
这适用于更一般的情况,因为E1 [E2]与(*((E1)+(E2)))相同。
答案 2 :(得分:2)
这是未定义的行为,你不能指望它。它恰好工作,它可能无法在另一台机器上工作。
为避免缓冲区溢出,请使用
fgets(name1, sizeof(name1) - 1, stdin);
或在C11
gets_s(name1, sizeof(name1) - 1);
答案 3 :(得分:2)
另一个让事情更清晰的例子:
#include <stdio.h>
int array[5] ;
int main ( void )
{
array[-1] = array[-1] ; // sound strange ??
printf ( "%d" , array[-1] ) ; // but work !!
return 0 ;
}
在这种情况下,数组在一个地址中,你得到数字 在该地址之前或之后,但这是未定义的行为 除非你知道你做了什么。指针适用于++或 - !
答案 4 :(得分:1)
从其他答案中可以清楚地看出,这会对您的程序构成某种漏洞。
从中可以学到什么?让我们假设:
int func(void)
{
char buffer[1];
...
在C编译器的几乎每个实现中,此处生成的代码将创建本地堆栈区域,使您能够通过buffer
中给出的地址访问此堆栈。在此堆栈上还有其他重要数据,例如:在函数返回其调用者之后要执行的下一个代码行的地址。
因此,理论上 :
这称为 buffer overflow exploit ,您可以阅读here(以及许多其他地方)。
答案 5 :(得分:1)
是的,在C中是允许的,因为没有绑定检查。