目录
一、printf
1、printf 的基本用法
printf() 的作用是将参数文本输出到屏幕。printf 全称为 print format(格式化),表示可以定制输出文本的格式。
#include <stdio.h>
int main()
{
printf("hello world");
return 0;
}

上边的代码在屏幕上输出一行文字“hello world”。printf() 不会在行尾自动换行。运行结束后,光标会停留在输出结束的地方。为了让光标移到下一行的开头,就可以在输出文本的结尾添加一个换行符 \n。如果文本内部需要换行,也可以通过插入换行符实现。
#include <stdio.h>
int main()
{
printf("hello world\n");
printf("hello\n");
printf("world\n");
printf("hello\nworld\n");
return 0;
}

需要注意的是,printf() 的使用需要包含头文件:stdio.h。
#include <stdio.h>
2、占位符
printf() 可以在输出文本中指定占位符。什么是占位符?占位符的作用就是可以将这个位置用其他数据替代。让我们看下面的代码。
#include <stdio.h>
int main()
{
printf("there are 8 people\n");
printf("there are %d people\n",8);
return 0;
}

在上面的代码中,%d 就是占位符,表示这个位置要用其它值代入。占位符都以 % 开头,后面的字符表示占位符的类型。%d 表示这里代入的值为整数。printf() 的第二个参数就是要替换占位符的数据。在上面的代码中,整数 8 替换了 %d。
常用的占位符除了 %d,还有 %s 等等,%s 表示的代入的值是字符串。我们再来看一个例子:
#include <stdio.h>
int main()
{
printf("%s will succeed\n", "Niko");
return 0;
}

在上面的代码中,%s 表示代入的数据是一个字符串,所以 printf() 的第二个参数就必须是字符串。
在C语言中,输出文本里面也可以使用多个占位符。
#include <stdio.h>
int main()
{
printf("%s has been selected on HLTV's top 20 rankings for %d times","Niko",8);
return 0;
}

在上面的代码中,输出文本"%s has been selected on HLTV's top 20 rankings for %d times"中有两个占位符,第一个是字符串占位符 %s,第二个是整数占位符 %d分别对应着 printf的第二个参数“Niko”和第三个参数"8"。执行结果为"Niko has been selected on HLTV's top 20 rankings for 8 times"
printf() 的参数与占位符是一一对应的。如果有 n 个占位符,printf() 的参数就要有 n+1 个,如果参数个数少于对应的占位符,printf() 可能会输出内存中的任意值。
3、占位符列举
printf() 的占位符有很多种,它与C语言中的数据类型相对应。下面是一些常见的占位符。
%a :⼗六进制浮点数,字⺟输出为⼩写。
%A :⼗六进制浮点数,字⺟输出为⼤写。
%c :字符。
%d :⼗进制整数。
%e :使⽤科学计数法的浮点数,指数部分的 e 为⼩写。
%E :使⽤科学计数法的浮点数,指数部分的 E 为⼤写。
%i :整数,基本等同于 %d 。
%f :⼩数(包含 float 类型和 double 类型)。
%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 类型。
%% :输出⼀个百分号。
4、printf 输出格式
printf() 可以定制占位符的输出格式。
(1)限定宽度
#include <stdio.h>
int main()
{
printf("%8s", "Niko");
return 0;
}

printf() 允许限定占位符的最小宽度。在上面的代码中,%5s 表示占位符的宽度至少是8位,如果不满8位,对应的值前面会自动添加空格,因为文本输出的数据默认是右对齐;如果希望变成左对齐,可以在占位符的%后插入一个 - 号。
#include <stdio.h>
int main()
{
printf("%-8s", "Niko");
return 0;
}

在上面的代码中,输出的内容后添加了4个空格。
#include <stdio.h>
int main()
{
printf("%18f",16.875);
return 0;
}

对于小数,限定符会限制所有数字的最小显示宽度,包括小数点。在上面的代码中,%18f 表示输出的浮点数至少要占18位。由于单精度浮点数默认显示精度是小数点后六位,所以16.875输出结果的前边添加9个空格。
(2)限定小数位数
在输出小数时,我们有时需要限定小数点后的位数。比如希望小数点后面保留两位,占位符可以写为 %.2f。
#include <stdio.h>
int main()
{
printf("%.2f",3.1415926);
return 0;
}

这种写法可以与限定宽度占位符结合使用。比如:
#include <stdio.h>
int main()
{
printf("%6.2f",3.1415926);
return 0;
}

最小宽度和小数位数这两个占位符,都可以用 * 代替,通过 printf() 的参数传入。
#include <stdio.h>
int main()
{
printf("%*.*f",6,2,3.1415926);
return 0;
}

在上面的代码中,%*.*f 的 * 通过 printf() 的两个参数 6 和 2 传入。
(3)输出部分字符串
%s 占位符用来输出字符串,默认是全部输出,如果只想输出开头的一部分,可以用 %.[m]s 指定输出长度。其中 [m] 表示一个数字,即所要输出字符串的长度。
#include <stdio.h>
int main()
{
printf("%.5s","hello world");
return 0;
}

这里需要与限定宽度占位符区分的是,限定宽度占位符必须应用于限定的宽度大于等于数据的位数;而输出部分字符串则没有限制。
(4)总是显示正负号
在默认状态下,printf() 不对正数显示 +,只对负数显示 -。如果想让正数显示 +,可以在占位符的 % 后加一个 +。
#include <stdio.h>
int main()
{
printf("%+d\n", 16);
printf("%+d\n", -16);
return 0;
}

二、scanf
当变量产生时,我们可以使用 printf() 将变量的值输出到屏幕上,同样,我们需要将变量输入值时就可以使用 scanf()。
1、scanf() 的基本用法
scanf() 函数用于读取用户键盘输入的数据。程序运行到 scanf() 语句时,会停下来等待用户从键盘输入;用户按下回车键后,scanf() 会处理用户的输入,将其存入对应的变量中。需要注意的是,scanf() 与 printf() 一样,都需要头文件 stdio.h 来定义,语法也与 printf() 类似。如下:
scanf("%d",&i);
scanf() 的第一个参数是格式化字符串,其中需要放置占位符,占位符的种类与 printf() 的占位符基本一致。输入占位符的目的就是要确定提供数据的类型,因为C语言中的数据都是有类型的,scanf() 必须提前知道用户输入的数据类型才能处理数据。
scanf() 的其余参数就是存放用户需要输入数据的变量,格式字符串中有多少占位符,就表示有多少要输入数据的变量。在上面的示例中,scanf() 的第一个参数 %d 表示用户需要输入一个整数,第二个参数是 &i 表示用户输入的数据存入变量 i 中。
需要注意的是,变量前面就需要加上运算符 & 才能被 scanf() 识别,因为 scanf() 传递的不是数值而是地址。如果是指针变量或者数组,则不需要运算符 &。
scanf() 也可以一次读取多个变量。如下:
#include <stdio.h>
int main()
{
int a = 0;
int b = 0;
float c = 0.0;
float d = 0.0;
scanf("%d%d%f%f",&a,&b,&c,&d);
printf("\n%d,%d,%f,%f", a, b, c, d);
return 0;
}
scanf() 在处理数值占位符时,会自动过滤空白字符,包括空格、制表符、换行符等等。所以,用户输入数据时,无论是回车还是空格都不会影响程序的解读。

scanf() 处理用户输入数据的原理是:用户输入的数据先放入缓存,按下回车键后,按照占位符对缓存进行解读。并且,解读用户输入时每次会从上一次解读遗留的第一个数据开始,直到读取缓存结束,或者遇到第一个不符合对应类型的数据为止。
#include <stdio.h>
int main()
{
int a = 0;
float b = 0;
//用户输入" 123.456^789"
scanf("%d", &a);
printf("\n%d\n", a);
scanf("%f", &b);
printf("%f\n", b);
return 0;
}

在上面的代码和运行结果中,scanf() 读取用户输入时,%d 忽略了起首的空格,从“1”处开始读取数据,读取完“123”后停下,因为“123”之后的数据不属于 %d 能读取的有效数据。第二次调用 scanf() 时,scanf() 会从上一次停止读取的地方继续读取,这一次读取的首字符时“.”,对应的占位符是 %f,会读取到“.456”。后面的 ^ 不属于浮点型数据的有效字符,所以读取会在这里停止。
2、scanf() 的返回值
scanf() 的返回值是一个整数,表示成功读取变量的个数。如果没有读取到任何数据或者读取失败,则 scanf() 返回 0。如果在成功读取任何数据之前发生了读取错误或者读取到文件末尾,则返回常量 EOF。
下面我们用代码验证一下 scanf() 的返回值。
#include <stdio.h>
int main()
{
int a = 0;
int b = 0;
float c = 0.0;
int y = 0;
y = scanf("%d %d %f", &a, &b, &c);
printf("%d %d %f\n", a, b,c);
printf("%d\n", y);
return 0;
}

如果我们输入两个数后想要将程序运行终止,则需要按 Ctrl+z 提前结束输入。

我们按了3次 Ctrl+z 才结束了输入,此时scanf() 的返回值是 2,如果我们不输入任何数据,直接使程序中止,scanf() 的返回值将是 -1,也就是 EOF。

3、scanf 占位符
scanf() 常用的占位符与 printf() 一致。
%c :字符。
%d :整数。
%f : float 类型浮点数。
%lf : double 类型浮点数。
%Lf : long double 类型浮点数。
%s :字符串。
%[] :在⽅括号中指定⼀组匹配的字符(⽐如 %[0-9] ),遇到不在集合之中的字符,匹配将会
停⽌。
需要注意的是,在上面的占位符中除了 %c 以外,都会自动忽略起首的空白字符。%c 不会忽略空白字符,只会返回当前的第一个字符,无论该字符是否为空格。如果需要强制跳过起首的空白字符,可以将 scanf() 语句改为 scanf(" %c",&char); 即在 %c 前加一个空格表示跳过起首的空白字符。
需要特别注意的是占位符 %s,它不简单地等同于字符串。它的规则是从当前第一个非空白字符开始读起,直到遇到空白字符(空格、换行符、制表符等)为止。因为 %s 不会包含空白字符,所以无法用来读取多个单词,除非多个 %s 连用。所以 scanf() 不适合读取包含空白字符的字符串。另外,scanf() 遇到 %s 占位符时,会在字符串末尾存储一个 \0。
scanf() 将字符串读入数组时,不会检测字符串是否超过了数组长度。所以在存储字符串时,如果超过了数组的边界,就会导致程序出现错误。为了防止这种情况的发生,使用 %s 占位符时,应该指定读入字符串的长度,写成 %[m]s,其中 [m] 表示一个整数,即读取字符串的最大长度,后面的字符将被丢弃。
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/01/19”,scanf() 解析数据会失败,得不到我们想要的结果。为了避免这种情况的发生,scanf() 提供了赋值忽略符 *。只要将 * 加在任何占位符的百分号后面,该占位符没有返回值,解析后将被丢弃。
#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;
}

9599

被折叠的 条评论
为什么被折叠?



