为什么数组接收的值多于声明要保存的值

时间:2013-07-15 14:56:21

标签: c arrays undefined-behavior

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];

为什么会这样?

6 个答案:

答案 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中是允许的,因为没有绑定检查。