《C Primer Plus》第 4 章 学习笔记(字符串格式化输入输出)(下)


4·4·5 scanf_s ( ) 的使用

scanf_s()把从键盘输入的 字符串 转为 整数,浮点数,字符或字符串 (而 printf()正相反)

与 printf()类似,scanf_s()也使用格式字符串与参数列表。

scanf_s ()中的 格式字符串 表明字符输入流目标数据类型

二者的差别主要在 参数列表 中:

  1. printf()函数使用 变量,常量,表达式
  2. scanf_s()函数使用 指向变量的指针

以下是 3 条使用 scanf_s ()的规则

  • 用 scanf_s()读取 基本变量 的值,在变量名前面加一个 “ &
  • 用 scanf_s()把字符串读入字符数组 中 ,不要使用 “ & ”
  • double 类型对应的转换说明:" %lf "
#include <stdio.h>
int main(void) {
	int age;
	double weight;
	char name[40] = { 0 };

	printf("What's you name?(Within 10 characters!)\n");
	scanf_s("%s", name, 20);

	printf("And how old are you?\n");
	scanf_s("%d", &age);

	printf("Now, tell me your weight (kg):");
	scanf_s("%lf", &weight);

	printf("Here are several information you told me:\n");
	printf("Name:%.10s\nAge:%3d\nWeight:%5.2lf\n", name, age, weight);


	return 0;
}

以下是结果:

What’s you name?(Within 10 characters!)
Alice
And how old are you?
12
Now, tell me your weight (kg):50
Here are several information you told me:
Name:Alice
Age: 12
Weight:50.00


scanf_s ( ) 的转换说明及其修饰符在《C Primer Plus》Page 93

这里省略


从scanf_s()角度看输入

首先声明,scanf_s()并不是最常用的输入函数,这里重点分析仅是因为它可以读取不同种类的数据;

其他的比如 getchar()和 fgets()更适合用于处理一些特殊情况(读取单个字符或者包含空格的字符串),

这些将在后面第 7 ,11,13 章加以讨论;

以 %d 为例,假设 scanf_s()根据 %d 转换说明读取一个整数:

scanf_s()每次读取一个字符,跳过所有的空白字符,直到遇到第一个非空白字符才开始读取

因为要读取一个整数,所以函数希望发现一个 数字字符 或 “ + / - ” ,

  1. 如果找到一个数字或者符号,便保存该字符,并读取下一数据
  2. 如果下一个字符是数字,则保存该数字,并读取下一字符
  3. 不断重复上一步骤,直到遇到非数字字符
  4. 如果遇到非数字字符,函数便认为到达了整数的末尾
  5. 然后程序把该字符放回,停止读取
    • 这意味着 下次 程序读取输入的时候,首先 读取的是 上一次读取剩下的字符
  6. 最后,scanf_s()计算读取到的数字(可能还有符号)相应的数值,并将这个值放入指定的变量

如果控制 字段宽度 ,则 scanf_s()会 在字段结尾第一个空白字符 处停止读取;

无法利用字段宽度只有一个 %s 的读取多个单词;

档把 字符串 放入 数组 时,会在字符末尾加上一个 ’ \0 ’

(也可能需要自己手动加:char name[20] = { 0 },有时还要求设置好缓冲区大小的参数,参考这里:程序)


格式字符串中的普通字符

scanf_s()函数允许把普通字符放入格式字符串中。除空格之外 的普通字符必须与输入字符 完全匹配

scanf_s()的格式串字符中,空白意味着跳过下一个输入项前面的 所有空白

所有空白 包括 没有空格 的特殊情况

示例:

#include <stdio.h>
int main(void){
    int a, b;
    int c, d;
    printf("Please enter two numbers (Separated by Space)\n");
    scanf_s("%d %d", &a, &b);
    printf("Please enter two numbers (Separated by ',')\n");
    scanf_s("%d,%d", &c, &d);
    /*
    此处解释为:
    用户输入一个整数,然后输入一个逗号,接着输入一个整数
    也即必须这样输入: NUM + , + NUM
    NOTE:
    因第一个 %d 后紧跟逗号,scanf_s()会跳过整数前的空白,
    所以输入第一个整数后必须紧跟逗号,但可以在其后加多个空白再接下一个整数。
    */
    printf("Here are the numbers that you gave us:\n");
    printf("%d %d\n%d %d\n", a, b, c, d);
    
    return 0;
}

结果:

Please enter two numbers (Separated by Space)
1 2
Please enter two numbers (Separated by ‘,’ )
3,4
Here are the numbers that you gave us:
1 2
3 4

除了 %c ,所有转换说明都会跳过待输入之前所有空白,因此

  • scanf_s("%d%d", &a, &b)scanf_s("%d %d", &a,&b) 没有区别

  • scanf_s("%d,%d", &a, &b)scanf_s("%d ,%d", &a,&b) 也没有区别

但对于 %c ,空格是有意义的,换句话说

  • scanf_s("%c", &a) 从第一个字符(包括空格)读取

  • scanf_s(" %c", &a) 从第一个非空白字符读取


scanf_s()的返回值

scanf_s()会返回 成功 读取的 项数,如果没有读取任何项,且需要读取一个数字而用户却输入一个字符串,则返回 0 。

当 scanf_s()检测到“文件结尾”时,返回 EOF ( EOF 是 #define 定义的特殊值,通常定义为 -1 )【第 6 章内容】。

可以使用 if 和 while 配合 scanf_s()检测返回值并处理不匹配的输入。


4·4·6 printf()和 scanf_s()的 * 修饰符(重点)

  1. printf()的情况:(让用户控制 最小字段宽度精度
#include <stdio.h>
int main(void){
    int width, precision;      //width 提供宽度,precision 提供精度
    int number = 233;          //待打印数字
    double weight = 22.3;
    
    printf("Please enter a width:\n");
    scanf_s("%d", &width);
    printf("The number is :[%*d]:\n", width, number);        //width —— number 输出时的宽度
    
    printf("Now, please enter a width and a precision:\n");
    scanf_s("%d %d", &width, &precision);
    
    printf("Weight = %*.*lf\n", width, precision, weight);   //参数表中这三个形参分别对应 * ,* ,lf
    printf("Finish.\n");
    
    return 0;
}

结果:

Please enter a width:
10
The number is :[ 233]:
Now, please enter a width and a precision:
5
5
Weight = 22.30000
Finish.

  1. scanf_s()的情况:(跳过当前输入项)

当程序需要读取文件中 特定列 的内容时,此功能可以参考使用

#include <stdio.h>
int main(void){
    int n;
    printf("Please enter three integers:\n");
    scanf_s("%*d %*d %d", &n);
    printf("The third one is: %d\n", n);         //用户输入三个整数,但函数只读取并保存第三个
    return 0;
}

结果:

Please enter three integers:
2020
2021
2077
The third one is: 2077


4·4·7 printf()用法提示

  1. 想要把数据打印成列,要指定一个 >= 待打印字段宽度的固定字段宽度。
printf("%10d %10d %10d\n", a, b, c);
printf("%10d %10d %10d\n", d, e, f);
printf("%10d %10d %10d\n", g, h, i);
  1. 如果在一段文字中嵌入一个数字,通常指定一个小于等于该数字宽度的字段。

声明

本文中省略的表格内容:

  • limits.h 的明示常量(Page 79)
  • float.h 的明示常量(Page 79)
  • printf()的转换说明(Page 81)
  • printf()的修饰符(Page 83)
  • printf()的标记(Page 84)
  • scanf_s()的转换说明(Page 93)
  • scanf_s()的修饰符(Page 93)

参考资料

《C Primer Plus》(第6版)中文版

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值