项目场景:
在visual studio 2019中,练习算法笔记上一道有关成绩排序的小题,大概题意是:输入N个学生的名字,学号,成绩,然后找出最高/最低成绩的学生名字和学号。
问题描述:
在用scanf_s函数读入学生名字和学号时,总是有问题:0x7A18E63C (ucrtbased.dll)处(位于 ConsoleApplication1.exe 中)引发的异常: 0xC0000005: 写入位置 0x006BC000 时发生访问冲突。
struct studentinfo
{
char name[15];
char num[15];
int score;
}stu[100];
int main()
{
int n;
scanf_s("%d", &n);
for (int i = 0; i < n; i++) {
scanf_s("%s %s %d",&stu[i].name,&stu[i].num,&stu[i].score);//编译没有问题,运行时提示错误。
}
}
原因分析:
scanf_s()函数是Microsoft公司VS开发工具提供的一个功能相同的安全标准输入函数,大概从vc++2005以后,VS系统提供了scanf_s()。在调用该函数时,必须提供一个数字以表明最多读取多少位字符。另外,很多带“_s”后缀的函数是为了让原版函数更安全,传入一个和参数有关的大小值,避免引用到不存在的元素,防止hacker利用原版的不安全性(漏洞)黑掉系统。简单的理解,就是scanf_s会比scanf更安全,那么为了安全也需要编程者多传一些参数,这些参数就是变量的长度(占用的字节数)。
解决方案:
在用scanf_s函数时,在输入的字符串后面加上一个数字,用来表示最多读取多少位字符。在我的这个解决方案中,学生的名字和学号都是定义的一个16位数组,因此在输入的字符后面加上一个15的数字。然后运行时就没有问题了。今天一上午时间都耗在这个scanf_s的坑上了。
scanf_s("%s %s %d",&stu[i].name,16,&stu[i].num,16,&stu[i].score);
使用scanf_s时,可以这样引用:(“%s”,&name,n),整形n为name类型的大小,如果name是数组,那n就是该数组的大小。另外有一点需要注意,参数n是接收缓冲区的大小(即buf的容量),表示最多读取n-1个字符。