C语言 替换gets函数

目录

    • 替换gets函数
      • gets()用处
      • gets()的危险之处
      • gets()的几种替代方法
        • 一、用%c循环输入直到遇到换行结束
        • 二、用getchar()循环输入直到遇到换行结束
        • 三、scanf的另一种用法
        • 四、c++中的getline()方法
        • 五、解决方案使用fgets代替

替换gets函数

gets()用处

gets从标准输入设备读字符串函数,其可以无限读取,不会判断上限,可以包含空格,以回车结束读取。

gets()的危险之处

因为该函数可以无限读取,所以应该确保buffer的空间足够大,以便在执行读操作时不发生溢出。如果溢出,多出来的字符将被写入到堆栈中,这就覆盖了堆栈原先的内容,破坏一个或多个不相关变量的值。这个事实导致gets函数只适用于玩具程序。

gets()的几种替代方法

既然gets()的用处是用来读取一个包含空格的字符串,那么我们就有了以下几种方法来代替gets():

一、用%c循环输入直到遇到换行结束

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<string>
using namespace std;
int main()
{
    char str[100];
    char ch;
    int i=0;
    while(scanf("%c", &ch) && ch != '\n')
    {
        str[i++] = ch;
    }
    cout << str << endl;
    return 0;
}

我们可以用上面的方法来读取一个包含空格的字符串,但是实际操作中遇到了下面的情况:

在这里插入图片描述

从图片中可以看出,我们给str输入的是“123 456 789”,但是输出结果却并不是我们想要的,这是为什么呢?

答案很简单,当我们输出str字符串的时候,系统是以’\0’符号来判断一个字符串的末尾的,我们输入遇到’\n’的时候就跳出循环了,所以后面的内容是不可预知的,直到遇到’\0’才停止输出。

要怎样解决呢?

更简单了,既然字符串需要以’\0’结束,那我们只需要把字符串的末尾的那个字符手动赋值为’\0’即可:

#include<iostream>
#include<stdio.h>
#include<string.h>
using namespace std;
int main()
{
    char str[100];
    char ch;
    int i=0;
    while(scanf("%c", &ch) && ch != '\n')
    {
        str[i++] = ch;
    }
    str[i] = '\0';    //手动吧字符串末尾字符赋值成'\0'
    cout << str << endl;
    return 0;
}

这个时候我们再来验证一下,发现问题就解决了:

在这里插入图片描述

二、用getchar()循环输入直到遇到换行结束

这个方法从原理是跟上面的方法是一样的,只是写法不一样,下面直接放上参考代码:(值得注意的是末尾仍要赋成’\0’)

#include<iostream>
#include<stdio.h>
#include<string.h>
using namespace std;
int main()
{
    char str[100];
    char ch;
    int i=0;
    while((ch = getchar()) != '\n')
    {
        str[i++] = ch;
    }
    str[i] = '\0';    //手动吧字符串末尾字符赋值成'\0'
    cout << str << endl;
    return 0;
}

三、scanf的另一种用法

我们知道用scanf的%s可以用来输入一个字符串,但是%s遇到空格之后便停止了,不能达到输入空格的效果,所以我们可以使用另一种方法:

scanf("%[^\n]%*c", str);

看似很复杂的一句代码,下面我们来解读一下:

这句话的意思是碰见了回车就退出,然后把缓冲区里面的内容按字符串格式输入str中,回车依然留在缓冲区。

其中"%[^\n]"表示读入一个字符串,遇到'\n'停止,并设置末尾的'\0'。^ 是“非”的意思,意思就是说把一个非“\n”字符读入字符串,直到遇到“\n”停止输入。

而“%*c”呢,则是代表读入一个字符到缓冲区,但是不向任何地方输入。这样,就解决了字符串后边的“\n”对下面数据的影响,如果不加“%*c”的话,则大多数情况下需要在scanf前加一句getchar()来消除回车的影响。

附:

其实所有对%s起作用的控制都可以用%[],比如%[0-9]表示只读入'0'到'9'之间的字符,%[a-zA-Z]表示只读入字母,'-'是范围连接符,当然也可以直接列出你需要读入的字符。
如果你只需要读"abc"里面的字符就可以用%[abc] (或者%[cab]、%[acb]、%[a-c]、%[c-a].....),
如果想读入某个范围之外的字符串就在前面加一个'^',如:%[^a-z]就表示读入小写字母之外的字符。

例如从键盘输入的"1235ab86"中读取1235、86给n,有如下方法:

#include <stdio.h>
bool skip(){
     scanf("%*[^0-9]");
     return true;
}
void main()
{
      int n;
      while(skip() && scanf("%d", &n)!=EOF)
        printf("%d\n", n);
}

输出为:

1235

86

四、c++中的getline()方法

getline不是C库函数,而是gcc的扩展定义或者C++库函数。它会生成一个包含一串从输入流读入的字符的字符串。

具体用法:

getline(cin, str);

需要注意的是,str字符串必须是C++中的string字符串类型

也就是说必须包含头文件

#include<string>

并且str必须定义为string类型

string str;

需要注意的是,既然str定义的是string类型,则说明求字符串长度函数strlen()将不再可用,C++提供了另一种方法:

int len = str.size();

下面来验证一下:

在这里插入图片描述

五、解决方案使用fgets代替

fgets(temp,sizeof(temp),stdin);   

gets 已被弃用,因为它很危险,可能会导致缓冲区溢出。

解决方案

//接收用户输入,gets函数已经被弃用,这里替换成fgets函数,由于fgets函数会读入回车,这里将回车去掉
fgets(msg.data, sizeof(msg.data), stdin);
//printf("%s", msg.data);
msg.data[strlen(msg.data) - 1] = '\0';
//printf("-------------\n");
//printf("%s", msg.data);

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/41305.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

C# Linq 详解四

目录 概述 二十、SelectMany 二十一、Aggregate 二十二、DistinctBy 二十三、Reverse 二十四、SequenceEqual 二十五、Zip 二十六、SkipWhile 二十七、TakeWhile C# Linq 详解一 1.Where 2.Select 3.GroupBy 4.First / FirstOrDefault 5.Last / LastOrDefault C# Li…

truffle 进行智能合约测试

本方法使用了可视化软件Ganache 前两步与不使用可视化工具的步骤是一样的&#xff08;有道云笔记&#xff09;&#xff0c;到第三步的时候需要注意&#xff1a; 在truffle插件下找到networks目录&#xff0c;提前打开Ganache软件 在Ganache中选择连接或者新建&#xff0c;我在…

软件测试测试用例

等价类&#xff1a;把输入的数据可以分为有效的数据和无效的数据 被测试的对象输入的数据&#xff1a; 1、有效的数据 2、无效的数据 测试一个产品&#xff0c;需要考虑它的正确场景&#xff0c;也需要考虑它的异常场景 边界值:边界值测试用例是针对等价类测试用例方法的补…

每天一道C语言编程:排队买票

题目描述 有M个小孩到公园玩&#xff0c;门票是1元。其中N个小孩带的钱为1元&#xff0c;K个小孩带的钱为2元。售票员没有零钱&#xff0c;问这些小孩共有多少种排队方法&#xff0c;使得售票员总能找得开零钱。注意&#xff1a;两个拿一元零钱的小孩&#xff0c;他们的位置互…

Thymeleaf + Layui+快速分页模板(含前后端代码)

发现很多模块写法逻辑太多重复的&#xff0c;因此把分页方法抽取出来记录以下&#xff0c;以后想写分页直接拿来用即可&#xff1a; 1. 首先是queryQrEx.html&#xff1a; <!DOCTYPE html> <html xmlns:th"http://www.w3.org/1999/xhtml"> <head>…

zabbix监控自己

目录 一、实验环境准备 二、server端 1、配置阿里云yum源 2、部署lamp环境 3、启动lamp对应服务 4、准备java环境 5、源码安装zabbix 6、mariadb数据库授权 7、创建zabbix程序用户并授权防止权限报错 8、修改zabbix配置文件 9、配置php与apache 10、web安装zabbix …

Qgis3.16ltr+VS2017二次开发环境搭建(保姆级教程)

1.二次开发环境搭建 下载osgeo4w-setup.exeDownload QGIShttps://www.qgis.org/en/site/forusers/download.html 点击OSGeo4W Network Installer 点击下载 OSGeo4W Installer 运行程序 osgeo4w-setup.exe&#xff0c;出现以下界面&#xff0c;点击下一页。 选中install from i…

uniapp中超好用(且免费)的安全类插件推荐!(持续更新中)

前几天写了一篇【干货分享】uniapp做的安卓App如何加固&#xff0c;发现收藏的人蛮多的。所以说&#xff0c;更加证明了我说的第一个问题&#xff1a;现在用uniapp的人是越来越多了。 而通过使用uniapp上自带的插件&#xff0c;也是能够实现事半功倍的效果&#xff0c;让不懂前…

OpenCv之图像形态学(二)

目录 一、形态学梯度 二、顶帽操作 三、黑帽操作 一、形态学梯度 梯度原图 - 腐蚀腐蚀之后原图边缘变小&#xff0c;原图 - 腐蚀 就可以得到腐蚀掉的部分&#xff0c;即边缘 案例代码如下: import cv2 import numpy as np# 导入图片 img cv2.imread(6.jpg)# 注意调节kern…

ubuntu打开usb摄像头

文章目录 前言一、识别 usb 摄像头二、安装应用程序显示摄像头捕捉到的视频1、使用应用程序茄子&#xff08;cheese&#xff09;2、运行 cheese 捕捉视频 前言 记录一下解决在 Linux 下打开 usb 摄像头界面黑屏的问题。 一、识别 usb 摄像头 1、保持在 ubuntu 界面&#xff0…

leetcode 965.单值二叉树

⭐️ 题目描述 &#x1f31f; leetcode链接&#xff1a;单值二叉树 思路&#xff1a; 让当前的根节点与左孩子节点与右孩子节点判断&#xff0c;若相等则继续向下分治&#xff0c;让左孩子与右孩子当作新的根节点继续判断&#xff0c;直到某个节点不相等。 1️⃣ 代码&#x…

相机标定学习笔记

Kalibr 是标定工具中&#xff0c;唯一一个可以标定camToImu的&#xff0c;是vio必不可少的工具&#xff0c;其他的都有替代品。所以学习多种开源算法进行相机标定&#xff0c;并记录学习相机标定的过程。 一、相机标定 1、在场景中放置一个已知的物体 &#xff08;1&#xff…

【DBA课程-笔记】第 3 章:MongoDB数据库核心知识

内容 一、MongoDB 数据库架构 A. MongoDB数据库体系架构 1. 存储引擎&#xff08;MongoDB Storage Engines&#xff09;&#xff1a; 2. MongoDB 数据逻辑架构 二、MongoDB 存储引擎 A. 查看mongodb服务器的状态 B. 查看引擎信息&#xff08;4.2.1 没有这个命令&#xf…

实例019 以图形按钮显示的界面

实例说明 菜单和工具栏虽然能方便用户操作程序的相应功能&#xff0c;但各有缺点。如果采用按钮式功能菜单&#xff0c;不但美观大方&#xff0c;而且操作灵活。当单击按钮时&#xff0c;用户区将显示相应的操作按钮组。下面介绍图形界面式菜单的设计方法。运行本例&#xff0…

ceph集群(二)

ceph 一、资源池 Pool 管理二、创建 CephFS 文件系统 MDS 接口三、创建 Ceph 块存储系统 RBD 接口四、创建 Ceph 对象存储系统 RGW 接口五、OSD 故障模拟与恢复 一、资源池 Pool 管理 上次我们已经完成了 Ceph 集群的部署&#xff0c;但是我们如何向 Ceph 中存储数据呢&#x…

餐饮行业油烟监控管理系统设计与应用

安科瑞 华楠 摘 要&#xff1a;餐饮油烟污染问题已经成为城市环境污染的重要污染源&#xff0c;本研究的油烟在线监测数据管理信息系统是油烟在线监测数据采集仪的配套软件&#xff0c;用于展现现场端数据采集仪采集的数据&#xff0c;对数据采集仪进行远程控制&#xff0c;以…

vue-cli多页面配置(vue2.0)

目录 概述 多页面的配置 步骤1&#xff1a;编写配置文件 vue.config.js 步骤2&#xff1a;在src目录下创建目录pages 步骤3&#xff1a;创建HTML文件&#xff08;主组件挂载点&#xff09; 测试 完毕&#xff0c;总结 概述 我们知道使用vue脚手架vue-cli创建的项目默认是…

基于IPC-CFX的点对点通信C#

IPC-CFX有两种主要的通信方式&#xff0c;可以通过RabbitMQ发布和订阅&#xff0c;也可以通过request和response进行点对点的通信&#xff0c;本文主要讲的是点对点的通信方式。 在vscode里建立新的dotnet项目&#xff0c;可以通过终端输入dotnet new console来建立&#xff0c…

如何实现CAN-SOME/IP通信路由测试

区别于基于UDP的车内通信路由&#xff0c;基于SOME/IP协议的路由增加了服务发现&#xff08;Service Discovery&#xff09;和服务发布&#xff08;Service Publish&#xff09;&#xff0c;那对于测试工程师来说&#xff0c;怎么实现CAN-SOME/IP路由的测试呢&#xff1f; 01 …

网络安全面试题

以下为网络安全各个方向涉及的面试题&#xff0c;星数越多代表问题出现的几率越大&#xff0c;祝各位都能找到满意的工作。 注&#xff1a;本套面试题&#xff0c;已整理成pdf文档&#xff0c;但内容还在持续更新中&#xff0c;因为无论如何都不可能覆盖所有的面试问题&#xf…