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

版权声明:共同提高:) https://blog.csdn.net/u011436427/article/details/83065797

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

扫描二维码关注公众号,回复: 3597858 查看本文章

具体例子如下:

本实例中,用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类型。

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

猜你喜欢

转载自blog.csdn.net/u011436427/article/details/83065797