C/C++中的安全函数

首先举个例子

#include<iostream>
using namespace std;
int main(){
    char buf1[8];
    gets(buf1);
    printf("%s",buf1);
}

多数情况下,特别是我们在学习一门语言的时候,很难发现以上代码有什么问题。但是当我们把代码调整如下:

#include<iostream>
using namespace std;
int main(){
    char buf1[8];
    char buf2[3];
    gets(buf2);//注意这里对buf2进行赋值
    printf("%s\n",buf2);
    printf("%s",buf1);
}

在这里插入图片描述
奇怪的事情发生了
我们输入了abcdef,只赋值给了buf2,针对buf1并没有任何操作,但是buf1还是输出了我们不想要的值

引入正题,原因是gets导致了内存操作不安全行为
我们将代码修改如下:

#include<iostream>
using namespace std;
int main(){
    char buf1[8];
    char buf2[3];
 
    printf("%d\n",&buf2);
    printf("%d\n",&buf1);
}

在这里插入图片描述

两个变量在内存中位置如下(此处buf2在buf1前面,所以我在前面针对buf2进行操作,否则,问题就展示不出来了):
在这里插入图片描述

我们在使用了gets函数后,如果输入的字符串数量大小小于3个时,不会发生问题,但是如果输入超过3个,比如“abcdef”,则内存赋值会如下:
在这里插入图片描述

所以,即使没有对buf1没有进行操作,但是gets在操作buf2的时候,如果输入数据过大,该函数不会检查是否合理,而是会直接将多余数据覆盖到其下游内存的区域,导致,内存数据发生不可预料的篡改,因此引发了不安全行为。
所以把这类会引发内存错误的行为称为不安全行为
所以我们在实际项目中最好避免使用gets不安全函数,而替换使用具有相同功能的安全函数fgets(当然在刷算法,练习码代码速度的时候,使用不安全函数一般没什么影响)

我们再把代码调整如下:

#include<iostream>
using namespace std;
int main(){
    
    char buf1[8];
    char buf2[3];
    fgets(buf2,3,stdin);
    printf("buf2:%s\n",buf2);
    printf("buf1:%s",buf1);
}

在这里插入图片描述

使用安全函数后,即使输入参数值大于3,但是fgets会自动屏蔽多余值,而不会操作其邻近内存进行覆盖。(注意,此处buf2为“ab”,因为会自动在字符串末尾添加‘\0’空字符)
因此,可以看出安全函数fget要更安全一些。

最后说明一下:
安全函数需要指定输入字符串长度,如果在一些场合下,需要提前输入字符串长度,或者对输入参数长度提前有安全保障,则使用gets也是没有问题的。

除了gets/fgets函数外,c语言中还有其他一些经常使用的安全函数

scanf

#include<iostream>
using namespace std;
int main()
{
  char euf[4];
  char buf[4];
  scanf("%s",&buf);
  printf("buf:%s\n",buf);
  printf("euf:%s\n",euf);
}

在这里插入图片描述

由于输入的数据数量大于4,同样造成了euf内存数据被篡改,引发不安全隐患

注意:
scanf函数有三个特点:

  1. 取数据时遇到空格、回车、TAB就会停止(截取之前数据);
  2. scanf函数和都是从输入流缓冲区中读取数据的,而不是从键盘(终端)缓冲区读取值的。读取时遇到回车\n即结束,且回车\n会被读入输入缓冲数据流中,这样第二次的读入函数将输入缓冲区中的回车\n读取走了,没有等待键盘的二次输入。
  3. scanf读取字符串时,会舍弃最后的回车符。

改用如下:
char buf[5]={’\0’};
scanf_s(“%s”,buf,5); //最多读取4个字符,因为buf[4]要放’\0’
//如果输入1234567890,则buf只会接受前4个字符

待补充:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值