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

    科技2022-07-17  103

    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("**]**%5.3d**d**.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("*.3f*\n", RENT); printf("*.3E*\n", RENT); printf("*%+4.2f*\n", RENT); printf("*0.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("[$s]\n", BLURB); printf("[$.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变量

    Processed: 0.010, SQL: 8