【转载】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 ...
随机推荐
- GO Time 类型方法处理集合
1.判断2个时间是否超时 package main import ( "fmt" "time" ) func main() { //获取1秒后时间 var No ...
- Asp.Net Core 使用 Sqlite 数据库
在Asp.Net Core 使用 Sqlite 数据库 在Asp.Net Core(5.0)项目中使用Sqlite数据库的设置, 1,创建新web项目 2,安装下面的依赖包 Install-Packa ...
- CNVD-2021-14536 锐捷 RG-UAC 统一上网行为管理审计系统信息泄露漏洞
漏洞简介 锐捷 RG-UAC 统一上网行为管理审计系统存在信息泄露,攻击者通过网页源代码可间接获取管理用户账号密码,登录管理后台. 漏洞复现 fofa搜索以下关键字 title="RG-UA ...
- 常见web中间件漏洞(五)weblogic漏洞
继续整理有关中间件漏洞思路(仅做简单思路整理,不是复现,复现请参考大佬们的长篇好文,会在文章中列举部分操作) WebLogic是Oracle公司出品的一个application server,确切的说 ...
- 陀螺仪、加速度计与MPU6050的关系
文章目录 一.引言 二.陀螺仪 三.加速度计 四.MPU6050 一.引言 要开始做俩轮平衡小车了,所以需要补充一些关于平衡小车的知识,首先就是如何让小车保持平衡,这是要依据小车当前的三轴角度和平衡位 ...
- MySQL数据类型 储存引擎
存储引擎 日常生活中文件格式有很多种,并且针对不同的文件格式会有对应不同存储方式和处理机制(txt,pdf,word,mp4...) 针对不同的数据应该对应着不同的处理机制来存储 存储引擎就是不同的处 ...
- NOIP 模拟 9 考试总结
T1 一道推规律的题,没想出来,暴力打得常数还太大了,挂了不少 题解 T2 这是一道二分题,很巧妙,但是对于想我一样懒得人,那个数据结构就水过去了 (裸的分块加强大的卡长和合适的块的大小可以卡过去) ...
- MySQL自动填充
一.数据库级别 1.1 表设计 create_time默认值添加CURRENT_TIMESTAMP. update_time默认值添加CURRENT_TIMESTAMP,更新打勾. 1.2 验证是否成 ...
- VirtualBox-虚拟硬盘扩容-win7
问题: 我在VirtualBox下搭建的win7系统只设置了一个C盘,当初只给硬盘分配32G,如今深受生活的毒打,发现只剩5G可用,装个PS都费劲. 我要扩容,扩容! 当前环境: VirtualBox ...
- SpringBoot-2-1-6-集成activiti7-1-0-M4
pom.xml <dependencyManagement> <dependencies> <dependency> <groupId>org.acti ...