gets puts and fflush

gets puts and fflush

本文关键字:fflush and puts gets      更新时间:2023-10-16

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

#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;
}

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

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

假设addressname之后。内存是这样分配的(最低的地址在上面):

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]中,NUL结束符在name[20]中),地址不应超过30个字符。

输入一个21个字符的名称,NUL结束符将在address[0]中,之后立即被地址覆盖。任何超过21的额外字符也将被覆盖。puts(name)将打印存储在name中的21个字符,后面跟着用户在address中输入的字符;实际上,姓名和地址是连接在一起的。puts(address)将以正常方式打印地址,因为它在address[0]处开始打印。

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

通过精心设计将覆盖返回地址的多余字符,有可能使程序发生其他事情而不是崩溃。有技巧的黑客可以利用这带来好运;这就是为什么缓冲区溢出漏洞如此危险。