C Primer Plus 学习笔记 Chapter 4 格式化输入输出

C Primer Plus 学习笔记 Chapter 4 格式化输入输出

字符串

c语言没有专门存储字符串的数据类型,而是把字符串存储在char类型的数组中。
scanf根据%s转换说明读取字符串时,读到第一个空白(制表符,换行符,空格)就停止。
sizeof()以字节为单位给出对象的大小,而strlen()函数给出字符串中的字符长度。相比较而言,sizeof()读取字符串末尾的\0空字符(null character)。二者都适用%zd的转换说明来返回类型。sizeof()函数,对于类型,应使用()如sizeof(int),而对于特定量,可不使用,如sizeof 3.14,sizeof x。不过最好都使用。

预处理器

预处理器#define指令,可定义常量,字符和字符串常量。三种定义格式:

#define NUMOFA 1 
#define CHARACTERA 'A'
#define TOGETHER "The number of A is 1"

不加分号,也无赋值号等
类似的,还有一个关键字const,用于限定一个变量为只读。声明为

const int MONTHS = 12;//此时months在程序中不可改,总为12。

明示变量

C头文件limits.h和float.h 中分别提供了与整数类型和浮点类型大小限制相关的信息。豆丁故意了一系列明示常量,例如limits.h头文件包含类似
#define INT_MAX +32767
这样的代码
书191页

printf()

书200页 主要说修饰符。又主要说这两种类型
五种标记(+ 数值为正加上+号,数值为负加上-号 ;-左对齐打印 ; 空格 值为负在前面加上一个空格; #与x,o配合使用 显示0xhh 和0dd; 0 对于数值用前导0替代空格填充字段宽度
.数字 对于%e%E%f转换表示小数点右边的位数。(这里“数字”前面有个点呀!!!!) 对于 %g%G表示有效数字最大位数 对于%s表示待打印字符的最大数量 对于整型表示待打印数字的最小位数 使用前导0可以以0补上所缺的位数来达到这个位数。
整型普通的修饰很简单,这里看一下含标记的格式化输出

/* flags.c -- 演示一些格式标记 */
#include <stdio.h>
int main(void)
{
printf("%x %X %#x\n", 31, 31, 31);
printf("**%d**% d**% d**\n", 42, 42, -42);
printf("**%5d**%5.3d**%05d**%05.3d**\n", 6, 6, 6, 6);
return 0;
}

输出为

1f 1F 0x1f
**42** 42**-42**//第二个为空格标记,多了一个空格
** 6** 006**00006** 006**//0为前导,填充空格

注意第三次printf,一是出现0标记前导填充,二是出现精度(此处精度为3,.3是最小位数)当0标记和精度同时出现时,0标记被忽略(最后一个006中的0不是来源于0标记而是精度)。

浮点型

// floats.c -- 一些浮点型修饰符的组合
#include <stdio.h>
int main(void)
{
const double RENT = 3852.99; // const变量
printf("*%f*\n", RENT);
printf("*%e*\n", RENT);
printf("*%4.2f*\n", RENT);
printf("*%3.1f*\n", RENT);
printf("*%10.3f*\n", RENT);
printf("*%10.3E*\n", RENT);
printf("*%+4.2f*\n", RENT);
printf("*%010.2f*\n", RENT);
return 0;
}

输出为

*3852.990000*
*3.852990e+03*
*3852.99*
*3853.0*
* 3852.990*
* 3.853E+03*
*+3852.99*
*0003852.99*

字符串输出

程序清单4.10 stringf.c程序
/* stringf.c -- 字符串格式 */
#include <stdio.h>
#define BLURB "Authentic imitation!"
int main(void)
{
printf("[%2s]\n", BLURB);
printf("[%24s]\n", BLURB);
printf("[%24.5s]\n", BLURB);
printf("[%-24.5s]\n", BLURB);
return 0;
}

输出是

[Authentic imitation!]
[ Authentic imitation!]
[                Authe]
[Authe                ]

精度.5.限制了待打印的字符个数。

转换不匹配

1.整型不匹配:

/* intconv.c -- 一些不匹配的整型转换 */
#include <stdio.h>
#define PAGES 336
#define WORDS 65618
int main(void)
{
short num = PAGES;
short mnum = -PAGES;
printf("num as short and unsigned short: %hd %hu\n", num,num);
printf("-num as short and unsigned short: %hd %hu\n", mnum,mnum);
printf("num as int and char: %d %c\n", num, num);
printf("WORDS as int, short, and char: %d %hd %c\n",WORDS,WORDS,WORDS);
return 0;
}

输出为:

num as short and unsigned short: 336 336
-num as short and unsigned short: -336 65200
num as int and char: 336 P
WORDS as int, short, and char: 65618 82 R

注意后面三个输出。
第二个输出是有符号和无符号的不匹配。系统采用二进制补码表示有符号整数,这样,数字0到32767为正数,数字32768到65535表示负数。其中65535为-1,65534为-2,,以此类推所以-336输出65200。
第三个输出是类型不匹配,大于255的数转换成char字符会发生的情况。short int是2字节,char是1字节,printf函数在打印时只会查看336的后1个字节。这叫做截断,相当于该整数除以256后取余数。336除以255取余为80,对应ascii码值为字符P。专业一点说,80被解释为“以256为模”(modulo 256),即该数字除以256取余数。
第四个输出为转换说明比值类型范围大的情况。short int为2字节,最大为32767,但此时要打印65618.此时计算机也进行了求模运算。首先计算机存储时把65618存储为4个字节,但以%hd为转换说明,只截取最后两个字节,就相当于65618除以65536的余数。此时余数为82。由于二进制补码存放有符号数,当余数在32767到65536之间时被打印为负数。

2.整型和浮点型不匹配

/* floatcnv.c -- 不匹配的浮点型转换 */
#include <stdio.h>
int main(void)
{
float n1 = 3.0;
double n2 = 3.0;
long n3 = 2000000000;
long n4 = 1234567890;
printf("%.1e %.1e %.1e %.1e\n", n1, n2, n3, n4);
printf("%ld %ld\n", n3, n4);
printf("%ld %ld %ld %ld\n", n1, n2, n3, n4);
return 0;
}

输出:

3.0e+00 3.0e+00 3.1e+46 1.7e+266
2000000000 1234567890
0 1074266112 0 1074266112

注意第一行后两个输出,把整型以浮点指数输出时出错了:首先,%e转换说明让printf()函数认为待打印的值是double类型(本系统中double为8字节)。当printf()查看n3(本系统中是4字节的值)时,除了查看n3的4字节外,还会查看查看n3相邻的4字节,共8字节单元。接着,它将8字节单元中的位组合解释成浮点数(如,把一部分位组合解释成指数)。因此,即使n3的位数正确,根据%e转换说明和%ld转换说明解释出来的值也不同。最终得到的结果是无意义的值。
第1行也说明了前面提到的内容:float类型的值作为printf()参数时会被
转换成double类型。在本系统中,float是4字节,但是为了printf()能正确地显示该值,n1被扩成8字节。
第2行输出显示,只要使用正确的转换说明,printf()就可以打印n3和
n4。
第3行输出显示,如果printf()语句有其他不匹配的地方(混合使用整型和浮点型),即使用对了转换说明也会生成虚假的结果。用%ld转换说明打印浮点数会失败,但是在这里,用%ld打印long类型的数竟然也失败了!

参数传递
参数传递机制因实现而异。下面以我们的系统为例,分析参数传递的原
理。函数调用如下:
printf("%ld %ld %ld %ld\n", n1, n2, n3, n4);
该调用告诉计算机把变量n1、n2、、n3和n4的值传递给程序。这是一种常见的参数传递方式。程序把传入的值放入被称为栈(stack)的内存区域。计算机根据变量类型(不是根据转换说明)把这些值放入栈中。因此,n1被储存在栈中,占8字节(float类型被转换成double类型)。同样,n2也在栈中占8字节,而n3和n4在栈中分别占4字节。然后,控制转到printf()函数。该函数根据转换说明(不是根据变量类型)从栈中读取值。%ld转换说明表明printf()应该读取4字节,所以printf()读取栈中的前4字节作为第1个值。这是n1的前半部分,将被解释成一个long类型的整数。根据下一个%ld转换说明,printf()再读取4字节,这是n1的后半部分,将被解释成第2个long类型的整数(见图4.9)。类似地,根据第3个和第4个%ld,printf()读取n2的前半部分和后半部分,并解释成两个long类型的整数。因此,对于n3和n4,虽然用对了转换说明,但printf()还是读错了字节。

printf的返回值

printf()函数也有返回值可用于赋值计算,返回打印字符的个数,个数包含空格和换行符,有输出的错误则返回负值。
printf()的多行输出
三种方法

/* longstrg.c ––打印较长的字符串 */
#include <stdio.h>
int main(void)
{
printf("Here's one way to print a ");
printf("long string.\n");
printf("Here's another way to print a \
long string.\n");
printf("Here's the newest way to print a "
"long string.\n"); /* ANSI C */
return 0;
}

法一分开使用多个打印,但不加入换行符。
法二第一行末尾\反斜杠,然后直接换行。
法三采用双引号。

scanf()函数

读入至数组名不用&.输入时要保证与scanf函数中一致,不同值之间输入用空白分开即可。
sacnf()的读取
如果使用字段宽度,scanf()会在字段结尾或第1个空白字符处停止读取
(满足两个条件之一便停止)。
如果第1个非空白字符是A而不是数字,?scanf()将停在221那里,并把A放回输入中,不会把值赋给指定变量。程序在下一次读取输入时,首先读到的字符是A。如果程序只使用%d转换说明, scanf()就一直无法越过A读下一个字符另外,如果使用带多个转换说明的scanf(),C规定在第1个出错处停止读取输入。
用其他数值匹配的转换说明读取输入和用%d 的情况相同。区别在于scanf()会把更多字符识别成数字的一部分。例如,%x转换说明要求scanf()识别十六进制数a~f和A~F。浮点转换说明要求scanf()识别小数点、e记数法(指数记数法)和新增的p记数法(十六进制指数记数法)。
scanf把字符串放进指定数组时会在末尾加’\0’。
%c读入时,若c前有空格,则不读入空白字符,若c前无空格,则会读入空白字符。其他转换说明会全部忽略空白字符。

使用指定宽度输入输出字符

/* varwid.c -- 使用变宽输出字段 */
#include <stdio.h>
int main(void)
{
unsigned width, precision;
int number = 256;
double weight = 242.5;
printf("Enter a field width:\n");
scanf("%d", &width);
printf("The number is :%*d:\n", width, number);
printf("Now enter a width and a precision:\n");
scanf("%d %d", &width, &precision);
printf("Weight = %*.*f\n", width, precision, weight);
printf("Done!\n");
return 0;
}

示例

Enter a field width:
6
The number is : 256:
Now enter a width and a precision:
8 3
Weight = 242.500
Done!

注意*号的使用和此时的width变量

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值