前言
本篇文章介绍C语言中的printf
和scanf
函数,之前在C语言中printf打印转换指令详解文章中详细讲解了转换指令,本篇文章介绍几个上篇文章没涉及到的点和其余的注意事项
%g和%G
这两个转换说明符的官方解释是根据值的不同,自动选择%e或者%f(当然,%G对应的是%E),%e或者%E格式用于指数小于-4或者大于等于精度时
,先说明一下两个定义:
- 指数计数法:也叫E计数法,是将一个数字表示为一个介于1到10之间的小数(基数)与一个表示幂次的整数(指数)的乘积。指数可以是正数、负数或零
- 精度:浮点数的精度是指C标准规定的浮点数必须能精确表示的小数点后有效数字的位数,
float一般是6位,double一般是10位
我们写一个例子测试一下:
#include <stdio.h>
int main()
{float a1 = 123456;float a2 = 1234567;float a3 = 0.0001;float a4 = 0.00001;printf("指数为5: %g\n",a1);printf("指数为6: %g\n",a2);printf("指数为-4: %g\n",a3);printf("指数为-5: %g\n",a4);return 0;
}
结果如下:
指数为5: 123456
指数为6: 1.23457e+06
指数为-4: 0.0001
指数为-5: 1e-05
所以可以看出** e < − 4 e<-4 e<−4或者 e ≥ 6 e\ge6 e≥6时会使用%e或者%E,否则使用%f**
printf的返回值
这个功能用的比较少,稍微介绍一下,printf返回打印字符的数目,如果输出过程中出现错误,返回一个负数,经过我测试,中文不止占用一个字符数目,这个应该跟编码规范有关,其实应该取得字符编码所占用字节的数目更恰当一些
printf打印长字符串
如果一个字符串太长,我们想换行打印,有没有什么办法呢?有四种办法:
- 一个printf打印分成多个printf,这会进行多次函数调用
- 在
逗号后面
断行,但是不能在第一个参数的字符串里边直接断行,很多情况是第一个参数字符串很长,所以实用性差
#include <stdio.h>
int main()
{float a1 = 123456;printf("1111111111222222222333333333: %g\n",a1);return 0;
}
- 如果想在字符串里边断行,断行的地方添加反斜杠
\
,但是之后的新行自动在最左侧对齐,不能进行缩进,因为一缩进就变成了字符串的一部分
,编码不美观,尤其是在嵌套的块里边使用这种方法
#include <stdio.h>
int main()
{float a1 = 123456;printf("1111111111222222\
222333333333: %g\n",a1);return 0;
}
- 把字符串分成多个字符串,两边用
"
括起来,这样就可以随便换行了,我觉得这是最好的方法
#include <stdio.h>
int main()
{float a1 = 123456;printf("1111111111222222""222333333333: %g\n",a1);return 0;
}
printf中使用*
printf中有一种形如a.b
的修饰符,a可能表示字符的宽度,b可能表示浮点数的小数位数,或者表示字符串的最小显示宽度等,这个a和b我们可以使用变量指定,只需要在使用修饰符的时候用*
代替即可,看下面例子:
#include <stdio.h>
int main()
{float a1 = 12.354;int fw = 12;int nw = 2;printf("a1: %*.*f\n",fw,nw,a1);return 0;
}
输出
a1: 12.35
scanf的使用规则
scanf和printf一样,也是使用转换说明符来进行读取输入的,scanf的读取规则如下:
- 如果读取%c,scanf读取一个字符就返回
- 否则,scanf会从跳过前面所有的空白字符,从第一个非空白字符开始读取,根据类型的不同会识别不同的字符,直到
遇到无法解析的字符
或者已经达到设置的最大宽度
或者遇到空白字符
- 因为遇到空白符就会停止,所以使用scanf
读取字符串的时候只会读取一个单词
- 如果使用scanf向字符数组读取字符串,会在读取结束后添加一个
\0
scanf格式字符串中的普通字符
scanf函数允许把普通字符放进格式字符串中,除空格字符外的普通字符必须与输入字符串严格匹配,空格字符的话就会跳过前面所有的空格,包括没有空格的情况
,看一个例子
#include <stdio.h>
int main()
{float a1 = 0;char c1 = ' ';scanf("%f ,haha, heihei, %c",&a1,&c1);printf("a1: %f\n",a1);printf("c1: %c\n",c1);return 0;
}
输入
12 ,haha, heihei,a
运行结果
a1: 12.000000
c1: a
解析输入过程如下:
- 首先从一个非空字符开始检测float输入,检测到12
- 因为%f后面是一个空格,所以跳过输入的所有空格,虽然我在12后面输入了三个空格,都会跳过
- 匹配
,haha,
,这个必须只能是这样的,否则输入就结束了 - 后面又是一个空格,所以跳过输入的所有空格,虽然我在,haha,后面输入了一堆空格,都会跳过
- 匹配
heihei,
,这个必须只能是这样的,否则输入就结束了 - 后面又是一个空格,所以跳过输入的所有空格,虽然我没有输入空格
- 检测到字符a,赋值给c1
- 检测到换行符,输入结束
scanf的返回值
scanf返回成功读取的项数
,如果没有读取到任何项,比如需要读取一个数字,你却输入一个字符串,这种会返回0,当scanf检测到文件结尾,会返回EOF
scanf中使用*
scanf中的*
和printf不同,把\*放在%和转换符之间,会跳过相应的输入项
,看下面的例子
#include <stdio.h>
int main()
{float a1 = 0;int a2 = 0;int a3 = 0;scanf("%*f, %*d, %d",&a3);printf("a1:%f\n",a1);printf("a2:%d\n",a2);printf("a3:%d\n",a3);return 0;
}
输入
12,12,12
运行结果
a1:0.000000
a2:0
a3:12
可以看出,输入跳过了前两个值,只给第三个值赋值了