最近在看一本书----《C语言解惑》,这篇博客相当于我做的笔记的其中一个,内容如下:
printf()函数和scanf()一对冤家
1.printf()输出
1.1.空格到底在哪
不难发现,“hello\n"之后有一个空格,而这个空格出现在了下一行,因为这个空格本身也在printf函数的打印范围之内,输出换行之后,就会继续打印空格了。而且有多少个空格,第二行就会出现多少个。
printf函数的格式-————
printf(格式控制,输出量表);
格式控制其实就是一个字符串,包括格式说明和普通字符串。格式说明就是如%d之类的(%+格式符),他的作用就是把数据转换成指定格式输出。而普通字符串就如同上边的”hello\n ",原样输出,遇到转义字符后做出相应的反应即可。
插一句题外话,如果想要在屏幕上打印一个%,需要使用%%才能打印出来一个%。
但是如果pintf()输出的时候,如果对于转移字符也是用%%,则达不到预期的目的。
1.2.别再傻傻分不清
话说回来,很多初学者甚至老手在书写代码,都会有傻傻分不清楚时候。
比如数字1和小写字母l,看着就很像。其实下边这个编译器(小熊猫)还好,比较明显。但是分不清楚这件事确确实实是存在的,这就需要我们去格外的注意。
除此之外,错用格式符相信 是每位学者都会犯的错误吧。
所以,在我们运行遇到类似这种问题的时候,不妨看看是不是格式符的错用。
2.printf()输出字符或整数
2.1.格式要配对
谈到字符和整数,就不由自主地会想到ASCII码表。一个0到255之间的整数,都可以被看作一个字符,可以用 %c 输出一个整数的字符,也可以用 %d 输出一个字符的整数。
还是那句话,不要错用格式符,否则达不到预期结果。就像下边这个输入的格式配对错误。
有人认为是%g的错误,其实不然。g是输出实数,它会根据数值自动选择 f 或者 e 。而且double类型输出是不必非要是%f,排除一次,我们发现还是scanf这里的问题。
scanf()中 f 是输入浮点数,输入时可以使用小数或者指数形式,因此认为是,没有使用%lf的原因。
“l”说明这是一个“长”,对应“long”。
2.2.丢弃,长度和空格
再来看一下下边的代码:
可以思考一下,输入123456789,会输出什么?
答案是12,6789,
这里的“*”号是表示输入项读取之后不赋值给相应的变量,而是丢弃。%2d是说明宽度是2,比如输入123456789,%2d会将12读取,%3d就把345吸收丢弃,剩下的全部给b,而换行则被%c吸收,因为换行是不可见字符。所以是这样的。
那如果输入123 456 789,又会怎么样呢?
直接公布答案吧,输出:12,456,
将12赋值给a,丢弃3,但3之后是一个空格,表示一个字符串的结束,于是456会被赋值给b,虽然有789,但是456之后有一个空格,这个空格被%c吸收。
所以结果是:
那输入1 2 3456 789,又怎么样呢?
被舍弃的空格是空格区分的,如果数量不够,也只是舍弃的空格而已。如果数量足够,就舍弃相应的位数,剩下的赋值给变量。
由此可见,空格是不是有点意思啊。
那么请你看看下边的例子————
(这里的a,b,c都是int类型)
1. scanf("%d%d%d", &a,&b,&c);
2.scanf("%d%d%d ",&a,&b,&c);//注意看,最后一个%d后边跟了一个空格
3.scanf(" %d%d%d",&a,&b,&c);//第一个%d前边有一个空格
实验可以发现,第一个和第三个可以正常运行,但是第二个却要输入4个数据才能进行下一步
也就是说,最后一个%d与双引号之间不能有空格。
2.3.回车一敲,脑子发烧
请看下边这个代码。
假如输入12 34 56
abc
会是什么样的景色呢?
你一猜就知道,这里必定有坑。
是的,没错,但有时候我们就是会跳
第一行输入结束之后,我们按下enter键,而这个换行就被被付给第一个%c,也就是c1,换行不可见,所以打印不了,于是就是下边这个:
解决办法也很简单,只需要加一个getchar()吸收掉换行就行了。
现在来看一种输入字符是比较有意义的一个方式。
这样写的话,既可以连续输入,也可以用空白符分割,甚至可以先打一个换行,再输入数据。
2.4.字符数组和字符
请你先来看这样的一段代码:
第三个打印之所以到不到目的,是因为str[5]仅仅代表的是y这个字母而已,如果想要达到目的,该怎么样修改呢?
很简单,改为&str[5]即可:
不过瘾?再来!!!
在这里,我们本来是想要把you and me装到str中,但是由于scanf遇到空白符会停止读取。所以只是把you装进去了。那如何达到目的呢?我们找来了scanf的弟弟———gets()。
有请gets()登场:
是不是手到擒来啊?
2.5.特殊对待一维数组
数组名是数组首元素的地址,想要打印出来整个数组的内容,这是远远不够的。可以使用循环单个输出数组的元素,就像这样:
那么如果是为数组赋值,又该怎么做呢?
首先想到的肯定就是循环了——
我们都知道&arr[i]表示数组arr的各个元素的地址,这些地址储存这相应的数组元素,对其进行操作,也可以输出于元素。
来分析以下,下面这段代码的错误——
#include <stdio.h>
int main()
{
int a = 25;
int addr;
addr = &a;
printf("分配给变量a的地址是0x%d\n",&a);
printf("addr的地址值=0x%p\n",addr);
printf("addr的地址的内容=%d\n",*addr);
}
编译会给出一个错误信息和一个警告信息。
因为addr是一个整型变量,&arr是一个地址,数据类型不匹配。可以使用强制类型转换,addr = (int)&arr;
直接对&a使用 * ,对addr出错,很明显也是数据类型不配对的原因。
再次给出强制类型转换
printf("addr的地址的内容=%d\n", *(int*)addr);
2.6.主角上场——指针
相信以上的代码对你来说,毫无压力,那我们我们一块来看看下边这个吧———
//代码的目的是模拟strcpy函数,复制一个字符串
没达到预期结果是因为,本身you and me就没有被t给接受。不难想到我们之前提到的函数gets
如果使用指针来输入字符串,需要保证指针指向的足够大的字符数组,以便储存输入的字符串和结尾的空字符。
本次笔记,就到这里吧,感谢~