下面的代码我遇到了一个小问题。这是一个简单的程序,它读入2个char和int数组。然后它将所有内容存储到另一个字符串中并将其打印出来。
#include <stdio.h>
#include <string.h>
int main ()
{
char string [50];
char first [11];
char last [16];
int age = 0;
printf("Please type in your first name: ");
scanf("%s", first);
printf("Please type in your last name: ");
scanf("%s", last);
printf("Please type in your age: ");
scanf("%d", &age);
sprintf(string, "Your name is %s %s and you are %d years old.", first, last, age);
puts(string);
getchar();
getchar();
return 0;
}
现在程序运行正常,但是当我关闭它时,我收到以下错误: 运行时检查失败#2 - 变量'string'周围的堆栈已损坏。 这有点令人困惑,我无法弄清楚问题出在哪里。我会感激的 任何建议。
答案 0 :(得分:14)
您在“字符串”中写入的字符多于分配空间(即超过50个)
在添加first,last和age的值之前,"Your name is %s %s and you are %d years old."
中有37个字符。这为所有三个变量留下了13个字符。所以它会溢出到堆栈上变量'string'之后声明的其他变量。
正如Jon所说,最佳做法是使用限制写入量的函数('n'变体),否则这些函数可能是缓冲区漏洞利用的来源。
BTW'string'是一个非常糟糕的变量名称。
答案 1 :(得分:4)
除了其他任何内容之外,您还允许使用最多10个字符的姓氏和最多15个字符的姓氏。如果达到(但未超过)这些限制且年龄为两位数,则需要66个字符 - 因此您必须将string
声明为67个字符的数组才能应对(包括空值)终止子)。
除此之外,您应该使用函数或格式化字符串,这些字符串允许您限制输入的大小 - 当前如果有人输入超过10个字符(等)的名字,您将践踏其他内存。我写了任何C已经有一段时间了,但使用格式字符串“%10s”和“%15s”可能在这方面有所帮助 - 或者使用fgets
。
同样,我建议使用snprintf
(或snprintf_s
,如果它可供您使用)而不是sprintf
,以避免超出输出问题。使用所有这些方法的返回值来检测错误:)
答案 2 :(得分:2)
您可以使用
限制字符scanf读取的数量scanf("%9s", foo)
最多可读取9个字符,然后附加NUL,适用于大小为10的缓冲区。
答案 3 :(得分:1)
我猜这与string
数组的长度为50个字符这一事实有关,你在sprintf 37(如果我算对了)加上然后高达11 {{1另外16 first
,加上年龄可能是2或3。一共工作正常,一切正常,但你很可能在分配的50个字符结束后覆盖。正如你所观察到的那样,这将“有效”,但会破坏堆栈。