运行时检查失败 #2 - 变量“cid1”周围的堆栈已损坏
Posted
技术标签:
【中文标题】运行时检查失败 #2 - 变量“cid1”周围的堆栈已损坏【英文标题】:Run-Time Check Failure #2 - Stack around the variable 'cid1' was corrupted 【发布时间】:2013-02-18 22:25:35 【问题描述】:我是 C 编程新手,目前正在大学上课。我遇到了这个错误,并且不确定如何在谷歌数小时后修复它。我正在创建一个打印成绩报告并不断遇到此错误的程序。
代码如下:
#include <stdio.h>
#include <stdlib.h>
int main (void)
char Name[20];
char cid1[5]="", cid2[5]="", cid3[5]="", cid4[5]="", cid5[5]="", cid6[5]="";
char Description1[20]="", Description2[20]="", Description3[20]="", Description4[20]="", Description5[20]="", Description6[20]="";
int hrs1 = 0, hrs2=0, hrs3=0, hrs4=0, hrs5=0, hrs6=0;
char grade1[1]="",grade2[1]="",grade3[1]="",grade4[1]="",grade5[1]="",grade6[1]="";
printf("Enter Students Name ");
gets(Name);
printf("Enter Class ID ");
scanf("%s", &cid1);
printf("Enter Class Description ");
gets(Description1);
printf("%s", Name);
printf("%s", cid1);
printf("%s", Description1);
system("pause");
【问题讨论】:
你输入了什么值? 如果是 C,为什么还要有 C++ 标签? 【参考方案1】:scanf("%s", &cid1);
您需要致电:
scanf("%s", cid1);
并且您的数组被声明为5
元素的大小,因此如果您传递的字符数超过4
(您必须计算尾随的\0
),您将调用未定义的行为。
【讨论】:
应该没关系。指针地址相同,但类型不同。 @nneonneo:你说得对,它不会对大多数实现产生影响,但只是为了记录,它确实会导致未定义的行为。【参考方案2】:您只能读取数组支持的内容。如果您声明一个 char 数组有 5 个字节(char cid1[5]
),那么您最多可以输入 4 个字符(第 5 个是空终止符)。如果您输入更多,您将破坏内存并收到该消息。
gets
也是一个非常不安全的函数,用于从输入中读取字符串,因为无法避免缓冲区溢出。 从不使用它。使用fgets
代替stdin
。
【讨论】:
请注意,scanf
与 %s
(并且没有指定长度,即 %s
而不是 %4s
)与 gets
一样不安全。
@nneonneo 成功了!我会改用 fgets,谢谢!不过,还有一个快速的问题,在调试和输入我的信息时,我无法输入我的课程描述。它甚至没有给我提示。一旦我输入我的 cid1 后按 enter,它会打印我的名字和 cid1 以及描述应该去的空格【参考方案3】:
我不确定这是否是唯一的问题,但我马上就可以看到字符串分配存在问题。
请记住,C 中的字符串存储为一系列 char 值,以 0 结尾。这意味着五位数的课程名称将需要六个字符来保存它...类似于 'C', 'S '、'1'、'0'、'1'、'\0' 。这也意味着以字符串形式显示的单个数字等级将需要两个字符。
由于gets() 函数将该零附加到字符串的末尾,因此您的grade1[1] 数组(作为一个示例)正在溢出。它被声明保存一个字符,但正在写入两个字符。除其他外,这最终会破坏您的堆栈。我会将所有数组的大小至少再增加一个字符。
另一个问题是您没有错误检查,因此可能有人会输入超过 20 个字符的名称并导致错误,但这可能只是因为您仍在学习基础知识。在“真实”代码中,您可能永远不会使用gets()。
【讨论】:
以上是关于运行时检查失败 #2 - 变量“cid1”周围的堆栈已损坏的主要内容,如果未能解决你的问题,请参考以下文章
c++ 运行时检查失败 #2 - 变量“ToSend22”周围的堆栈已损坏