C语言实战105例子——实例1 一个价值“三天”的bug

scanf家族的使用

int fscanf (FILE *stream»char const *format, …)
int scanf (char const *format,…)
int sscanf(char const *string,char const *format, …)

每个函数原型中的省略号表示一个可变长度的指针列表
从输入转换而来的值逐个存储到这些指针参数所指向的内存位置
fscanf的输入源是作为参数给出的流(FILE *stream)
scanf的输入源是标准输入
sscanf则是从第1个参数(char const *string)给出的字符串中读入字符

这些函数的功能都是从输入源读取字符,然后根据format字符串指定的格式代码对读入的字符进行相应转换。函数的返回值就是被转换的输入值的数目。

scanf函数家族中的format字符串参数包含的字符有空白字符、格式代码和其他字符
空白字符可与与输入中的任意个空白字符相匹配,在处理过程中会被忽略;
格式代码就是要指定函数如何解释接下来的输入字符;
除了空白字符和格式代码之外的其它字符中可以出现,也可不出现,若他们出现在格式字符串中,下一个输入的字符必须与之匹配,若匹配,该输入字符将被丢弃,若不匹配,函数就不在读取而直接返回。

当格式化字符串到达末尾或者读取的输入不再匹配格式字符串所指定的类型时,输入就停止

格式代码就是一个字符,用干指定输入的字符如何被解释开始标志是一个百分号( % ) , 百分号后面可以跟如下4 种字符:

( 1 ) 星 号 (* ) : 并不存储转换后的值,而是将其丢弃,可以用来跳过不需要的输入字符。
( 2 ) 宽 度一个非负整数):用来限制被读取转换的字符个数,在没有指定宽度的情况下,函数会连续读入字符直到遇到空白字符为止
( 3 ) 限定符:用干修改有些格式代码的含义,比如在格式代码"%d " 中使用限定符"h ", 即 "%h d " , 那 么 " d " 表示的不再是默认整型,而 是 short int。
( 4 ) 格式代码:也就是说格式代码后面还可以有格式代码

在这里插入图片描述

在使用scanf函数家族的时候,特别注意两点。
( 1 ) 指针参数的类型必须是对应格式代码的正确类型。
由 干 C 语言采用传址参数传递机制,把内存位置作为参数传递给函数的惟一方法就是传递一个指向该位置的指针。在使用scanf数家族的时候,一个非常容易出现的错误就是忘记加 上 省 略 地 址 符 号 将 导 致 将 变 量 的 值 作 为 参 数 传 递 给 函 数 ,而 scanf函数家族却把它解释为指针。这会导致一个不可谓料的内存位置的数据被改写。

( 2 ) 要正确使用限定符。
限定符的自的是为了指定参数的长度。**如果整形参数比缺省的整形参数更长或者更短时,在格式代码中省略限定符就是一个常见的错误。**对干浮点类型也是如此,如果省略了限定符,可能导致一个较长的变量只有部分被初始化,或者- ‘ 个较短变量的邻近变量也被修改(这取决于它们的相对长度)

具体例子如下:

本实例中,用fgets:从指定的stream中读取字符并将他们复制到buffer中,当他读取一个换行符并存储到缓冲区之后就不再读取本实例中的stream被指定为标准输入流
fgets函数原型为:

char ♦fgets(char *buffer,int BUFFER,SIZE’FILE *stream)

用到sscanf来处理缓冲区buffer中的数据

#include<stdio.h>
#include<stdlib.h>
#define BUFFERSIZE 1024  /*允许处理的最长行有1024个字符*/
int main()
{
	int a,b,sum;         /*将输入的两个数分别存储在变量a和b中,sum=a+b*/
	char buffer[BUFFERSIZE];
	printf("***********************************\n");
	printf("*  Welcome to use our counter     *\n");
	printf("*  Input two integers in one line *\n");
	printf("*  The sum will be printed        *\n");
	printf("*  Input the char '#' to quit     *\n");
	printf("***********************************\n");
	/*从标准输入(stdin)读取输入的数据,存储在buffer中.
	如果读取的第一个字符是'#'则退出程序*/
	while((fgets(buffer,BUFFERSIZE,stdin)!=NULL)&&(buffer[0]!='#'))
	{
		if(sscanf(buffer,"%d %d",&a,&b)!=2)              /*处理存储在buffer中的一行数据*/
			{
				printf("The input is skipped:%s",buffer);/*如果输入的数字不是两个则报错*/
				continue;                               /*继续读取下一组数据*/			
			}
		sum=a+b;                                         /*计算a与b的和*/
		printf("The sum of %d and %d is %d\n",a,b,sum);  /*输出计算结果*/
	}

	
	system("pause");
	return 0;
}

在这里插入图片描述

=价值三天的bug===========
将a, b 的声明变成了 unsigned short类型。这时错误的运行结果

#include<stdio.h>
#include<stdlib.h>
#define BUFFERSIZE 1024  /*允许处理的最长行有1024个字符*/
int main()
{
	unsigned short a,b,sum;         /*将输入的两个数分别存储在变量a和b中,sum=a+b*/
	char buffer[BUFFERSIZE];
	printf("***********************************\n");
	printf("*  Welcome to use our counter     *\n");
	printf("*  Input two integers in one line *\n");
	printf("*  The sum will be printed        *\n");
	printf("*  Input the char '#' to quit  s  *\n");
	printf("***********************************\n");
	/*从标准输入(stdin)读取输入的数据,存储在buffer中.
	如果读取的第一个字符是'#'则退出程序*/
	while((fgets(buffer,BUFFERSIZE,stdin)!=NULL)&&(buffer[0]!='#'))
	{
		if(sscanf(buffer,"%d %d",&a,&b)!=2)            /*处理存储在buffer中的一行数据*/
			fprintf(stderr,"The input is skipped:%s",buffer);
		sum=a+b;                                       /*计算a与b的和*/
		printf("The sum of %d and %d is %d\n",a,b,sum);/*输出计算结果*/
	}

	
  system("pause");
	return 0;
}

在这里插入图片描述

解释:
因为 sscanf在处理整型数据时,默认的整 型 是 int类型的,而unsigned short比缺省的整型值短,这就导致较短变量的邻近变量也被修改,根本原因就在干忽略了限定符的使用。
因此修正程序:

if(sscanf(buffer,"%hd %hd",&a,&b)!=2)            /*处理存储在buffer中的一行数据*/

将sscanf的format格式字符串加上限定符以后,与定义的变量a,b类型保持一致,都是short类型。

下面列出限定符对常用的格式码的含义的修改:
在这里插入图片描述

第1部分 基础篇 实例1 一个价值三天”的BUG 2 实例2 灵活使用递增(递减)操作符 5 实例3 算术运算符计算器 7 实例4 逻辑运算符计算器 9 实例5 IP地址解析 11 实例6 用if…else语句解决奖金发放问题 13 实例7 用for循环模拟自由落体 16 实例8 用while语句求n! 19 实例9 模拟银行常用打印程序 22 实例10 使用一维数组统计选票 26 实例11 使用二维数组统计学生成绩 29 实例12 简单的计算器 32 实例13 时钟程序 35 实例14 华氏温度和摄氏温度的相互转换 38 实例15 SimpleDebug函数应用 40 第2部分 数值计算与数据结构篇 实例16 常用的几种排序方法 46 实例17 广度优先搜索及深度优先搜索 53 实例18 实现基本的串操作 59 实例19 计算各点到源点的最短距离 62 实例20 储油问题 65 实例21 中奖彩球问题 67 实例22 0-1背包问题 69 实例23 阶梯计数问题 72 实例24 二叉树算法集 74 实例25 模拟LRU页面置换算法 79 实例26 大整数阶乘新思路 82 实例27 银行事件驱动模拟程序 84 实例28 模拟迷宫探路 87 实例29 实现高随机度随机序列 89 实例30 停车场管理系统 91 第3部分 文本屏幕与文件操作篇 实例31 菜单实现 96 实例32 窗口制作 97 实例33 模拟屏幕保护程序 100 实例34 文件读写基本操作 102 实例35 格式化读写文件 105 实例36 成块读写操作 107 实例37 随机读写文件 108 实例38 文件的加密和解密 111 实例39 实现两个文件的连接 113 实例40 实现两个文件信息的合并 116 实例41 文件信息统计 118 实例42 文件分割实例 121 实例43 同时显示两个文件的内容 123 实例44 模拟Linux环境下的vi编辑器 124 实例45 文件操作综合应用——银行账户管理 128 第4部分 病毒与安全篇 实例46 实用内存清理程序 134 实例47 如何检测Sniffer  136 实例48 加密DOS批处理程序 139 实例49 使用栈实现密码设置 141 实例50 远程缓冲区溢出漏洞利用程序 144 实例51 简易漏洞扫描器 146 实例52 文件病毒检测程序 149 实例53 监测内存泄露与溢出 150 实例54 实现traceroute命令 152 实例55 实现ping程序功能 154 实例56 获取Linux本机IP地址 157 实例57 实现扩展内存的访问 161 实例58 随机加密程序 164 实例59 MD5加密程序 165 实例60 RSA加密实例 168 第5部分 图形篇 实例61 制作表格 172 实例62 用画线函数作出的图案 174 实例63 多样的椭圆 176 实例64 多变的立方体 177 实例65 简易时钟 178 实例66 跳动的小球 181 实例67 用柱状图表示学生成绩各分数段比率 183 实例68 EGA/VGA屏幕存储 187 实例69 按钮制作 190 实例70 三维视图制作 193 实例71 红旗图案制作 194 实例72 火焰动画制作 196 实例73 模拟水纹扩散 199 实例74 彩色的Photo Frame  201 实例75 火箭发射演示 203 第6部分 系统篇 实例76 恢复内存文本 208 实例77 挽救磁盘数据 210 实例78 建立和隐藏多个PRI DOS分区 213 实例79 简单的DOS下的中断服务程序 216 实例80 文件名分析程序 219 实例81 鼠标中断处理 222 实例82 实现磁盘数据的整体加密 224 实例83 揭开CMOS密码 227 实例84 获取网卡信息 229 实例85 创建自己的设备 231 实例86 设置应用程序启动密码 233 实例87 获取系统配置信息 236 实例88 硬件检测 239 实例89 管道通信 241 实例90 程序自杀技术实现 244 第7部分 游戏篇 实例91 连续击键游戏 248 实例92 掷骰子游戏 250 实例93 弹力球 252 实例94 俄罗斯方块 253 实例95 24点扑克牌游戏 257 实例96 贪吃蛇 260 实例97 潜水艇大战 262 实例98 机器人大战 265 实例99 图形模式下的搬运工 266 实例100 十全十美游戏 269 第8部分 综合篇 实例101 强大的通信录 274 实例102 模拟Windows下UltraEdit程序 277 实例103 轻松实现个人理财 279 实例104 竞技比赛打分系统 281 实例105 火车订票系统 286
第1部分 基础篇 实例1 一个价值三天”的BUG 2 实例2 灵活使用递增(递减)操作符 5 实例3 算术运算符计算器 7 实例4 逻辑运算符计算器 9 实例5 IP地址解析 11 实例6 用if…else语句解决奖金发放问题 13 实例7 用for循环模拟自由落体 16 实例8 用while语句求n! 19 实例9 模拟银行常用打印程序 22 实例10 使用一维数组统计选票 26 实例11 使用二维数组统计学生成绩 29 实例12 简单的计算器 32 实例13 时钟程序 35 实例14 华氏温度和摄氏温度的相互转换 38 实例15 SimpleDebug函数应用 40 第2部分 数值计算与数据结构篇 实例16 常用的几种排序方法 46 实例17 广度优先搜索及深度优先搜索 53 实例18 实现基本的串操作 59 实例19 计算各点到源点的最短距离 62 实例20 储油问题 65 实例21 中奖彩球问题 67 实例22 0-1背包问题 69 实例23 阶梯计数问题 72 实例24 二叉树算法集 74 实例25 模拟LRU页面置换算法 79 实例26 大整数阶乘新思路 82 实例27 银行事件驱动模拟程序 84 实例28 模拟迷宫探路 87 实例29 实现高随机度随机序列 89 实例30 停车场管理系统 91 第3部分 文本屏幕与文件操作篇 实例31 菜单实现 96 实例32 窗口制作 97 实例33 模拟屏幕保护程序 100 实例34 文件读写基本操作 102 实例35 格式化读写文件 105 实例36 成块读写操作 107 实例37 随机读写文件 108 实例38 文件的加密和解密 111 实例39 实现两个文件的连接 113 实例40 实现两个文件信息的合并 116 实例41 文件信息统计 118 实例42 文件分割实例 121 实例43 同时显示两个文件的内容 123 实例44 模拟Linux环境下的vi编辑器 124 实例45 文件操作综合应用——银行账户管理 128 第4部分 病毒与安全篇 实例46 实用内存清理程序 134 实例47 如何检测Sniffer  136 实例48 加密DOS批处理程序 139 实例49 使用栈实现密码设置 141 实例50 远程缓冲区溢出漏洞利用程序 144 实例51 简易漏洞扫描器 146 实例52 文件病毒检测程序 149 实例53 监测内存泄露与溢出 150 实例54 实现traceroute命令 152 实例55 实现ping程序功能 154 实例56 获取Linux本机IP地址 157 实例57 实现扩展内存的访问 161 实例58 随机加密程序 164 实例59 MD5加密程序 165 实例60 RSA加密实例 168 第5部分 图形篇 实例61 制作表格 172 实例62 用画线函数作出的图案 174 实例63 多样的椭圆 176 实例64 多变的立方体 177 实例65 简易时钟 178 实例66 跳动的小球 181 实例67 用柱状图表示学生成绩各分数段比率 183 实例68 EGA/VGA屏幕存储 187 实例69 按钮制作 190 实例70 三维视图制作 193 实例71 红旗图案制作 194 实例72 火焰动画制作 196 实例73 模拟水纹扩散 199 实例74 彩色的Photo Frame  201 实例75 火箭发射演示 203 第6部分 系统篇 实例76 恢复内存文本 208 实例77 挽救磁盘数据 210 实例78 建立和隐藏多个PRI DOS分区 213 实例79 简单的DOS下的中断服务程序 216 实例80 文件名分析程序 219 实例81 鼠标中断处理 222 实例82 实现磁盘数据的整体加密 224 实例83 揭开CMOS密码 227 实例84 获取网卡信息 229 实例85 创建自己的设备 231 实例86 设置应用程序启动密码 233 实例87 获取系统配置信息 236 实例88 硬件检测 239 实例89 管道通信 241 实例90 程序自杀技术实现 244 第7部分 游戏篇 实例91 连续击键游戏 248 实例92 掷骰子游戏 250 实例93 弹力球 252 实例94 俄罗斯方块 253 实例95 24点扑克牌游戏 257 实例96 贪吃蛇 260 实例97 潜水艇大战 262 实例98 机器人大战 265 实例99 图形模式下的搬运工 266 实例100 十全十美游戏 269 第8部分 综合篇 实例101 强大的通信录 274 实例102 模拟Windows下UltraEdit程序 277 实例103 轻松实现个人理财 279 实例104 竞技比赛打分系统 281 实例105 火车订票系统 286
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

喜欢打篮球的普通人

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值