C语言总结

您所在的位置:网站首页 c51语言与标准c语言区别 C语言总结

C语言总结

2024-07-03 15:03:07| 来源: 网络整理| 查看: 265

一、printf() 1、基本用法-printf( 格式字符串, 待打印项1, 待打印项2,…);

格式字符串:这些符号被称为转换说明 (conversion specification),它们指定了如何把数据转换成可显示的形式。在%和转换字符之间 插入修饰符可修饰基本的转换说明。 类型匹配:函数打印数据的指令要与待打印数据的类型相匹配。例如, 打印整数时使用%d,打印字符时使用%c。 待打印项:它们可以是变量、常量,甚 至是在打印之前先要计算的表达式。

2、转化说明 与 修饰符(含标记)

转化说明 主要描述了 按什么数据类型输出。如%d 以十进制有符号的整数,%u 十进制无符号整数,%x 以十六进制无符号整数(字符小写,X字符大写) %c单个字符,%s字符串 %p 指针输出。(由于使用%符号来标识转换说明,因此打印%符号约定使用两个%) 在这里插入图片描述 修饰符:在%和转换字符之间插入修饰符可修饰基本的转换说明,用于描述 (1)在打印位置的对齐方式(2)长度不够时前导空格或者0 (3)特殊进制添加前缀-#使用0开头打印8进制,0x开头打印十六进制。(4)最小宽度 (5)精度 (6)标识整形长度类型,如h位short长度、hh为char长度类型、l为long长度类型,ll为longlong型长度类型; 修饰符顺序要求: 如果要插入多个字符,其书写顺序应该与表 中列出的顺序相同。不是所有的组合都可行。 下表列出可作为修饰符的合法字符: 在这里插入图片描述在这里插入图片描述

3、转化说明与待打印项不匹配分析

格式字符串中的转换说明一定要与后面的每个项相匹配,若忘记这个基 本要求会导致严重的后果。 1、数量不匹配问题 printf(“The score was Squids %d, Slugs %d.\n”, score1); 这里,第2个%d没有对应任何项。系统不同,导致的结果也不同。出现这种问题最好的状况是得到无意义的值,也可能保留系统堆栈中的关键信息,被攻击获取。 2、类型不匹配问题 通常都有多种选 择。例如,如果要打印一个int类型的值,可以使用%d、%x或%o。打印double类型的值时,可使用%f、%e或%g。但是如果不匹配时,如下: 符号不匹配 :一个负数按无符号输出,输出其负数按补码表示的整数。 长度不匹配 :使用短类型输出长类型时,会发生截断。只读取其最低几个和短类型等长的字节(类似除余)。 混淆整型和浮点型:使用整形打印浮点数会失败,而使用浮点数打印整形时,printf会尝试读取按浮点数长度的预期字节长度,如果整形小于预期会出现越界读取,打印出来的数据无意义。

#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); // 输出 num as short and unsigned short: 336 336 printf("-num as short and unsigned short: %hd %hu\n", mnum,mnum); // 输出 -num as short and unsigned short: -336 65200 /* short 大小是2字节使用二进制补码,0~32767代 表正数,32768~65535为负数。 65535表示-1,65534 表示-2,-336表示为65200 */ printf("num as int and char: %d %c\n", num, num); // 输出 num as int and char: 336 P /*只看储存336的2字节中的后1字节,截断相当于用一 个整数除以256, 只保留其余数是80,对应的ASCII值 是字符P */ printf("WORDS as int, short, and char: %d %hd %c\n",WORDS,WORDS,WORDS); //输出 WORDS as int, short, and char: 65618 82 R return 0; } 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); // 输出 3.0e+000 3.0e+000 3.1e+046 3.6e+266 /* %e转换说 明让printf函数认为待打印的值是double类型8字节。 除了查看n3的4字节外,还会相邻的4字节共8字节单元组合解释成浮点数, 最终得到的结果 是无意义的值 */ printf("%ld %ld\n", n3, n4); // 输出 2000000000 1234567890 printf("%ld %ld %ld %ld\n", n1, n2, n3, n4); // 输出 0 1074266112 0 1074266112 /* %ld转换说明打印浮点数会失败,在 里用%ld打印long类型的数也失败, 问题出在C如何把信息传递给函数。具体情况因编译器实现而异 */ return 0; } 4、printf的参数传递机制

参数传递机制因编译器实现(入栈的顺序关系)而异。要特别注意 上一个举例中的如printf("%ld %ld %ld %ld\n", n1, n2, n3, n4);

int main(void) { float n1 = 3.0; double n2 = 3.0; long n3 = 2000000000; long n4 = 1234567890; printf("%ld %ld %ld %ld\n", n1, n2, n3, n4); // 输出 0 1074266112 0 1074266112 /* %ld转换说明打印浮点数会失败,在 里用%ld打印long类型的数也失败,问题出在C如何把信息传递给函数。 具体情况因编译器实现而异 */ return 0; }

1、程序把传入的值放入被称为栈(stack)的内存区域。 计算机根据变量类型(不是根据转换说明)把这些值放入栈中。常见从右往左顺序入栈。因此,n1被 储存在栈中,占8字节(float类型被转换成double类型)。同样,n2也在栈中 占8字节,而n3和n4在栈中分别占4字节。 2、控制转到printf()函数读取栈中内容 该函 数根据转换说明(不是根据变量类型)从栈中读取值。%ld转换说明表明 printf()应该读取4字节,所以printf()读取栈中的前4字节作为第1个值。这是 n1的前半部分,将被解释成一个long类型的整数。根据下一个%ld转换说 明,printf()再读取4字节,这是n1的后半部分,将被解释成第2个long类型的 整数。类似地,根据第3个和第4个%ld,printf()读取n2的前半部 分和后半部分,并解释成两个long类型的整数。因此,对于n3和n4,虽然用 对了转换说明,但printf()还是读错了字节。 3、printf("%d %d %d %d ",i++,–i,++i,i++)说明 不同编译器产生不同的结果,原因主要有1:入栈的顺序关系 2、i++和++i操作符和入栈之间的顺序关系。 如使用vscode中测试gcc编译器:先处理完所有自增自减之后再最后统一一次性的入栈(并且如果发生i++或者i–会先缓存值,对应成员入栈时按缓存值计算入栈值,如果是–i或者++i则无缓存 使用最终i结果计算入栈值) ,测试如下:

int main(void) { int i = 8; printf("%d,%d,%d,%d\n", ++i, --i, i++, i--); // 输出 8,8,7,8 /* 1、先处理++/-- i++(i--):先缓存i的原始值,然后i自增(自减)。最后入栈时,用缓存的i的原始值入栈。 ++i(--i):i自增,不缓存i的原始值。最后入栈时,是更新后的最终i。 i--: 缓存8,i=7 i++:缓存7,i=8 --i:i=7 ++i:i=8(到这一步时i=8,也就是说最后入栈之前i的最终值为8,因此++i和--i的入栈值都是8) 2、最后入栈 第一个入栈值8(存在缓存),第二个入栈值7(存在缓存),第三个入栈值8(此时的i值),第四个入栈8(此时的i值) 所以这时候栈的数据是:8,8,7,8.(从顶到底)。 */ i = 0; printf("%d %d %d %d\n", i+1, i++, i+2, ++i); // 输出 3 1 3 2 /* 先处理++/--:++i:i为1, i++:缓存1,i为2,入栈:第一个为2(此时i值),第二个为3,第三个 为缓存1,第四个为3, 所以这时候栈的数据是 3 1 3 2 (从顶到底)*/ return 0; } 二、scanf() 1、基本用法–scanf( 格式字符串, 地址1, 地址2,…);

通用终端格式化输入函数,它从标准输入设备(键盘) 读取输入的信息,给变量赋值。 数据分段:scanf()函数使用空白(换行符、制表符和空格)把输入分成多个字段。 在依次把转换说明和字段匹配时跳过空白。只要在每个输入项之间输入至少一个换行 符、空格或制表符即可,可以在一行或多行输入。唯一例外的是%c会读取每个字符,包括空白。 (1)以试读取一个%d举例: 每次读取一个字符*跳过所有的 空白字符,直至遇到第1个非空白字符才开始读取。因为要读取整数,所以希望发现一个数字字符或者一个符号(+或-)。如果找到一个数字或 符号,保存并读取下一个,直至遇到非数字字符,便认为读到了整数的末尾。然后把非数字字符放回输入。这意味着程序在下一次读取输入时,首先读 到的是上一次读取丢弃的非数字字符。如果使用字段宽度,scanf()会在字段结尾或第1个空白字符处停止读取 (满足两个条件之一便停止)。 (2)其他类型说明: 读取输入和用%d 的情况相同。区别在于 scanf()会把更多字符识别成数字的一部分。%x转换说明要求scanf()识 别十六进制数a~f和A~F。浮点转换说明要求scanf()识别小数点、e记数法 (指数记数法)和新增的p记数法(十六进制指数记数法)。 %s 转换说明,scanf()会读取除空白以外的所有字符。scanf()跳 过空白开始读取第 1 个非空白字符,并保存非空白字符直到再次遇到空白。当scanf()把字符串放进指定数组中时,它会在字符序列的末尾加上’\0。

char str[80]; scanf("%s",str); // 输入 test is good printf("%s",str); // 输出 test (遇到第一个空白字符结束)

解决读取包含空格的字符串问题,使用扫描字符集合[],多个字符串的输入,并对结束符进行自定义。

char str[80]; scanf("%[^\n]",str); // 输入 test is good // 使用扫描字符集合[],多个字符串的输入,并对结束符进行自定义 printf("%s",str); // 输出 test is good return 0; 2、转化说明 与 修饰符(含标记)

scanf()函数所用的转换说明与printf()函数几乎相同。主要的区别是,对 于float类型和double类型,printf()都使用%f、%e、%E、%g和%G转换说 明。而scanf()只把它们用于float类型,对于double类型时要使用l修饰符。表 4.6列出了C99标准中常用的转换说明。 在这里插入图片描述 在这里插入图片描述 在这里插入图片描述

4、格式字符串 包含 普通字符

scanf()函数允许把普通字符放在格式字符串中,除空格字符外的普通字 符必须与输入字符串严格匹配。 如scanf("%d,%d", &n, &m);中的‘,’为普通字符,用户将输入一个数字、一个逗号,然后再输入一个数字。(%d后面紧跟逗号,所以必须在输入一个数字输入一 个逗号);如果为scanf("%d ,%d", &n, &m),第一个%d后包含空格,空白意味着跳过下一个输入项前面的所有空白,因此第一个输入后可以有空格再出现逗号。

scanf("%d,%d", &n, &m); /* 情况1:第一个%d后面紧跟',' (第一个数输入完后必须经跟‘,’,‘,’到第二个数可以有空格) 输入可以用:123,234,123, 234 不能使用的输入:123 ,234 (‘,’前有空格引起第二次读取‘,’失败,m未i输入) */ scanf("%d,%d", &n, &m); /* 情况2:第一个%d后面有空格连接',' 输入可以用:123,234,123, 234,123 ,234,123 , 234 */

scanf( )的格式字符串中加入\n的问题,当出现scanf("%d\n",&a)写法时,按照“整型数字 回车”的格式读取,读到回车之后,由于缓冲区空白,程序停滞,等待键盘输入,要等再接收到一个非空白符输入之后,该scanf语句才结束,接着才输出。

int a; scanf("%d\n",&a);/*注意%d后的\n*/ //单纯输入123后,会继续等待输入,此时继续输入回车无效的,需要再输入一个非空字符,scanf才结束 printf("%d",a); 5、scanf的缓冲区问题

scanf()函数应该只是扫描stdin流,输入的数据都存再stdin的缓冲区,被跳过和取出的数据,系统会将它从缓冲区中释放掉。未被跳过或取出的数据,系统会将它一直放在缓冲区中,直到下一个 scanf 来获取。

char str1[80]; char str2[80]; char str3[80]; scanf("%s",str1); // 输入 test is good printf("%s\n",str1); // 输出 test scanf("%s",str2); // 无需输入,缓冲区还有数据 scanf("%s",str3);// 无需输入,缓冲区还有数据 printf("%s\n",str2); // 输出 is printf("%s\n",str3); // 输出 good

对于参数%d:会忽略缓冲区开头的空白符;对于参数 %c直接读取缓冲区的第一个字符(无论这个字符是什么);

int a; char c; scanf("%d",&a); // 输入 123 scanf("%c",&c); // 直接执行了,由于缓存区还有一个'\n'回车符,c直接获取了 printf("%d %d",a,(int)c); // 输出 123 10 (换行\n的asci码为10) return 0;

为了解决缓存区问题,可以使用fflush(stdin)清空缓存区,或者getchar()吃掉回车,或者下一行%c前加空格丢弃空白字符。

int a; char c; scanf("%d",&a); // 输入 123 fflush(stdin); // 清空缓存区中数据即回车(也可以用getchar()吃掉,或者在下一行%c前加空格) scanf("%c",&c); // 输入5 printf("%d %d",a,(int)c); // 输出 123 53 (字符5的asci码值53) 6、scanf返回值

scanf()函数返回成功读取的项数。如果没有读取任何项,且需要读取一 个数字而用户却输入一个非数值字符串,scanf()便返回0。 当scanf()检测 到“文件结尾”时,会返回EOF(EOF是stdio.h中定义的特殊值,通常用 #define指令把EOF定义为-1)。我们将在第6章中讨论文件结尾的相关内容 以及如何利用scanf()的返回值。在读者学会if语句和while语句后,便可使用 scanf()的返回值来检测和处理不匹配的输入。



【本文地址】

公司简介

联系我们

今日新闻


点击排行

实验室常用的仪器、试剂和
说到实验室常用到的东西,主要就分为仪器、试剂和耗
不用再找了,全球10大实验
01、赛默飞世尔科技(热电)Thermo Fisher Scientif
三代水柜的量产巅峰T-72坦
作者:寞寒最近,西边闹腾挺大,本来小寞以为忙完这
通风柜跟实验室通风系统有
说到通风柜跟实验室通风,不少人都纠结二者到底是不
集消毒杀菌、烘干收纳为一
厨房是家里细菌较多的地方,潮湿的环境、没有完全密
实验室设备之全钢实验台如
全钢实验台是实验室家具中较为重要的家具之一,很多

推荐新闻


图片新闻

实验室药品柜的特性有哪些
实验室药品柜是实验室家具的重要组成部分之一,主要
小学科学实验中有哪些教学
计算机 计算器 一般 打孔器 打气筒 仪器车 显微镜
实验室各种仪器原理动图讲
1.紫外分光光谱UV分析原理:吸收紫外光能量,引起分
高中化学常见仪器及实验装
1、可加热仪器:2、计量仪器:(1)仪器A的名称:量
微生物操作主要设备和器具
今天盘点一下微生物操作主要设备和器具,别嫌我啰嗦
浅谈通风柜使用基本常识
 众所周知,通风柜功能中最主要的就是排气功能。在

专题文章

    CopyRight 2018-2019 实验室设备网 版权所有 win10的实时保护怎么永久关闭