C语言 替换gets函数

news2024/11/27 12:42:05

目录

    • 替换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);

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

noSQL的小练习

目录 Redis&#xff1a; 1、 string类型数据的命令操作&#xff1a; 2、 list类型数据的命令操作&#xff1a; 3、 hash类型数据的命令操作&#xff1a; MongoDB&#xff1a; 1. 创建一个数据库 名字grade 2. 数据库中创建一个集合名字 class 3. 集合中插入若…

Redis分片集群有什么作用?怎样读取和存储信息

分片集群主要解决的是&#xff0c;海量数据存储的问题&#xff0c;集群中有多个master&#xff0c;每个master保存不同数据&#xff0c;并且还可以给每个master设置多个slave节点&#xff0c;就可以继续增大集群的高并发能力。同时每个master之间通过ping监测彼此健康状态&…

Selenium中如何抓取网络请求响应及WebSocket信息

目录 获取Chrome性能日志 获取请求及响应信息 我们在使用Selenium测试Web或Electronjs/Cef框架应用时&#xff0c;有时候操作一个元素需要判断是否发送了请求以及请求的参数是否正确 我们可以通过&#xff0c;开启Chrome的性能日志来然后配合driver.get_log("performan…

qgis添加地理地图书签,快速定位到想要的位置

我们打开qgis软件&#xff0c;一般这个功能区域默认在左侧的中间位置&#xff0c;如图&#xff1a; 如果没有的话&#xff0c;我们需要调出来&#xff0c;在软件上方的菜单栏的空白处&#xff0c;右键显示面板调试框&#xff0c;勾选空间书签管理器面板&#xff0c;即可&…

6.3.4 利用Wireshark进行协议分析(四)----ARP协议解析

6.3.4 利用Wireshark进行协议分析&#xff08;四&#xff09;----ARP协议解析 我们知道对于单跳网络内部的数据传输&#xff0c;使用的是网络接口层的技术&#xff0c;比如以太网技术&#xff0c;以太网将报文数据封装在数据帧中进行传送&#xff0c;帧头指明发送方网卡的地址…

初学者必看!PLC转型C#上位机编程学习路线和方法

一.通过线上学习C#&#xff0c;机器视觉&#xff0c;运动控制卡&#xff0c;工程案例&#xff0c;我迈向工控软件开发的转型之路 大家好&#xff0c;我是华山编程培训中心的学员——李工&#xff0c;今天分享下我是如何从电气工程师成功转型上位机开发的经历&#xff0c;希望我…

【10】STM32·HAL库开发-MAP文件解析 | STM32启动过程

目录 1&#xff0c;MAP文件浅析&#xff08;了解&#xff09;1.1MAP文件概念和作用1.2MAP文件组成1.3MAP文件实操 2.STM32启动过程&#xff08;了解&#xff09;2.1STM32启动模式&#xff08;F1/F4/F7/H7&#xff09;&#xff08;也称自举模式&#xff09;2.1.1STM32启动模式&a…

MybatisPLus3-Activerecord

不用注入数据层对象&#xff0c;就可以实现对数据的访问和操作 具体步骤 1.实体类继承Model<实体类名> 2.mapper接口继承BaseMapper<类名> 3.通过实例化实体对象&#xff0c;就可以通过对象调用CRUD的方法 增 删除/修改/查找的方式都和上面一样

《TCP IP网络编程》第六章

《TCP IP网络编程》第六章&#xff1a;基于 UDP 的服务端/客户端 UDP 套接字的特点&#xff1a; 通过寄信来说明 UDP 的工作原理&#xff0c;这是讲解 UDP 时使用的传统示例&#xff0c;它与 UDP 的特点完全相同。寄信前应先在信封上填好寄信人和收信人的地址&#xff0c;之后…

力扣142. 环形链表 II

题目 给定一个链表的头节点head&#xff0c;返回链表开始入环的第一个节点。 如果链表无环&#xff0c;则返回null。 链接&#xff1a;142. 环形链表 II - 力扣&#xff08;LeetCode&#xff09; 题解 方法一&#xff1a;设置两个指针&#xff0c;一个指针指向链表头结点&#…

重生之我要学C++第一课

时隔三月&#xff0c;继C语言之后&#xff0c;博主学成C归来&#xff0c;欲重开博客&#xff0c;与诸位分享经验&#xff0c;共同学习&#xff0c;今天就开始我们的c第一课——入门篇。 既然要开始学习c&#xff0c;就要了解 什么是c&#xff1a; C 语言是结构化和模块化的语言…

Vue2 ➔ Vue3 都做了哪些改变?

不是吧&#xff0c;兄弟&#xff0c;Vue3 都出来多久了&#xff0c;你还对这个感兴趣&#xff0c;说&#xff01;是不是没好好卷&#xff1f;&#x1f60f; 俺也一样 &#x1f602;&#xff0c;Vue3 出来之后只是简单了解了一下&#xff0c;然后还是转头一直在写 Vue2。当然&a…

如何升级iOS17/iPadOS17公测版?iOS17公测版升级教程

苹果官方发布了iOS 17/iPadOS 17系统首个公测版更新&#xff0c;其版本号及更新内容与iOS 17 beta 3一致&#xff0c;版本号为21A5277j。 对于想升级iOS 17/iPadOS 17 公测版的用户&#xff0c;可以参考本教程进行操作。 升级注意事项&#xff1a; 1. 为防止意外情况&#xf…

AlignPS中的TOIM损失

本文介绍了CVPR2021行人重识别领域中一篇名为AlignPS论文中的TOIM损失函数 论文链接&#xff1a;https://arxiv.org/abs/2109.00211 代码链接&#xff1a;GitHub - daodaofr/AlignPS: Code for CVPR 2021 paper: Anchor-Free Person Search TOIM TOIM Loss OIM Loss Trip…

【STM32零基础入门教程02】STM32环境获取及搭建

(14条消息) 【STM32零基础入门教程01】STM32入门基础知识_小超电子笔记的博客-CSDN博客 工欲善其事必先利其器&#xff0c;在上一章了解完STM32的一些基础知识之后&#xff0c;我们需要对使用的环境进行获取和安装。 一、MDK&#xff08;KEIL&#xff09;的获取 Keil是一种…

CCF 202209-2 何以包邮? (01背包动态规划练习)

一、先温习一下01背包问题 有N件物品和一个容量为V的背包。第i件物品的体积是c[i]&#xff0c;价值是w[i]。求解将哪些物品装入背包可使价值总和最大。 条件汇总 -------- 背包限制容量&#xff1a;Z 此时背包容量&#xff1a;C 物品&#xff1a;1 , i ... …

WSA - root,frida与ida测试

本文旨在配置windows subsystem for android(win安卓子系统)来作为win在开启了hyper-v的情况下的一种轻量的安卓模拟器方案。使用MagiskOnWsa设置root权限&#xff0c;最终使其正常与开发环境、frida、ida打通。 1. Root的WSA 常用的Wsa版本在目前是没有默认root的。在物理机…

matlab滤波器设计-IIR滤波器的设计与仿真

matlab滤波器设计-IIR滤波器的设计与仿真 1 引言 在现代通信系统中&#xff0c;由于信号中经常混有各种复杂成分&#xff0c;所以很多信号的处理和分析都是基于滤波器而进行的。但是&#xff0c;传统的数字滤波器的设计使用繁琐的公式计算&#xff0c;改变参数后需要重新计…

【Matlab】智能优化算法_猎豹优化算法CO)

【Matlab】智能优化算法_猎豹优化算法CO 1.背景介绍2.数学模型2.1 搜索策略2.2 坐等策略2.3 攻击策略2.4 假设 3.文件结构4.伪代码5.详细代码及注释5.1 CO.m5.2 CO_VectorBased.m5.3 Get_Functions_details.m 6.运行结果7.参考文献 1.背景介绍 猎豹&#xff08;Achinonyx jubat…

Kubernetes部署服务到集群中的指定节点

# kubectl get node NAME STATUS ROLES AGE VERSION k8s-master Ready master 25h v1.17.3 k8s-node2 Ready <none> 25h v1.17.3 集群只有两个节点&#xff0c;这里打算将应用部署在k8s-node2节点上&#xff0c;需要先记下这个节点的…