关于Scanf函数与Scanf_s带来的数据溢出的问题

 

目录

前言

一、“scanf”函数是什么?

二、“Scanf_s ”函数是什么?

三、问题再现

四、问题分析

五、解决办法 

总结



前言

今天我在编译程序的时候,有一个细节所所带来的数据溢出问题。

这一方面在老一点的教材和现有教材上是没有说明的,那就是Scanf带来的数据溢出问题。

这个BUG困扰我足足两周。

终于,在两周后的今天解决了。正所谓“在哪里跌倒就在那个地方继续趴着,休息好了再站起来。


言归正传

一、“scanf”函数是什么?

        scanf()是C语言中的一个输入函数。与printf函数一样,都被声明在头文件stdio.h里,因此在使用scanf函数时要加上#include <stdio.h>。(在有一些实现中,printf函数与scanf函数在使用时可以不使用预编译命令)它是格式输入函数,即按用户指定的格式从键盘上把数据输入到指定的变量之中

(以上词条源自“百度百科”)

int scanf(const char * restrict format,...);

        这运用一个指针指向内存来读取键盘上输入的数据给编译器,但是既然是内存那么就一点有大小。那么进而带来边界问题进而带来的是数据溢出问题。数据溢出带来的就是数据安全问题。所以比"Scanf"更安全的"Scanf_s"孕育而生......

二、“Scanf_s ”函数是什么?

        很多带“_s”后缀的函数是为了让原版函数更安全,传入一个和参数有关的大小值,避免引用到不存在的元素,有时黑客可以利用原版的不安全性黑掉系统。

(以上词条源自“百度百科”)

scanf_s( _In_z_ _Scanf_s_format_string_ char const* const _Format, ...)

 可起初我并没有重视"scanf_s"带来的数据严谨性。一直到前两周的一个''BUG'',让我不得不重视这个问题

三、问题再现

"未经处理的异常!"

四、问题分析

对于这个问题我在用''%d''的时候是没有问题的,但我在源代码这用了"%S"

关键--"%s"

扩展:"%s"是什么

说简单就是给编译器''输入输出字符串''的,什么是字符串呢?说白了就是''A、B、C、D、F、G''

可计算机却不认识''A、B、C、D、F、G''他们只知道''0'' or ''1''所以.

后来创造了“Ascll”码用来人们用来与机器交换自然语言。于是就在这里容易忽略一个内存问题。

接下来我用一张图来解释我想说的内容

各个类型的实际储存

顺着这个思路我们继续往下面看

黑框里的输入

 C:\Users\Administrator\Desktop\text.txt

假定这一串字符自然长度为X ,那么翻译成机器语言的长度大于7*x

(因为ASLLC把单个的字母翻译成7位二进制数据)

此刻在机器中编译器识别你输入了''X''长度的字符串,这个时候编译器像计算机申请了''X''长度的内存;但由于''ASLLC''的编译方式,实际到达机器内存的数据达到了''7*x''个长度.这里就会造成数据溢出

这里就会有聪明的同学就会说了,那我输入一个字符就好了。那我在这里给你们试试看

结果

结果

 

所以在这里大家看出来了?

五、解决办法 

很简单向机器申请足够的内存!

怎么申请!

用''Scanf_s''申请!

scanf_s("%s", intputfile,100);

 就是在''scanf_s''中申请100个长度

在这里需要强调一下''scanf_s''的具体用法

(来源'''百度词条'')

读取单个字符也需要限定长度:scanf_s("%c,%c",&c1,1,&c2,1);而不能写成scanf_s("%c,%c",&c1, &c2,1, 1);否则编译器会报错

六:源代码 

  • 错误代码

#include<stdio.h>

int main()
{
    char intputfile[100];  // 定义用于存储输入文件名字的字符数组

    FILE* fp;  // 定义文件指针

    printf("请输入要打开文件的名字:");
    scanf_s("%s", intputfile);  // 输入要打开的文件名字

    if (fopen_s(&fp, intputfile, "w+") != 0)  // 正确使用 fopen_s 打开文件
    {
        printf("\n%s 打开失败!\n", intputfile);
        return 0;
    }

    printf("%s 文件内容:\n", intputfile);

    while (1)  // 用一个恒真的条件进入循环
    {
        int ch = fgetc(fp);  // 获取字符
        if (ch == EOF)  // 如果是文件结束标志
            break;  // 则退出循环
        putchar(ch);  // 输出字符
    }
    printf("\n");

    fclose(fp);  // 关闭文件

    return 0;
}
  • 正确代码 

#include<stdio.h>

int main()
{
    char intputfile[100];  // 定义用于存储输入文件名字的字符数组

    FILE* fp;  // 定义文件指针

    printf("请输入要打开文件的名字:");
    scanf_s("%s", intputfile,100);  // 输入要打开的文件名字

    if (fopen_s(&fp, intputfile, "w+") != 0)  // 正确使用 fopen_s 打开文件
    {
        printf("\n%s 打开失败!\n", intputfile);
        return 0;
    }

    printf("%s 文件内容:\n", intputfile);

    while (1)  // 用一个恒真的条件进入循环
    {
        int ch = fgetc(fp);  // 获取字符
        if (ch == EOF)  // 如果是文件结束标志
            break;  // 则退出循环
        putchar(ch);  // 输出字符
    }
    printf("\n");

    fclose(fp);  // 关闭文件

    return 0;
}

总结

  • 内存溢出
  • scanf_s带来的数据安全、
  • scanf_s与scanf的区别
  • 17
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值