二维字符数组的三种输入方式浅析(scanf()、gets()和fgets())

news2024/10/5 15:28:29

二维字符数组的输入

目录

  • 二维字符数组的输入
    • 1.scanf函数
      • 知识点
      • scanf()关于回车的问题:
    • 2.gets函数
    • 3.fgets函数
    • 参考链接


1.scanf函数

知识点

按照常规输入数组的办法,通过 for 循环实现

  • 将整个字符串输入时,在数组名前不加&(eg:scanf("s",str[i])
  • 一个一个字符输入时,在数字名前加&(eg:scanf("%c",&str[i][j])

结束:当遇到回车,空格和tab键结束

对末尾的处理:编译时会自动在字符串后面添加’\0’

缓冲区:回车,空格和tab键仍会留在输入的缓冲区中。

缺点:

  • 以空格作为结束,无法识别空格
  • 因其对缓存区的处理,可能会导致被后面的scanf吸收,即将回车赋值给后面的字符型变量。
    可在其后用getchar()将回车吸收
    (仅在下一次scanf()输入的是字符型时才考虑,因为回车符是转义符,归属于字符型数据,因此scanf()可将之作为输入)

scanf()关于回车的问题:

首先要搞清楚一个概念,空格、回车、制表Table都是空白字符,空白字符不仅仅是空白字符;

1.对于%d类型的输入,scanf默认的分割符是所有的空白字符。也就是说如果一个scanf函数中出现scanf("%d%d",&a,&b),那么用任何一个空白字符来分隔两个整数a,b的值,变量a,b都可以接收到正确的输入。且scanf会忽略输入数据项前面的空白字符。

2.对于%c类型的输入,scanf默认所有字符都是需要接收的字符,包括所有的空白字符也会被接收。也就是说如果一个scanf函数中出现scanf("%c%c",&a,&b),那么输入c t,最后a是c,b是,t是接收不了的;

3.对于%s类型的输入,scanf默认的分割符是所有的空白字符。scanf对于字符串输入的处理和对整数类似,会忽略前导的空白字符,而且默认的分隔符是所有的空白字符。
- 这里需要详细讲一下
- 比如scanf("%[^\n]",s);这句代码的意思是除了回车键,其余都接收放进s字符串里面。如果你打了回车,回车不会被接收进字符串s里面,回车之前的所有字符包括空格都会被放进字符串s里面。
- 那么,这个回车呢?它会一直被留在缓存里面,只要不动这个缓存,他会一直在。此时scanf的返回值是1(如输入:abc\n)或者0(如输入:\n)。

演示一
以逐个字符的形式进行二维字符数组的输入
image-20221229112505147
可见在输入num的值后,下方程序不再进行。
因为我们知道scanf通过回车符判断结束,因此可知该程序不再进行的原因是输入num后的回车被保存在缓冲区,下一步for循环中scanf就从缓冲区将这个回车符读走,认为程序结束。

演示二
以逐行字符串的形式进行二维字符数组的输入
image-20221229113347214
可见每一步都能够正常运行。

上述两个演示验证了:

  • scanf输入的回车符会被保存在缓存区中
  • scanf输入不是直接从标准输入(即键盘)读取,而是从缓存区读取
  • 需要考虑scanf回车问题的情况仅有下一次scanf是以字符型输入的,而当下一次是字符串型、整数型、浮点数型……都不需要考虑。

2.gets函数

char str[100];
gets(str);
//即gets(数组名或指针)

gets()函数从标准输入(键盘)读入,经常和puts()函数配对使用,puts()函数用于显示字符串,并自动在字符串后面添加一个换行标志’\n’

接收:gets能够接受空格、制表符Tab、回车等;

结束:遇到回车认为输入结束

对末尾的处理:自动用’\0’替代’\n’

缓冲区:回车键不会留在输入缓冲区中

缺点:

  • 因为 gets 函数没有限制输入的字符串长度

  • 函数 gets 可以无限读取,不会判断上限,所以程序员应该确保 buffer 的空间足够大,以便在执行读操作时不发生溢出。也就是说,gets 函数并不检查缓冲区 buffer 的空间大小,事实上它也无法检查缓冲区的空间

    如果函数的调用者提供了一个指向堆栈的指针,并且 gets 函数读入的字符数量超过了缓冲区的空间(即发生缓存区溢出(buffer overflow)),gets 函数会将多出来的字符继续写入堆栈中,这样就覆盖了堆栈中原来的内容,破坏一个或多个不相关变量的值。

    当用户在键盘上输入的字符个数大于缓冲区 buffer 的最大界限时,gets 函数也不会对其进行任何检查,因此我们可以将恶意代码多出来的数据写入堆栈。因此,gets 函数是极其不安全的,可能成为病毒的入口。

    因此,尽管该函数书写简单,仍然建议尽可能不使用gets()

在使用gets()函数做二维字符数组的输入时,可采用如下方式(再次声明不建议使用gets(),此处仅作演示):

char str[10][20];
int i=0;
for(i=0;i<10;++i){
gets(str[i]);
}

3.fgets函数

fgets()函数作为危险函数gets的代替

char *fgets(char *buf, int bufsize, FILE *stream);
  • 第一个参数:为字符数组数组名或字符型指针
  • 第二个参数bufsize:限制了读取的字符的个数,这就可以解决gets()函数的缺陷。
  • 第三个参数:
    • fgets函数主要用于读取文件,此时为文件结构体指针
    • 如果要读取键盘,则stream参数应该为stdin
    • 在读取过程中,发生以下三种情况时,读取停止:
      1. 发现换行符
      2. 发现文件终结符EOF
      3. 发生错误

需要注意的是,如果bufsize设置为n,那么fgets函数最多读取n-1个字符,之所以用“最多”这个词是因为,如果在之前遇到了换行符,fgets函数也会返回。

还有一点就是,fgets()函数会读取换行符这一点和gets函数不同),当读取结束后,fgets函数会为buf在末尾添加一个空字符作为字符串的结束。换行符同样会被读入,且在’\0’前,为’\n\0’的形式。

在使用fgets函数从键盘输入二维字符数组时,可采用如下方法:

char str[10][81];
int i=0;
for(i=0;i<10;++i){
fgets(str[i],81,stdin);
}

关于处理fgets函数尾部回车符的问题,请移步下方链接:
C语言中fgets()函数回车符相关的问题


参考链接

1.gets和fgets函数及其区别,C语言gets和fgets函数详解 (biancheng.net)
2.C语言中scanf函数与空格回车
3.(4条消息) 为什么有些情况下scanf后面要跟一个getchar?_热爱编程的大忽悠的博客-CSDN博客_scanf后面getchar

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

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

相关文章

Java 基础进阶篇(二)—— static 静态关键字与单例模式

文章目录 一、static 静态关键字1.1 静态成员变量与实例成员变量1.2 静态成员方法与实例成员方法1.3 static 访问注意事项1.4 内存使用情况 二、工具类三、代码块四、单例模式4.1 饿汉单例4.2 懒汉单例 一、static 静态关键字 static&#xff1a;代表静态的意思&#xff0c;可…

Java 基础进阶篇(六)—— 接口详解

文章目录 一、接口概述二、接口的基本使用三、接口从 JDK 8 开始新增的方法四、接口的注意事项&#xff08;了解&#xff09;补充&#xff1a;接口与接口的关系 一、接口概述 规范的基本特征是约束和公开。 接口就是一种规范&#xff0c;其约束别人必须干什么事情。 所以&…

【五一创作】Matlab 绘制风速、风向统计玫瑰花图【优化】

在之前&#xff0c;有个博客专门讲matlab 绘制风速、风向统计玫瑰花图&#xff1b;这里面存在不少细节问题&#xff0c;目前对该部分代码做了优化。以前的博客链接见下&#xff1a; Matlab 绘制风速、风向统计玫瑰花图 最近接了一个任务&#xff0c;需要绘制风速、风向的统计玫…

Java 基础进阶篇(五)—— 抽象类与模板方法设计模式

文章目录 一、抽象类、抽象方法概述二、抽象类的特征三、模板方法设计模式3.1使用场景3.2 实现步骤3.3 写作文案例 补充&#xff1a;final 和 abstract 是什么关系? 一、抽象类、抽象方法概述 在 Java 中 abstract 是抽象的意思&#xff0c;可以修饰类、成员方法。 abstract …

Java 基础进阶篇(七)—— 面向对象三大特征之三:多态

文章目录 一、多态的概述二、多态中成员访问特点 ★三、多态的优势与劣势四、多态下的类型转换4.2 自动类型转换&#xff08;从子到父&#xff09;4.2 强制类型转换&#xff08;从父到子&#xff09;4.3 instanceof 关键字 一、多态的概述 多态&#xff1a;是指执行同一个行为…

Java 基础进阶篇(四)—— 权限修饰符、final 关键字与枚举

文章目录 一、权限修饰符二、final 关键字2.1 final 作用2.2 final 修饰变量举例2.3 常量 三、枚举3.1 枚举的格式3.2 枚举的特征3.3 枚举的应用 一、权限修饰符 权限修饰符 用于约束成员变量、构造器、方法等的访问范围。 权限修饰符&#xff1a; 有四种作用范围由小到大 (p…

Java 基础进阶篇(三)—— 面向对象的三大特征之二:继承

文章目录 一、继承概述二、内存运行原理 ★三、继承的特点四、继承后&#xff1a;成员变量和方法的访问特点五、继承后&#xff1a;方法重写六、继承后&#xff1a;子类构造器的特点七、继承后&#xff1a;子类构造器访问父类有参构造器八、this、super 总结 一、继承概述 Jav…

机器学习之利用SMO算法求解支持向量机—基于python

大家好&#xff0c;我是带我去滑雪&#xff01; 本期将讨论支持向量机的实现问题&#xff0c;我们知道支持向量机的学习问题可以化为求解凸二次规划问题。这样的凸二次规划问题具有全局最优解&#xff0c;并且有许多最优化算法可以用于这一问题的求解。但是当训练样本容量很大…

【C++】 探索程序 详细解读程序在运行过程中都发生了什么

目录 头文件-源代码 头文件重复包含 问题 解决方案 程序生成过程 预处理Preprocessi 编译Compilation 汇编Assembly 链接Linking 编译期-运行期 编译期确定 运行期确定 编译期错误 运行期错误 类和对象 宏 宏的其他用法 inline内联 头文件-源代码 头文件&…

Vue简介和常用指令

概述&#xff1a; MVVM思想&#xff1a;视图层数据和数据模型里面的数据发生变化都会影响到另一边的数据&#xff0c;通过ViewModel自动实现。 Vue入门案例 步骤&#xff1a; 上面提到了数据模型和试图层的数据是关联的&#xff0c;此处数据模型里面el的值就是选择了哪一个视…

jQuery引入----练习

jQuery引入----练习 html <!DOCTYPE html> <html><head><title>jQuery引入</title><!-- css样式引入 --><link rel"stylesheet" href"../css/a.css"><!-- jquery函数库引入 --><script type"tex…

Linux基础IO【深入理解文件系统】

✨个人主页&#xff1a; 北 海 &#x1f389;所属专栏&#xff1a; Linux学习之旅 &#x1f383;操作环境&#xff1a; CentOS 7.6 阿里云远程服务器 文章目录 &#x1f307;前言&#x1f3d9;️正文1、磁盘文件2、磁盘概念2.1、基本结构2.2、数据存储 3、磁盘信息3.1、分区意义…

【C++初阶】类与对象:6大默认成员函数------拷贝构造和赋值运算符重载

一.拷贝构造函数 A.概念 拷贝构造函数&#xff1a;只有单个形参&#xff0c;该形参是对本类类型对象的引用(一般常用const修饰)&#xff0c;在用已存在的类类型对象创建新对象时由编译器自动调用。 B.特性 1. 拷贝构造函数是构造函数的一个重载形式&#xff1b; 2. 拷贝构造函…

shell的基础学习二

文章目录 一、Shell 数组二、Shell 基本运算符三、Shell echo命令四、Shell printf 命令五、Shell test 命令总结 一、Shell 数组 数组中可以存放多个值。Bash Shell 只支持一维数组&#xff08;不支持多维数组&#xff09;&#xff0c;初始化时不需要定义数组大小&#xff08…

【五一创作】【Simulink】基于FCS-MPC的三相并网逆变器控制(Stateflow)

上次写了一篇【Simulink】基于FCS-MPC的三相并网逆变器控制&#xff08;Matlab Function&#xff09;&#xff0c;控制部分用 Matlab Function 写的&#xff0c;因实验室一般用 Stateflow&#xff0c;所以这篇把 Matlab Function 改成 Stateflow. 原理 电路原理图&#xff1a;…

如何批量查询快递的签收状态?

如果一次性网购大量快递&#xff0c;我们就得经常进入快递或网购平台查询物流&#xff0c;随时查看快递单号的物流状态。如果快递公司少&#xff0c;查询起来比较容易&#xff0c;但是如果快递公司很多&#xff0c;每次都要人工查询就是一件很麻烦的事情了。今天&#xff0c;小…

数据库相关知识

一.1 数据库 与Sybase不同&#xff0c;一个用户就对应于一个数据库。 create user CBMAIN identified by "sunline" default tablespace CBMAIN_DATA  -- 表空间 temporary tablespace CBMAIN_TEMP; -- 临时表空间 一.2 表空间 表空间由一个或多个物理文件组成&…

js使用splice方法删除数组元素可能导致的问题

splice() 方法通过删除或替换现有元素或者原地添加新的元素来修改数组&#xff0c;并以数组形式返回被修改的内容。此方法会改变原数组。 JavaScript 遍历数组并通过 splice 方法删除该数组符合某些条件的元素将会导致哪些问题&#xff1f; 导致的问题 当使用 splice 方法从 …

QT 中的多线程之继承 Thread

文章目录 1. 概述2. UML 类的关系图3. 代码&#xff1a;4. 运行结果及说明5. 结语 1. 概述 任何继承于QThread的线程都是通过继承 QThread 的run函数来实现多线程的&#xff0c;因此&#xff0c;必须重写QThread的run函数&#xff0c;把复杂逻辑写在QThread的run函数中。然后在…

effective c++ item40-44

item40:谨慎的使用多重继承 多重继承带来的符号的歧义性 #include <iostream> #include <vector> using namespace std; class A { public:void f() { cout << "A" << endl; } }; class B { private:void f(); }; class C : public A, publ…