c语言-scanf与printf

本文详细介绍了C语言中的printf和scanf函数,包括它们的基本用法、占位符、输出格式(如宽度限定和正负号显示)、输入处理(如赋值忽略符和连续多组输入)以及在VisualStudio编译器中的安全性问题。
摘要由CSDN通过智能技术生成

目录

一、printf

1.1 基本用法

1.2 占位符

1.3 输出格式

1.3.1 限定宽度

1.3.2 总是显示正负号

1.3.3 限定小数位数

1.3.4 输出部分字符串

二、scanf

2.1 基本用法

2.2 scanf的返回值

2.3 占位符

2.4 赋值忽略符

2.5 连续多组输入

2.6 scanf函数在VS编译器不安全问题


'scanf''printf' 是C语言中的两个标准库函数,用于输入和输出。'<stdio.h>' 头文件包含了 C 语言标准库中有关输入和输出的函数声明。因此,在你使用 'printf' 和 'scanf' 函数之前要包含这个头文件。


一、printf

'printf'函数用于将格式化的数据输出到标准输出流(通常是屏幕)。它名字里面的 f 代表 format (格式化),表示可以定制输出文本的格式。 它允许程序员根据格式化字符串指定的格式将数据输出到控制台或文件中。


1.1 基本用法

#include <stdio.h>
int main()
{
	printf("hello world!\n");
	return 0;
}

上面的代码执行结果为在屏幕上输出一行文字“hello world”。‘\n’起到换行的作用

注意:printf() 是在标准库的头⽂件 stdio.h 定义的。使用这个函数之前,必须在源码⽂件头部引⼊这 个头文件。


1.2 占位符

printf() 可以在输出文本中指定占位符。 所谓 “占位符”,就是这个位置可以用其他值代入。

#include <stdio.h>
int main()
{
	printf("There are %d students",6);
	return 0;
}
上面示例代码中, There are %d students 是输出文本,里面的 %d 就是占位符,表示这个位置要 用其他值来替换。占位符的第⼀个字符⼀律为百分号 % ,第⼆个字符表表占位符的类型, %d 表示 这里代入的值必须是⼀个整数。printf() 的第⼆个参数就是替换占位符的值,上面的例子是整数 6   替换 %d 。执行后的输出结果就是 There are 3 students 。
常用到的占位符:
%c :字符
%d :⼗进制整数
%f :小数(包含 float 类型和 double 类型)
%p :指针
%s :字符串
%u :无符号整数(unsigned int)
%zd size_t 类型
%% :输出⼀个百分号

输出文本里面可以使用多个占位符 

printf() 参数与占位符是⼀⼀对应关系,如果有 n 个占位符,printf() 的参数就应该有 n +
1 个。如果参数个数少于对应的占位符, printf() 可能会输出内存中的任意值。

1.3 输出格式

printf() 可以定制占位符的输出格式,确保输出的灵活性。

1.3.1 限定宽度

printf() 允许限定占位符的最小宽度。
上面示例中, %5d 表示 这个占位符的宽度至少为5位。如果不满5位,对应的值的前面会添加空格。输出的值默认是右对齐,即输出内容前面会有空格;如果希望改成左对齐,在输出内容后面添加空格,可以在占位符的 % 的后面插入⼀个 -(负) 号。
对于小数,这个限定符会限制所有数字的最小显示宽度。 上面示例中%12lf表示输出的浮点数最少 要占据12位。由于小数的默认显示精度是小数点后6位,
所以 123.45 输出结果的头部会添加2个空格。

1.3.2 总是显示正负号

默认情况下, printf() 不对正数显示  + 号,只对负数显示  - 号。如果想让正数也输出 + 号,可
以在占位符的 % 后面 加⼀个 +
上面示例中, %+d 可以确保输出的数值,总是带有正负号。

1.3.3 限定小数位数

输出小数时,可以限定小数的位数。在%与f之间加上.数字(你想保留的位数)。

上面示例中与限定宽度结合使用,表示输出的宽度为12,小数位数为2。

最小宽度和小数位数这两个限定值,都可以用  * 代替,通过 printf() 的参数传入。
上面示例中, %*.*f 的两个星号通过 printf() 的两个参数 6 2 传⼊。

1.3.4 输出部分字符串

%s 占位符用来输出字符串,默认是全部输出。如果只想输出开头的部分,可以用  %.[m]s 指定输 的长度,其中 [m] 代表⼀个数字,表示所要输出的长度。
只输出了字符串“Hello World!”的前五个字符“Hello”。

二、scanf

有了变量,我们需要给变量输入值就要使用 scanf 函数了。
'scanf' 函数是 C 语言标准库中的一个函数,用于从标准输入流(通常是键盘)中读取格式化输入。它允许程序员根据格式化字符串指定的格式来读取输入,并将输入的值存储到指定的变量中。
注:标准输⼊⼀般指的就是键盘,标准输出⼀般指的就是屏幕

2.1 基本用法

程序运行到这个语句时,会停下来,等待用户从键盘输入。用户输入数据、按下回车键后,scanf() 就会处理用户的输入,将其存入变量。
scanf()函数的第⼀个参数是⼀个格式字符串,里面会放置占位符(与 printf() 的占位符基本⼀致),告诉编译器如何解读用户的输入,需要提取的数据是什么类型。这是因为 C 语言的数据都是有类型的, scanf() 必须提前知道用户输入的数据类型,才能处理数据。它的其余参数就是存放用户输入的变量,格式字符串里面有多少个占位符,就有多少个变量。上面示例中, scanf() 的第⼀个参数 %d ,表示用户输入的应该是⼀个整数。 %d 就是⼀个占位符, % 是占位符的标志, d 表示整数。第二个参数 &a 表示,将用户从键盘输入的整数存入变量a种。
注意: 变量前面必须加上 & 运算符(指针变量除外),因为 scanf() 传递的不是值,而是地址,即将变量 a 的地址指向用户输⼊的值。如果这里的变量是指针变量(比如字符串变量),那就不用加 & 运算符。
⼀次从键盘输入读入多个变量:
scanf("%d %f %c %s",&a,&b,&c,d);
scanf() 处理数值占位符时,会自动过滤空白字符,包括空格、制表符、换行符等。 所以,用户输⼊的数据之间,有⼀个或多个空格不影响 scanf() 解读数据。另外,用户使用回车键,将输入分成几行,也不影响解读。
10
3.14
'w'
"yunanbei"
上面示例中,用户分成四行输入,得到的结果与一行输入是完全⼀样的。每次按下回车键以后, scanf() 就会开始解读,如果第一行匹配第⼀个占位符,那么下次按下回车键时,就会从第二个占位符开始解读。 scanf() 处理用户输⼊的原理是,用户的输入先放入缓存,等到按下回车键后,按照占位符对缓存进行解读。 解读用户输入时,会从上⼀次解读遗留的第⼀个字符开始,直到读完缓存,或者遇到第⼀个不符合条件的字符为止。

 示例代码

#include <stdio.h>
int main()
{
 int x;
 float y;
 
 // ⽤⼾输⼊ " -13.45e12# 0"
 scanf("%d", &x);
 printf("%d\n", x);
 scanf("%f", &y);
 printf("%f\n", y);
 return 0;
}
上面示例中, scanf() 读取用户输入时, %d 占位符会忽略起首的空格,从 - 处开始获取数据,读取到 -13 停下来 ,因为后面的 . 不属于整数的有效字符。这就是说,占位符 %d 会读到 -13 。 第二次调用scanf() 时,就会从上⼀次停止解读的地方,继续往下读取。这⼀次读取的首字符 是 . ,由于对应的占位符是 %f ,会读取到 .45e12 ,这是采用科学计数法的浮点数格式。后面的# 不属于浮点数的有效字符,所以会停在这里。 

2.2 scanf的返回值

scanf() 的返回值是⼀个整数表示成功读取的变量个数。 如果没有读取任何项,或者匹配失败,则返回 0 。如果在成功读取任何数据之前,发生了读取错误或者遇到读取到文件结尾,则返回常量 EOF(-1)。
#include <stdio.h>
int main()
{
	int a = 0;
	int b = 0;
	float f = 0.0f;
	int r = scanf("%d %d %f", &a, &b, &f);
	printf("a=%d b=%d f=%f\n", a, b, f);
	printf("r = %d\n", r);
	return 0;
}

测试1:正常输入三个数字。r是3,表示正确读取了3个数值。测试2:输⼊2个数后,按 ctrl+z ,提前结束输入。r是2,表示正确读取了2个数值。

测试3:啥都不输入,直接按3次ctrl+z,结束输入。 ⼀个数字都不输⼊,直接按3次 ctrl+z ,输出的r是-1,也就是EOF。 测试4:输入‘#’,scanf匹配失败,结束输入,返回0,所以r的值为0。

2.3 占位符

scanf() 常用 的占位符如下,与 printf() 的占位符基本⼀致。
%c: 字符
%d: 整数
%f:float类型浮点数
%lf: double类型浮点数
%Lf:  long double 类型浮点数。
%s: 字符串
%[] :在方括号中指定⼀组匹配的字符(比如 %[0-9] ),遇到不在集合之中的字符,匹配将会停止。

上面所有占位符之中,除了%c以外,都会自动忽略起首的空白字符。%c 不忽略空白字符,总是返回当前第⼀个字符,无论该字符是否为空格。 如果要强制跳过字符前的空白字符,可以写成 scanf(" %c", &ch) ,即 %c 前加上一个空格,表示跳过零个或多个空白字符。

下面要特别说⼀下占位符 %s ,它其实不能简单地等同于字符串。它的规则是,从当前第⼀个非空白字符开始读起,直到遇到空白字符(即空格、换行符、制表符等)为止。
因为 %s 不会包含空白字符,所以无法用来读取多个单词,除非多个 %s ⼀起使用。这也意味着, scanf() 不适合读取可能包含空格的字符串,比如书名或歌曲名。另外, scanf() 遇到 %s 占位符,会在字符串变量末尾存储⼀个空字符 \0
scanf() 将字符串读入字符数组时,不会检测字符串是否超过了数组长度。所以,储存字符串时, 很可能会超过数组的边界,导致预想不到的结果。为了防止这种情况,使用 %s 占位符时,应该指定读⼊字符串的最长长度,即写成 %[m]s ,其中的 [m] 是⼀个整数,表示读取字符串的最大长度,后面的字符将被丢弃。

测试:输入"  hello world",该字符串前面有两个空格,并没有读入,hello与world之间也有空格,scanf跳过了前面两个空格,遇到空白字符(空格)结束了,所以输出结果为hello

s是一个长度为12的字符数组, scanf() 的占位符 %5s 表示最多读取用户输入的5个字符,后面的字符将被丢弃,这样就不会有数组溢出的风险了。


2.4 赋值忽略符

#include <stdio.h>
int main()
{
 int year = 0;
 int month = 0;
 int day = 0;
 scanf("%d-%d-%d", &year, &month, &day);
 printf("%d %d %d\n", year, month, day);
 return 0;
}
上面示例中,如果用户输入 2024-4-9   ,就会正确解读出年、月、日。问题是用户可能输入其他
格式,比如 2024/04/09  ,这种情况下, scanf() 解析数据就会失败。
为了避免这种情况, scanf() 提供了⼀个赋值忽略符(assignment suppression character) *

只要把 * 加在任何占位符的百分号后面,该占位符就不会返回值,解析后将被丢弃。

#include <stdio.h>
int main()
{
 int year = 0;
 int month = 0;
 int day = 0;
 scanf("%d%*c%d%*c%d", &year, &month, &day);
 return 0;
}

2.5 连续多组输入

有的时候我们需要连续多组或者循环输入,这种情况在在线OJ题中经常出现。前面我们提到scanf() 的返回值是⼀个整数表示成功读取的变量个数。 如果没有读取任何项,或者匹配失败,则返回 0 。如果在成功读取任何数据之前,发生了读取错误或者遇到读取到文件结尾,则返回常量 EOF(-1)。

代码1:

#include <stdio.h>
int main()
{
	int a = 0, b = 0, c = 0;
	while (scanf("%d %d", &a, &b) == 2)	//如果正确输入两个数返回2满足条件,循环继续,否则跳出循环
	{
		c = a + b;
		printf("%d\n", c);
	}
	return 0;
}

代码2: 

#include <stdio.h>
int main()
{
	int a = 0, b = 0,c = 0;
	while (scanf("%d %d", &a, &b) != EOF)
	{
		c = a + b;
		printf("%d\n", c);
	}
	return 0;
}

2.6 scanf函数在VS编译器不安全报错问题

这个问题,我在之前的博客中有详细介绍,感兴趣的可以参考了解一下

scanf函数在VS编译器中不安全报错问题


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值