得到放置和fflush

时间:2014-07-02 12:11:31

标签: c++ c

当输入的字符串长于指定的大小时,请解释输出

#include<stdio.h>

int main()
{
  char name[21],address[31];
  puts("enter a name(max 21 characters)");
  gets(name);
  fflush(stdin);
  puts("enter an address(max 31 characters)");
  gets(address);
  fflush(stdin);
  puts("your name is:");
  puts(name);
  puts("Your address is:");
  puts(address);
  return 0;
}

2 个答案:

答案 0 :(得分:0)

当您输入超过要求的大小时,由于不检查边界,您将获得未定义的行为,并且在保留的空格之后可以(或不能,未定义的行为)写入太多的字符。你应该在C中使用fgets(有边界检查),在C ++中使用std :: getline。

答案 1 :(得分:0)

大多数C编译器会在堆栈中分配nameaddress,在内存中彼此相邻。我在Linux机器上使用GCC进行了测试,address在内存中name之后进行了测试;其他C编译器也可以反过来做。出于内存对齐的原因,编译器还可以在nameaddress之间分配几个字节的未使用空间;虽然这对于char数组来说并不常见。

我们假设address位于name之后。内存分配如下(最上面的地址):

name[0]
name[1]
name[2]
...
name[19]
name[20]
address[0]
address[1]
address[2]
...
address[29]
address[30]
base pointer
return address
stack frame of caller

正如mafso所指出的,字符串存储有一个尾随的NUL字符,因此名称最多应为20个字符(其最后一个字符位于name[19]name[20]中的NUL终结符),地址不应超过30个字符。

输入一个21个字符的名称,NUL终结符将在address[0]中,但此后不会被地址覆盖。输入21以外的任何其他字符也将被覆盖。 puts(name)将打印name中存储的21个字符,然后是用户在address中输入的内容;有效地,名称和地址连接在一起。 puts(address)将以正常方式打印地址,因为它会在address[0]开始打印。

任何输入超过30个字符的地址的尝试都会覆盖基址指针和/或返回地址,这很可能会使函数main在返回时崩溃。显然,当您输入超过51个字符的名称时也会发生同样的情况。

通过仔细制作将覆盖返回地址的多余字符,可以使程序执行除崩溃之外的其他操作。熟练的黑客可以利用这个来获得好运;这就是缓冲区溢出漏洞如此臭名昭着的原因。