0
点赞
收藏
分享

微信扫一扫

让你提前认识软件开发(16):如何对程序进行优化?


第1部分 重新认识C语言

如何对程序进行优化?


         对程序进行优化,是软件开发工程师必然会涉及到的问题。那么为什么要对程序进行优化呢?原因有以下几个:

        第一,在原程序基础之上新增、删除或修改了功能,需要改变原程序流程。客户需求随时可能会变化,今天已经实现的功能,说不定明天就要修改或去掉。落实到程序上面,就需要我们随时准备对写好的代码进行修改,而不要奢望写好之后就永远不要动了。

        第二,原程序有bug。这类情况出现得非常的频繁,很多软件有1.0、2.0、3.0等版本,部分原因就是前面版本中程序有问题,在修改程序的过程中使得软件版本不断升级。

        第三,原程序效率较低或不便于阅读,对程序进行优化之后可提高效率或更易于阅读。在软件项目中,对每个函数包含的代码行数都有一定的规定,如果超出了规定的行数,就要考虑对代码进行优化,将部分函数提取出来单独写成一个函数。

 

        有关程序优化,我们要遵循以下两个原则:

        第一,“小步快跑”原则。这个原则是指每修改一点点就对程序进行测试,测试通过之后再修改一点点,再进行测试。如此不断地循环下去,直到程序修改完成并测试通过。这样可以确保程序功能的正确性,减少后期重大变更所带来的成本。

        第二,“两顶帽子”原则。一顶是只重构代码而不新增功能,一顶是增加新的功能以实现新需求。即如果发现原程序存在诸多问题,需要先进行优化后再添加新的功能,那么第一步就优化原代码而不增加新功能,第二步在新代码的基础之上添加新代码以实现新功能。


        本文以一个实际的程序为例,详细介绍如何对程序代码进行优化。

 

1.优化之前的程序

       本程序实现将输入字符串中的大写字母变成小写字母的功能,具体代码如下:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void main()
{
char s[100];
unsigned int i;
scanf("%s", s);
for(i=0; i<strlen(s);i++)
{ s[i]=tolower(s[i]); }
printf("%s\n", s);
}

        可以看出,本程序存在如下问题:

        (1)代码排版不工整且无注释。

        (2)变量命名不规范,且在定义的同时没有进行初始化。

        (3)代码缩进不规范,for语句的书写不规范。

        (4)对于输入和输出,没有相应的文字提醒。

        (5)对于大写转换为小写的功能,可考虑封装为一个函数,利于阅读和其它的模块调用。

        可以看出,虽然程序能够实现基本的功能,但并非最优的。以下我们将逐步对代码进行优化。

 

2.对代码进行优化

        Step 1:重新对程序排版,并添加注释

{}”之内的语句相对于“{}”要缩进4个空格,同级的代码要对齐。在程序的头部、函数的头部及关键语句处要添加注释。

        修改之后的代码如下所示:

/**********************************************************************
*版权所有 (C)2014, Zhou Zhaoxiong。
*
*文件名称: StrToLowerCase.c
*文件标识:无
*内容摘要:将输入字符串中的大写字母变成小写字母
*其它说明:无
*当前版本: V1.0
*作 者: Zhou Zhaoxiong
*完成日期: 20140426
*
*修改记录1://修改历史记录,包括修改日期、版本号、修改人及修改内容
*修改日期: 20140426
*版本号: V1.0
*修改人: Zhou Zhaoxiong
*修改内容:创建
**********************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/**********************************************************************
*功能描述:主函数
*输入参数:无
*输出参数:无
*返回值:无
*其它说明:无
*修改日期 版本号 修改人 修改内容
* ----------------------------------------------------------------------------------------------
*20140426 V1.0 Zhou Zhaoxiong 创建
***********************************************************************/
void main()
{
char s[100];
unsigned int i;

printf("Input the source string: ");
scanf("%s", s); //读入原始字符串

for (i = 0; i < strlen(s); i ++)
{
s[i] = tolower(s[i]); //将字符串中的大写字母变成小写字母,其它字符不变
}

printf("Output the destination string: %s\n", s); //输出目的字符串
}

修改之后,程序的排版工整,在重要的地方添加了注释,且代码的缩进更为合理。
for语句的书写规范。在“for”关键字和“(”之间,要留有一个空格,以区分出关键字。“{}”要与“for”关键字在同一列,“{}”里面的语句不能与“{}”在同一行,并且里面的语句要缩进4个空格。

Step 2:规范变量、函数等的命名及变量初始化
在实际的软件开发项目中,规定在定义变量的同时要进行初始化,防止变量被错误地引用。
在上步的基础之上,对代码进一步优化之后如下所示:
/**********************************************************************
*版权所有 (C)2014, Zhou Zhaoxiong。
*
*文件名称: StrToLowerCase.c
*文件标识:无
*内容摘要:将输入字符串中的大写字母变成小写字母
*其它说明:无
*当前版本: V1.0
*作 者: Zhou Zhaoxiong
*完成日期: 20140426
*
*修改记录1://修改历史记录,包括修改日期、版本号、修改人及修改内容
*修改日期: 20140426
*版本号: V1.0
*修改人: Zhou Zhaoxiong
*修改内容:创建
**********************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

//重新定义数据类型
typedef unsigned char UINT8;
typedef int INT32;
typedef unsigned int UINT32;

/**********************************************************************
*功能描述:主函数
*输入参数:无
*输出参数:无
*返回值:无
*其它说明:无
*修改日期 版本号 修改人 修改内容
* -----------------------------------------------------------------------------------------------
* 20140426 V1.0 Zhou Zhaoxiong 创建
***********************************************************************/
INT32 main()
{
UINT8 szString[100] = {0}; //用于存放字符串,在定义的同时进行初始化
UINT32 iLoopFlag = 0; //用于表示循环变量,在定义的同时进行初始化
UINT32 iStrLen = 0; //用于表示字符串长度,在定义的同时进行初始化

printf("Input the source string: ");
scanf("%s", szString); //读入原始字符串

iStrLen = strlen(szString);

for (iLoopFlag = 0; iLoopFlag < iStrLen; iLoopFlag ++)
{
//将字符串中的大写字母变成小写字母,其它字符不变
szString[iLoopFlag] = tolower(szString[iLoopFlag]);
}

printf("Output the destination string: %s\n", szString); //输出目的字符串

return 0; // main函数返回0
}

修改之后,代码更加的规范。以下方面值得注意:
(1)在前面的文章中,提到了重定义数据类型、变量命名规范等,在此处就有所体现。
(2)一行代码尽量只完成一个功能,不要企图在一行代码里面完成多个功能。
(3) main函数有返回值,在函数执行完成之后返回0。

Step 3:对代码进行重构,提取关键语句封装为函数
在经过第二步的优化之后,程序基本达到了规范性、易于阅读性等要求。
对于代码中的大写字母变成小写字母的语句,我们考虑将它们封装成一个独立的函数,以后程序有类似的功能要求可以直接调用函数。这就涉及到对代码进行重构。
重构之后的代码如下所示:
/**********************************************************************
*版权所有 (C)2014, Zhou Zhaoxiong。
*
*文件名称: StrToLowerCase.c
*文件标识:无
*内容摘要:将输入字符串中的大写字母变成小写字母
*其它说明:无
*当前版本: V1.0
*作 者: Zhou Zhaoxiong
*完成日期: 20140426
*
*修改记录1://修改历史记录,包括修改日期、版本号、修改人及修改内容
*修改日期: 20140426
*版本号: V1.0
*修改人: Zhou Zhaoxiong
*修改内容:创建
**********************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

//重新定义数据类型
typedef unsigned char UINT8;
typedef int INT32;
typedef unsigned int UINT32;

INT32 StrToLowerCase(UINT8 *pszInStr, UINT32 iInLen); //对函数进行声明

/**********************************************************************
*功能描述:主函数
*输入参数:无
*输出参数:无
*返回值:无
*其它说明:无
*修改日期 版本号 修改人 修改内容
* -------------------------------------------------------------------------------------------
* 20140426 V1.0 Zhou Zhaoxiong 创建
***********************************************************************/
INT32 main()
{
UINT8 szString[100] = {0}; //用于存放字符串,在定义的同时进行初始化
UINT32 iLoopFlag = 0; //用于表示循环变量,在定义的同时进行初始化
UINT32 iStrLen = 0; //用于表示字符串长度,在定义的同时进行初始化
UINT32 iRetVal = 0; //表示调用函数的返回值,在定义的同时进行初始化

printf("Input the source string: ");
scanf("%s", szString); //读入原始字符串

iStrLen = strlen(szString);

iRetVal = StrToLowerCase(szString, iStrLen); //调用封装好的函数
if (iRetVal == -1)
{
printf("exec StrToLowerCase failed!");

return -1; //返回-1表示调用StrToLowerCase函数执行失败
}

printf("Output the destination string: %s\n", szString); //输出目的字符串

return 0; // main函数返回0
}


/**********************************************************************
*功能描述:将字符串中的大写字母变为小写字母
*输入参数: *pszInStr-输入/输出字符串
iInLen-字符串长度
*输出参数: *pszInStr-输入/输出字符串
*返回值: 0-成功 -1-失败
*其它说明:无
*修改日期 版本号 修改人 修改内容
* ------------------------------------------------------
* 20140426 V1.0 Zhou Zhaoxiong 创建
***********************************************************************/
INT32 StrToLowerCase(UINT8 *pszInStr, UINT32 iInLen)
{
UINT32 iLoopFlag = 0;

if (pszInStr == NULL) //异常保护,判断输入字符串是否为空
{
printf("Input string is NULL!");
return -1; //返回-1表示该函数执行失败
}

for (iLoopFlag = 0; iLoopFlag < iInLen; iLoopFlag ++)
{
pszInStr[iLoopFlag] = tolower(pszInStr[iLoopFlag]);
}

return 0; //返回0表示该函数执行成功
}

 

         修改之后的代码与最开始的代码相比,无论是代码的整洁程度、注释、变量的命名,还是程序逻辑,都更上一层楼了。

         需要注意以下几个地方:

         (1)函数在被调用之前,一定要进行声明。

         (2)对于传入的指针变量,在使用之前一定要检查该变量是否为空,也就是要进行异常保护。

         (3)代码重构的目的是使得代码的逻辑更加的清晰,并不是说一个函数中代码行数多了,就要将部分代码挑出来写成一个新的函数。

        (4)对于有返回值的函数,在调用的时候一定要对返回值进行处理。如本程序中对StrToLowerCase函数返回的-1进行了判断处理。

 

3.总结

bug的代码是每一个软件开发工程师的梦想,因此,掌握基本的对代码进行优化的方法是我们的必修课。

      “实践出真知”,只有通过不断的实践,我们才能够总结出更加实用和有效的代码优化的方法。



(欢迎访问南邮BBS:​​http://bbs.njupt.edu.cn/​​​)
(欢迎访问重邮BBS:​​​http://bbs.cqupt.edu.cn/nForum/index​​)

(本系列文章每周更新两篇,敬请期待!本人新浪微博:​​http://weibo.com/zhouzxi?topnav=1&wvr=5​​,欢迎关注!)

举报

相关推荐

0 条评论