【转载】flag标志什么?哦,它标志代码馊了
几乎每次在代码中发现flag变量,我总是能嗅到一股馊味。不管你闻没闻到,反正我闻到了。
在代码中,flag通常作为标志变量的名字。但问题在于,不是所有的问题或代码都需要使用这种标志变量,更不是使用标志变量一定要用flag这个名字。需要使用标志变量的问题只有一小部分而已,况且即使使用标志变量,取flag这个名字也往往是一种草率的下策。
然而由于基础不扎实及某些书籍的误导等缘故,不少初学者往往特别善于滥用flag。几乎在任何场合他们都有能力把这个flag使用上且用得出神入化般的别扭,就如同用if语句和goto语句构造循环结构一样,甚至比这更坏。这种情况是由于不熟悉基本的代码结构所致。
另一种滥用flag的情况则是,由于最初的设计千疮百孔漏洞百出,等到发现时用flag打上丑陋的补丁。
下面开始阅读代码,请自备口罩。
样本代码1
#include <stdio.h>
#define N 10
int main()
{
int num [N],number,flag=1,c;
char name[N][8];
/*……*/
while(flag==1)
{printf("\ninput number to look for:");
scanf("%d",&number);
search(number,num,name);
printf("continue ot not(Y/N)?");
getchar();
c=getchar();
if(c=='N'||c=='n')
flag=0;
}
/*……*/
return 0;
}
*——谭浩强 ,《C程序设计(第四版)学习辅导》,清华大学出版社,2010年7月,p92*
这段代码中的while语句是明显的缺陷,因为从这个程序段的功能来说使用do-while才是自然的表达。
#include <stdio.h>
#define N 10
int main( void )
{
int num [N],number,flag=1,c;
char name[N][8];
/*……*/
do{
printf("\ninput number to look for:");
scanf("%d",&number);
search(number,num,name);
printf("continue ot not(Y/N)?");
getchar();
c=getchar();
if(c=='N'||c=='n')
flag=0;
}
while(flag==1);
/*……*/
return 0;
}
其次flag标志变量根本没有必要,代码完全可以写成
#include <stdio.h>
#define N 10
int main( void )
{
int num [N],number,flag=1,c;
char name[N][8];
/*……*/
do{
printf("\ninput number to look for:");
scanf("%d",&number);
search(number,num,name);
printf("continue ot not(Y/N)?");
getchar();
c = getchar() ;
}
while(!(c=='N'||c=='n'));
/*……*/
return 0;
}
最后,getchar();也用得十分蹩脚,它的用意是读入前面调用scanf("%d",&number)输入一个十进制整数后输入的<CR>(回车换行)。但实际上如果程序使用者输入十进制整数后又顺手按了一个<SP>空格再回车,这个“getchar();”就会因为读入了空格而导致后面的“c = getchar() ;”读取N、n、Y、y这几个文字字符的企图遭到失败。更好的写法应该是
#include <stdio.h>
#define N 10
int main( void )
{
int num [N],number,flag=1,c;
char name[N][8];
/*……*/
do{
printf("\ninput number to look for:");
scanf("%d",&number);
search(number,num,name);
printf("continue ot not(Y/N)?");
scanf("\n%c",&c );
}
while(!(c=='N'||c=='n'));
/*……*/
return 0;
}
与“样本代码1”对比一下,不难发现样本代码1中的flag有多么拙劣。
样本代码2
#define N 10
char str[N];
int main()
{
/*……*/
int i,flag;
for(flag=1;flag==1;)
{scanf("%s",&str);
if(strlen(str)>N)
printf("string too long,input again!");
else
flag=0;
}
/*……*/
}
* ——谭浩强 ,《C程序设计(第四版)学习辅导》,清华大学出版社,2010年7月,p85*
这段代码的flag用得更加可惊可愕,它甚至不如写成功能等价的
#define N 10
char str[N];
int main(void)
{
/*……*/
int i,flag;
do {
scanf("%s",&str);
if(strlen(str)>N)
printf("string too long,input again!");
else
break;
}
while(1);
/*……*/
}
由此不难看出那个flag有多么多余。然而这个写法依旧啰嗦,更简洁的写法是:
#define N 10
char str[N];
int main(void)
{
/*……*/
do {
scanf("%s",&str);
}
while(strlen(str)>N && printf("string too long,input again!"));
/*……*/
}
这写法虽然简洁,然而依然带着样本代码中原来的毛病,这个毛病就是scanf("%s",&str);中的&str。因为str的定义是 char str[10];,而与转换格式%s相对应的参数应该是char *类型的指针,所以这个调用应该写为scanf("%s",str);。
即便如此,代码依然是错误的。原代码企图在strlen(str)>N的情况下重新输入,这是幼稚的一厢情愿,而且有着双重的错误。从逻辑来说,strlen(str) 等于N时就已经是越界使用数组了。所以strlen(str)>N这个关系表达式不应该使用“>”运算。从实践的角度来说strlen(str)>=N时的越界已然对内存中的数据存储造成了破坏,程序以后的行为是建立在错误的基础上,最后的结果必然是错误的,至少是不可靠的。而结果不可靠,对于程序来说就是一种错误。
那么,这段代码应该怎样写呢?由于样本代码2要解决的问题是对十个字符排序,这里的要求是输入10个字符。这根本不用写一个循环语句反复折腾,只需简单地
#define N 10
char str[N];
int main(void)
{
/*……*/
int i;
scanf("%10c" , str ) ;
/*……*/
}
即可。
当然,也许有人会指责scanf("%10c" , str )没有用上N这个宏,这个指责确实有道理。其实用N这个宏来写scanf("%10c" , str )也并非什么难事,代码可以这样写:
#define N 10
#define FMT(x) ("%"NUM(x)"c")
#define NUM(x) #x
char str[N];
int main(void)
{
/*……*/
int i;
scanf( FMT(N) , str ) ;
/*……*/
}
转载自https://www.cnblogs.com/pmer/archive/2011/11/10/2245012.html
【转载】flag标志什么?哦,它标志代码馊了的更多相关文章
- 转载--Typecho install.php 反序列化导致任意代码执行
转载--Typecho install.php 反序列化导致任意代码执行 原文链接(http://p0sec.net/index.php/archives/114/) 0x00 前言 漏洞公布已经过去 ...
- [转载]关于在Linux下上传代码至Github
刚开始使用Github没多长时间,所以很多地方不太熟练,看到阿里云上有一篇文章写得不错,故转载过来. 转载自:https://www.aliyun.com/jiaocheng/122729.html ...
- 【转载】PDB命令行调试Python代码
转载自这里. (博主按:PDB调试python代码和用GDB调试c++代码很类似) 你有多少次陷入不得不更改别人代码的境地?如果你是一个开发团队的一员,那么你遇到上述境地的次数比你想要的还要多.然而, ...
- stm32之ADC应用实例(单通道、多通道、基于DMA)-转载精华帖,最后一部分的代码是精华
硬件:STM32F103VCT6 开发工具:Keil uVision4 下载调试工具:ARM仿真器网上资料很多,这里做一个详细的整合.(也不是很详细,但很通俗).所用的芯片内嵌3个12位的 ...
- [转载]Sublime Text 2 - 性感无比的代码编辑器!程序员必备神器!跨平台支持Win/Mac/Linux
代码编辑器或者文本编辑器,对于程序员来说,就像剑与战士一样,谁都想拥有一把可以随心驾驭且锋利无比的宝剑,而每一位程序员,同样会去追求最适合自己的强大.灵活的编辑器,相信你和我一样,都不会例外. 我用过 ...
- 转载:用Source Insight中看Python代码
在Source Insight中看Python代码 http://blog.csdn.net/lvming404/archive/2009/03/18/4000394.aspx SI是个很强大的代码查 ...
- [转载]Delphi 版 everything、光速搜索代码
近日没啥事情,研究了一下 everything.光速搜索原理.花了一个礼拜时间,终于搞定. 废话不多说,直接上代码: unit uMFTSearchFile; { dbyoung@sina.com 2 ...
- [转载]Jupyter Notebook中自动补全代码
原文地址:https://yq.aliyun.com/articles/667928 在公众号之前的文章中,已经介绍了在Jupyter Notebook中设置主题以及输出代码文件到pdf文件中,本文来 ...
- [转载]获取当前日期和农历的js代码
原文地址: http://www.cnblogs.com/Gnepner/archive/2011/09/07/2169822.html 获取当前日期时间: function GetCurrentDa ...
随机推荐
- MeteoInfo-Java解析与绘图教程(一)
MeteoInfo-Java解析与绘图教程(一) 已经进入开发行业很多年了,这两年一直从事气象开发行业,为此对气象绘图有了新的见解 像色斑图与卫星图一直都有python去绘制,在偶然的情况下,我接触到 ...
- Spring Boot 配置中的敏感信息如何保护?
在之前的系列教程中,我们已经介绍了非常多关于Spring Boot配置文件中的各种细节用法,比如:参数间的引用.随机数的应用.命令行参数的使用.多环境的配置管理等等. 这些配置相关的知识都是Sprin ...
- 关于Feign、Jackson、RabbitMQ、Jrebel插件的开发中遇到的问题
在工作实际开发中需要开发一个消息模块对外提供统一的接口feign调用提供消息加载到MQ队列的服务,采用泛型的形式. 刚开始搭建好之后,正好需要做一个全局的日志添加到zuul网关中,通过网关feign ...
- python3+telnetlib实现简单自动测试
1 telnetlib介绍 1.1 简介 官方介绍文档:telnetlib -- Telnet 客户端 - Python 3.9.6 文档 telnetlib 模块提供一个实现Telnet协议的类 T ...
- SQL注入:基本查询原理
SQL注入概述 sql注入不需要精通sql的各种命令,只需要了解几个命令并会使用即可. SQL注入:一种针对于数据库的攻击 现在的web网站都需要数据库的支持. SQL部分重要内容: 库:databa ...
- noip模拟45[真是啥也不会]
noip模拟45 solutions 真是一个题都不会了,然而考完试之后我在10min之内切掉了最后一个题 话说这是为什么呢, 因为最后一个是回滚莫队的大板子,然而我忘记了,不不不,是没有记起来过 T ...
- metasploit的数据库配置
metasploit所处位置:/usr/share/metasploit-framework msf数据库连接命令:db_connect msf:msfadmin@127.0.0.1/msf 1.启动 ...
- Redis5.0 配置文件中文参考
Redis 5.0 配置文件#是否在后台执行,yes:后台运行:no:不是后台运行daemonize yes#是否开启保护模式,默认开启.要是配置里没有指定bind和密码.开启该参数后,redis只会 ...
- 【mysql】索引优化分析
1. 索引的概念 1.1 索引是什么 MySQL 官方对索引的定义为:索引(Index)是帮助MySQL 高效获取数据的数据结构.可以得到索引的本质:索引是数据结构.可以简单理解为排好序的快速查找数据 ...
- Qt学习笔记(2)-利用StackWidget实现选项卡式页面
学习笔记第二篇,利用Qt实现选项卡式的页面,效果如图1.1-图1.3所示.程序实现的功能是通过点击状态栏实现不同页面的切换,实际上Qt中自带有Tab选项卡式的控件,本文利用StackWidge实现类似 ...