✨前言
C语言系列:博主是初次做这种,可能有一些不足之处,希望大家帮忙指出!说明一下该系列是对c语言从0到1的介绍😶🌫️,后续我会出汇总篇进行全面的综合整理。作为一个系统的教程,这个系列会持续推新的,所以关注博主🍻,在学习C语言的路上结伴前行吧!
🐶📑作者:@ Serein橘橘橘
🐶🐋专栏:C语言
🐶👤资源推荐:C语言程序设计从入门到进阶
🐶🚀一句话:该做的只求结果,想做的只问本心
文章目录
一、printf ☃️
在C语言系列的初识C语言博客里(没看过?点这里),我们已经见识到了printf这个库函数,接下来我将带大家具体地学习一下printf函数
1.基本用法
printf() 的作用: 将参数⽂本输出到 标准输出设备 (通常是屏幕)。它名字⾥⾯的 f 代表 format (格式化),表示可以定制输出文本的格式。
Tip:printf() 是在标准库的头文件 stdio.h 定义的。使用这个函数之前,必须在源码文件头部引入这个头文件。下面用代码来演示一下👇
•
printf() 不会在行尾自动添加换行符
,运行结束后,光标就停留在输出结束的地方,不会⾃动换行
• 为了让光标移到下⼀行的开头,可以在输出文本的结尾,添加⼀个换行符\n
• 如果文本内部有换行,也是通过插⼊换行符来实现
2.占位符
% + 占位符的类型:占位符的第一个字符一律为百分号%,第二个字符表示占位符的类型
①含义
printf可以在输出文本中指定占位符。所谓 ”占位符“,就是这个位置可以用其他值代入。现在我们用代码演示一下:👇
如上:There are %d apples\n 是输出文本,里面的%d 就是占位符,它用于打印整数
printf()的第二个参数就是替换占位符的值,因此%d的位置会被后面的参数10替换。%s用于打印字符串(同理)
🌈我相信有人就要疑惑了,那什么是参数呢,只能使用一个占位符吗?下面来解答 !!!
输出文本里面可以使用多个占位符
上述输出文本 %s says it is %d o’clock\n 有两个占位符,第一个是字符串占位符%s,第二个是整数占位符%d,分别对应 printf() 的第二个参数(lisi)和第三个参数(10)
• printf() 参数与占位符是一一对应的关系
•有n个占位符 ,printf() 的参数就有 n+1 个
• 参数个数少于对应的占位符,printf() 可能会输出内存中的任意值
②常见的占位符
printf() 的占位符有许多种类,与C语⾔的数据类型相对应,常用占位符大全都看过来拉👇
占位符 | 含义 |
---|---|
%a | ⼗六进制浮点数,字⺟输出为⼩写 |
%A | 十六进制浮点数,字符输出为大写 |
%c | 字符 // char |
%d | 十进制整数 // int |
%e | 使用科学计数法的浮点数,指数部分的e为小写 |
%E | 使用科学计数法的浮点数,指数部分的E为大写 |
%i | 整数,基本等同于%d |
%f | 小数(包含float类型和double类型) float - %f double - %lf |
%g | 6个有效数字的浮点数。整数部分一旦超过6位,就会自动转为科学计数法,指数部分的e为小写 |
%G | 等同于%g,指数部分的E为大写 |
%hd | 十进制 short int 类型 |
%ho | 八进制 short int 类型 |
%hx | 十六进制 short int 类型 |
%hu | unsigned short int 类型 |
%ld | 十进制 long int 类型 |
%lo | 八进制 long int 类型 |
%lx | 十六进制 long int 类型 |
%lu | unsigned long int 类型 |
%lld | 十进制 long long int 类型 |
%llo | 八进制 long long int 类型 |
%llx | 十六进制 long long int 类型 |
%llu | unsigned long long int 类型 |
%Le | 科学计数法表示的long double 类型浮点数 |
%Lf | long double 类型浮点数 |
%n | 已输出的字符串数量。该占位符本身不输出,只将值存储在指定变量之中 |
%o | 八进制整数 |
%p | 指针(用来打印地址) |
%s | 字符串 |
%u | 无符号整数(unsigned int) |
%x | 十六进制整数 |
%zd | size_t类型 |
%% | 输出一个百分号 |
3.输出格式
🌈printf() 可以定制占位符的输出格式
①限定宽度
printf() 允许限定占位符的最小宽度,下面直接来用代码演示👇
• %5d 表⽰这个占位符的宽度⾄少为5位。如果不满5位,对应的值的前面会添加空格
• 输出的值默认是右对齐,即输出内容前⾯会有空格
• %05d 表示这个占位符的宽度至少为5位。如果不满5位,对应的值的前面会用0补齐
• 如果希望改成左对齐,在输出内容后面添加空格,可以在占位符的%的后面插入⼀个-号
• 可以限定最小宽度,printf() 当长度超过时则不会受限
对于小数,这个限定符会限制所有数字的最小显示宽度,是‼️所有数字
②限定小数位数(会四舍五入)⭐
输出小数时,有时希望限定小数的位数。举例来说,希望小数点后面只保留两位,占位符可以写成%.2f
限定小数位数可以与限定宽度占位符,结合使用。此外,最小宽度和小数位数这两个限定值,都可以用*代替,通过printf() 的参数传入🐰
③总是显示正负号
默认情况下,printf() 不对正数显示+号,只对负数显示 -号。如果想让正数也输出+号,可以在占位符的%后面加⼀个+
#include <stdio.h>
int main()
{
printf("%+d\n", 12); // 输出 +12
printf("%+d\n", -12); // 输出 -12
return 0;
}
%+d 可以确保输出的数值,总是带有正负号
④输出部分字符串
%s 占位符用来输出字符串(默认是全部输出)
%.[m]s
指定输出的长度,其中[m]代表一个数字,表示所要输出的长度
现在我们用代码演示一下👇
#include <stdio.h>
int main()
{
printf("%s\n", "abcdef");//输出abcdef
printf("%.3s\n", "abcdef");//输出abc
return 0;
}
二、scanf 🚀
当有了变量,需要给变量输入值就可以使用 scanf函数 —— C语言中用于从标准输入设备(通常是键盘)读取数据的函数;将变量的值输出在屏幕上时可以使用 printf函数。
1.scanf报错的原因及解决办法⭐
🐰接下来先做个引入:以下内容只针对 Visual Studio 2022(以下简称VS2022)
上面是一个正确无误的 scanf输入以及 printf输出的代码,可是编译运行时却显示报错,为什么❓
① scanf函数报错的原因
error C4996: ‘scanf’: This function or variable may be unsafe. Consider using scanf_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details. 👈 来看编译器给出的报错理由
( 这句话大概是说:“scanf是不安全的,需要用scanf_s来替换 或者 使用_CRT_SECURE_NO_WARNINGS 才能避免报错”)🍥 我们先来说说为vs觉得scanf函数是不安全的,举个栗子:
这里先用_CRT_SECURE_NO_WARNINGS这一种方法作为例子演示(如何使用该方法稍后详细解释)
🌈补充一下上述例子中的 数组:c语言中我们定义数组是不允许数据越界的,比如上面的数组 arr[5]其中5就是arr这个数组的界限,我们在给这个数组输入数据的时候不能超过5个,但是我在输入了abcdef 6个字母后,它竟然给我们打印出来了,这在c语言中显然是不合法的,所以编译器也给我们报了个错误提醒我们。 这就是为什么VS2022认为scanf函数是不安全的原因。
② scanf 报错的解决办法
在了解VS2022中使用scanf函数报错的原因之后,我们就来介绍一下针对scanf 函数报错的解决方法
(1)使用 scanf_s替换
• scanf_s是vs提供的一个函数,但是这个函数的使用和scanf是有区别的
• scanf_s既然是vs提供的,其他的编译器并不认识这个函数。
• 如果代码中使用了scanf_s函数,代码就存在跨平台性问题
‼️当前建议大家不要使用scanf_s,踏实使用scanf
(2)使用 _CRT_SECURE_NO_WARNINGS(推荐)👈
1.就在当前的代码所在的.c文件的第一行加上:#define _CRT_SECURE_NO_WARNINGS
( 问题:只要使用scanf函数就得加上这句代码,挺麻烦)
2.一劳永逸:
效果:新建的.c文件中的第一行,默认就加上:#define _CRT_SECURE_NO_WARNINGS 1
// 其实在VS上新建.c文件的时候,是拷贝newc++file.cpp这个文件的
// 如果能在newc++file.cpp这个文件的第一行加上:#define _CRT_SECURE_NO_WARNINGS 1
// 新建文件中就有了
👉第一步:复制 #define _CRT_SECURE_NO_WARNINGS
👉第二步:打开 此电脑 ,在右上角搜索newc++file.cpp
👉第三步:选中文件右击鼠标 打开文件所在的位置(注意打开后不要关掉)
👉第四步:将newc++file.cpp 复制到 桌面 然后右击鼠标 在记事本编辑,粘贴第一步的那句话
👉第五步: Ctrl+S 保存后关掉记事本,将桌面的newc++file.cpp拖回文件所在的位置,选择 替换目标中的文件
Tip:到这里,大功告成‼️之后每次创建源文件的时候,第一行都会自动给我们加上这句话了
2.基本用法
scanf 的原型定义在 头文件stdio.h。使用这个函数之前,必须在源代码头部引入这个头文件。
scanf() 函数用于读取用户的键盘输入。程序运行到这个语句时,会停下来,等待用户从键盘输入。
用户输入数据、按下回车键后,scanf() 就会处理用户的输入,将其存入变量。
• 第一个参数是一个格式字符串,里面会放置占位符,告诉编译器如何解读用户的输入,需要提取的数据是什么类型。
• C语言的数据都是有类型的,scanf() 必须提前知道用户输入的数据类型,才能处理数据。
• 其余参数就是存放用户输入的变量,格式字符串里面有多少个占位符,就有多少个变量。
Tip:变量前面必须加上&运算符(指针变量除外),因为scanf() 传递的不是值,而是地址,即将变量 i 的地址指向用户输入的值。如果这里的变量是指针变量(比如字符串变量),那就不用加&运算符。
🌈scanf() 处理数值占位符时,会自动过滤空白字符,包括空格、制表符、换行符等。
用户输入的数据之间,有⼀个或多个空格 / 使用回车键将输入分成几行,都不影响 scanf() 解读
scanf() 处理用户输入的原理:用户的输入先放入缓存,等到按下回车键后,按照占位符对缓存进行解读。解读用户输入时,会从上⼀次解读遗留的第⼀个字符开始,直到读完缓存,或者遇到第⼀个不符合条件的字符为止。
现在我们用代码来演示一下:👇
#include <stdio.h>
int main()
{
int x;
float y;
//用户输入" -13.45e12# 0"
scanf("%d", &x);
printf("%d\n", x);//输出 -13
scanf("%f", &y);
printf("%f\n", y);//输出449999994880.000000
return 0;
}
浮点数在内存中有可能无法精确保存
• scanf() 读取用户输入时,%d 占位符会忽略起首的空格,从 - 处开始获取数据,读取到 -13 停下来,因为后面的 . 不属于整数的有效字符。这就是说,占位符%d会读到 -13
• 第二次调用scanf() 时,就会从上⼀次停止解读的地方,继续往下读取。这⼀次读取的首字符是 . ,由于对应的占位符是%f,会读取到 .45e12 ,这是采用科学计数法的浮点数格式。后⾯的 # 不属于浮点数的有效字符,所以会停在这里
scanf() 可以连续处理多个占位符,so~ 上面的例子也可以写成下面这样:👇
int main()
{
int x;
int y;
//用户输入" -13.45e12# 0"
scanf("%d%f", &x, &y);
return 0;
}
3.scanf 的返回值
1.scanf() 的返回值是⼀个整数,表示成功读取的变量个数
2.如果没有读取任何项,或者匹配失败,则返回0
3.如果在成功读取任何数据之前,发⽣了读取错误或者遇到读取到文件结尾,则返回常量EOF(-1)
EOF — end of file 文件结束标志
现在我们一起来观察以下四种运行结果👇
👆第一种:按照scanf() 格式字符串给出的预定格式输入4个值,返回值为4,结果正常
👆第二种:前3个值按照预定格式输入,但第4个值前有“,”,不属于整数的有效字符,会停在这里,不能正常读取第4个值,因此第4个值 d = 0,并且 scanf() 的返回值是3
👆第三种:在正常输入前两个值后,按Ctrl+Z提前结束输入,此时只读取到两个值,scanf()的返回值是2
👆第四种:⼀个数字都不输⼊,直接按3次 Ctrl+Z ,scanf() 的返回值是-1,也就是EOF
🌈那我想就有人要问了,scanf() 的返回值到底有什么用呢这里来小科普一下:
• scanf函数的返回值一般在竞赛的OJ题目,笔试的OJ题目中比较常见
• OJ – online judge – 在线判题
#include <stdio.h>
int main()
{
int a = 0;
int b = 0;
while (scanf("%d%d", &a, &b) == 2)//或者用while (scanf("%d%d",&a,&b)!=EOF)
{
int r = a + b;
printf("%d\n", r);
}
//10 20
//-10 20
//-10 -20
//0 3
//....
//多组数据测试
return 0;
}
4.占位符
scanf 的占位符和 printf 的占位符基本一致,这里做些补充🍥:
%[ ]:在方括号中指定⼀组匹配的字符(比如%[0-9]),遇到不在集合之中的字符,匹配将会停止
• 除了%c以外,都会自动忽略起首的空白字符
• %c 不忽略空白字符,总是返回当前第一个字符,无论该字符是否为空格
• 如果要强制跳过字符前的空白字符,可以写成scanf(" %c", &ch),即%c前加上一个空格,表示跳过零个或多个空白字符
🌈现在在%c前面加上一个空格:
占位符%s的规则:从当前第一个非空白字符开始读起,直到遇到 空白字符(即空格、换行符、制表符等)为止。
• %s不会包含空白字符,所以无法用来读取多个单词,除非多个%s 一起使用
• scanf() 遇到%s 占位符,会在字符串变量末尾存储一个空字符\0
scanf读取空白字符的特殊写法: %[^\n]s --> 一直读取,直到遇到\n
scanf() 将字符串读入字符数组时,不会检测字符串是否超过了数组长度— VS会提示scanf函数不安全
为防止:储存字符串时,超过数组的边界,so~ 使用 %s 占位符时,应该指定输入字符串的最长长度
%[m]s :其中的 [m] 是⼀个整数,表示读取字符串的最大长度,后面的字符将被丢弃
#include <stdio.h>
int main()
{
char arr[5]={0};
scanf("%4s",arr); //%4s:为\0留出1一个空间
printf("%s\n",arr);
return 0;
}
5.赋值忽略符
有时,用户的输入可能不符合预定的格式
🌈 scanf函数的第一个参数中的格式一定要和输入的格式匹配才可以正确读取数据
应该有人会想到,既然用户输入时在年月和月日之间都要加上字符( / - 空格),那就直接在scanf() 的第一个参数中加上字符让它读取就好了👇
但是上述方式虽然能解决问题,但是并不是很好的办法,为了接收两个字符( / - 空格 ),在格式串里专门搞了两个字符%c、%c,并且创建了两个变量ch1、ch2,但是它们并没有什么用。下面有个更好的办法👇
为避免用户输入其他格式导致scanf() 解析数据失败,scanf() 提供了一个赋值忽略符*0
只要把*加在任何占位符的百分号后面,就表示该占位符没有对应的变量,不会返回值,解析后将被丢弃
✨总结
至此,关于C语言的 scanf 和 printf 两大函数的探索暂告一段落了。偷摸说已经吧嗒一万多字了(心好累),初次写文难免有不足之处,但还是感谢你的耐心阅读,我会继续努力的!😝都看到这里了,给博主我个一键三连吧!!!感谢你的支持!!!