




版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
C程序员从校园到职场第1第2第3第4第5第6第7第8第9第10SQL语句和Shell命令第11附录A同行评审第1章 概述本章介绍C语言的发展历史和主要特点,以及实际项目工作中软件开发工程师常用到的工具软件。C语言的发展历史C语言之父C语言是1972年由美国贝尔实验室的计算机科学家DennisRitchie(丹尼斯·里奇)设计发明的。因此,DennisRitchie被誉为“C语言之父”(他已于2011年10月9日去世,享年70岁)。图1.1所示的人物就是DennisRitchie。图1.1 “C语言之父”DennisRitchieDennisRitchie曾在哈佛大学学习物理学和应用数学,1967年进入贝尔实验室工作。作为计算机科学家,在他身上有很多可贵的、值得我们学习的品格,例如:第一,他对所做的事十分有兴趣;第二,跳出舒适区工作,不断挑战自己;第三,有创新思维,不拘泥于条条框框;第四,喜欢分享,不藏匿自己的核心技术。DennisRitchie对计算机科学的贡献主要有以下几个方面:第一,作为“C语言之父”,他最大的贡献当然是发明了C语言;第二,1973年他与KenThompson合作,把UNIX90%以上的内容用C语言改写,因此也被誉为“UNIX之父”;第三,1978年他与BrianW.Kernighan一起出版了名著TheCProgrammingLanguage(《C程序设计语言》),此书已被翻译成多种语言,成为C语言方面最权威的教材之一。基于DennisRitchie的杰出成就,1983年他与KenThompson一起获得了图灵奖。1999年,DennisRitchie和KenThompson因为在发展C语言和UNIX操作系统方面所做出的贡献一起荣获了美国国家技术奖章。C语言的演进作为在国际上广泛使用的计算机编程语言,C语言的发展简史如图1.2所示。C语言到底有多少人在用?C语言的受欢迎程度如何?如图1.3所示为CodeForge网站公布的2014年11月“我最喜爱的编程语言”排行榜。这个排行榜来自2014年11月对56000多名软件工程师的问卷调查。该排行榜非常清楚地反映了在世界不同国家和地区各种编程语言的流行程度,可供软件工程师及IT相关行业人士参考。从图1.3可以看出,在全球范围内,C语言的受欢迎程度位居排行榜的榜首。因此,C语言使用得非常广泛。图1.2 C语言的发展简史图1.3 2014年11月“我最喜爱的编程语言”排行榜C语言的主要特点C语言是一种功能强大的、被广泛应用的面向过程的编程语言,可用于编写系统软件和应用软件。C语言的主要特点如图1.4所示。如图1.4所示,C语言的诸多特点使其越来越受到广大软件开发人员的青睐,也使其成为了使用人数最多的计算机编程语言之一。学习好C语言,对于深入学习计算机科学的其他课程都是很有好处的。图1.4C语言的主要特点常用工具软件有一次,我打开电视机准备随便看看,无意中被一部战争片吸引住了。成千上万的战士搭起云梯,想攻破一座城池。但是城楼上面的敌人负隅顽抗,拼了命地阻击进攻。双方的伤亡都很惨重,但城就是攻不下来。眼看剩下的人不多了,突然不知从什么地方开出一辆坦克,两炮就把城门轰开了。战士们趁势攻入城中,将敌人全部歼灭了。这类电视剧比较常见,相信大家看了不止一次。但是,我看完之后,那个场景还一直留在我的脑海里。成千上万的人不如一辆坦克来得直接,说明了什么问题呢?我立马想到了一句俗语:工欲善其事,必先利其器。的确,工具对于软件开发工程师来说,真的是很重要。好的工具能够提高开发的效率,进而缩短产品的研发周期。那么,在实际的软件研发项目中,软件开发工程师常用的工具软件有哪些呢?MicrosoftVisualStudio/MicrosoftVisualC++6.0MicrosoftVisualStudio(VS)是美国微软公司的开发工具包系列产品。它是一个较为完整的开发工具集,包括了整个软件生命周期中所需要的大部分工具,如集成开发环境(IDE)等。MicrosoftVisualC++6.0(VC或者VC6.0),是微软推出的一款C++编译器,将“高级语言”(如C、C++等)翻译为“机器语言”的程序。它是一个功能强大的可视化软件开发工具,已成为大多数专业程序员进行软件开发的首选工具之一。现在的最新版C++编译器集成在MicrosoftVisualStudio2015软件里面。用MicrosoftVisualC++6.0软件打开的代码如图1.5所示。图1.5 用MicrosoftVisualC++6.0软件打开的代码鉴于使用MicrosoftVisualStudio/MicrosoftVisualC++6.0进行软件开发的人员很多,有热心人士为其开发了一款叫做VisualAssistX的插件。VisualAssistX是一款非常好的MicrosoftVisualStudio/MicrosoftVisualC++6.0插件,支持C、C++、Java等语言,能够自动识别各种关键字、系统函数、成员变量,同时能够自动给出输入提示、标示错误、更正大小写错误等,有助于提高开发效率。SourceInsightSourceInsight是一个面向项目开发的程序编辑器和代码浏览器,它拥有内置的对C、C++、Java等程序的分析。它能够分析你的源代码,并自动为你显示有用的上下文信息。SourceInsight不仅是一个强大的程序编辑器,还提供了最快速的对源代码的导航信息。该工具被视为如今最好用的语言编辑器之一。用SourceInsight软件打开的代码如图1.6所示。图1.6 用SourceInsight软件打开的代码Notepad++Notepad++是一款很有特色的Windows环境下免费开源的代码编辑器。除了可以用来制作一般的纯文字说明文件之外,也十分适合用作代码程序的编辑器。Notepad++极具特色的一个功能就是语法的高亮度显示,方便了对关键词语的阅读。它支持的语言包括C、C++、Java等。用Notepad++软件打开的代码如图1.7所示。图1.7 用Notepad++软件打开的代码AraxisMerge/BeyondCompareAraxisMerge当程序代码比较多(成千上万行)的时候,我们想要了解最新代码与之前某个时期的代码的不同之处,并不是一件容易的事情。这样,代码比较工具就应运而生了。AraxisMerge和BeyondCompare是两款用得较多的代码比较工具。AraxisMerge是一个可视化的文件比较、合并和同步的软件,能够方便地被软件工程师用于快速精确地比较不同版本的源文件。此外,它还能被用于进行版本和质量控制。用AraxisMerge软件进行代码比较如图1.8所示。BeyondCompareBeyondCompare是一套由ScooterSoftware推出的软件,主要用于文件之间的比较。对于软件开发工程师来说,它可以用来发现不同版本代码或文档的不同,使用起来非常方便。图1.8 用AraxisMerge软件进行代码比较用BeyondCompare软件进行代码比较如图1.9所示。图1.9 用BeyondCompare软件进行代码比较Evernote(印象笔记)Evernote(印象笔记)是2012年5月10日由Evernote公司推出的一款产品,具有储存重要资料、剪辑网页、图片搜索等功能。对于软件开发工程师来说,Evernote可用于记录阅读过的重要技术书籍的笔记、在工作过程中的一些想法,以及软件实践或论文等。Evernote软件的界面如图1.10所示。图1.10 Evernote软件的界面FTP工具(如FileZilla等)在工作过程中,我们会不时地需要用FTP工具来上传或下载一些东西。FileZilla是软件开发工程师用得较多的FTP工具之一。FileZilla是一款免费的、开源的FTP软件,分为客户端版本和服务器版本两种。它具备所有的FTP软件功能,使用起来非常方便、快捷,曾在2002年11月获选为当月最佳推荐专案。FileZilla软件的操作界面如图1.11所示(在使用的时候,需要输入正确的主机IP地址、用户名和密码,端口号一般使用默认的21)。图1.11 FileZilla软件的操作界面UltraEdit在实际的软件开发过程中,UltraEdit也是一款经常会使用到的工具软件。它是一款功能十分强大的文本编辑器,可以用于编辑文本、十六进制、ASCII码等。当然,用它来编写C/C++代码也是十分方便的。用UltraEdit软件打开代码之后的界面如图1.12所示。好的工具对于软件开发工程师来说,就像优良的战斗武器对于战士一样重要。善于利用优秀的工具,可节省开发时间、提高我们办事的效率,进而提高软件产品的质量。因此,掌握一些常用软件的使用方法是非常重要的。图1.12 用UltraEdit软件打开代码小结本章对C语言的发展历史、C语言的主要特点,以及软件开发工程师常用到的工具软件进行了详细的介绍。本章对后续章节起到了一个抛砖引玉的作用。第2章学校到职场踏出校门,对于我们整个学习生涯来说,只是“万里长征走出了第一步”。为了使得之后学习和工作的道路走得更加顺畅,我们需要认清自身所学知识的不足,我们需要破除一些有关软件开发的错误观念,我们更需要在学校里面就未雨绸缪地开始培养工作所需的一些技能。认清自身不足我在走出校门的时候非常“轻狂”,认为自己在学校里面已经学得够多了,工作就只是“小菜一碟”。但在工作中屡次碰壁之后,我才发现自己当时的很多想法都是不成熟的。我们踏上工作岗位,一切几乎都要从零开始。对于大家“非常熟悉”的C语言来说,我们在学校里面学到的只是皮毛,远远不能满足实际软件开发工作的要求。我们在学校里面学到的典型的C语言程序如下:#include<stdio.h>voidmain(){floatfac(intn);intn;floaty;printf("inputanintegernumber:");scanf("%d",&n);y=fac(n);printf("%d!=%10.0f\n",n,y);}floatfac(intn){floatf;if(n<0){}
printf("n<0,dataerror!");if(n==0||n==1)f=1;f=fac(n-1)*n;return(f);}对于以上程序,至少存在如下几个问题。第一,变量命名不规范,而且没有初始化。对于该程序,main函数里的变量n、y,fac函数里变量f的命名均不规范,不能让人一眼就看出它是什么意思、要做什么操作。这对于一小段程序来说,影响还不是很大,但如果代码行数达到数千行甚至上万行,那么阅读起来就比较的费力。另外,以上3个变量只是定义了,并没有初始化,这在实际项目中也是不允许的。第二,函数的命名不规范,且没有在主函数开始之前进行声明。本程序中的fac函数要做什么操作?通过阅读代码,我们知道该函数的功能是计算一个整数的阶乘。在实际项目数调用者的内部来对被调函数进行声明,而是将声明放在外部,最好新建一个头文件(.h文件)来对程序里出现的函数进行声明。第三,程序代码排版不工整,“if…else”语句书写不规范。在fac函数中,代码的排版不工整。第一个if语句下面的大括号应该与“if”关键字保持在同一列上,第二个“else”关键字应该与第二个“if”关键字保持在同一列上,“f=1;”和“f=fac(n-1)*n;”应该再缩进4个空格。另外,“if”和“else”关键字下面的执行语句不管有多少行,都应该用“{}”括起来,以方便阅读。第四,程序注释过少,函数开头没有注释。一般说来,在程序的关键语句的前面或右边,都应该添加适当的注释,这对程序的理解有辅助的作用。函数fac的前面应该加注释,说明此函数的功能、输入/输出参数、返回值、修改记录等。在整个程序的开头也要添加版本信息、修改记录等注释信息,以方便日后查阅。第五,程序中出现了“printf”、“scanf”和“main”函数。这是大家都习以为常的,但在实际的项目中,几乎不可能出现这3个函数。因为很多公司都有自己的开发平台,而且代码都达到数千行,甚至上万行,再加上大部分都不是基于VC开发的,你在哪里去输入,又在哪里去看输出呢?我一进公司,最开始看到程序,就想去找“printf”、“scanf”和“main”,但这是徒劳的,因为根本就没有。关于输入/输出,开发中会有专门的消息处理流程来处理,大家需要知道的就是一个完整的代码工程中不一定非要有上面的3个函数(但本书为了给大家介绍C语言的相关知识,在程序仍然使用这3个函数)。短短的几十行代码,就出现了这么多大家“没有想到”的问题。看到以上的分析,也许你会很惊慌:我以前的C语言难道是白学了?非也!我举这个例子,不是为了给大家当头一棒,让大家觉得软件开发是多么高深和艰难。我只是想说明,对于C语言,我们还有很多不知道的东西,即使是自己知道的,也与阶段,而后才逐渐去改变了自己“根深蒂固”的观念。“知错能改,善莫大焉”啊!破除错误观念要让我们做事情的能力能够有所提升,观念的转变是关键。从学生转变为职业人的过程是很艰难的,因为我们要与自己积累了多年的“老毛病”作斗争,这些“老毛病”包括:做事拖拉、不守时、不遵守规则、怕吃苦等。就像发射火箭卫星了。所谓“万事开头难”,也就是这个道理。那么,要想掌握工作中C语言的基本技能,我们需要破除哪些错误观念呢?如图2.1所示。图2.1 我们需要破除的错误观念错误观念一:我的C语言学得很好。很多刚走出学校的、准备从事软件开发的人都持有这样的观念,因为他们在学校考试都得了高分。但想法是美好的,现实是残酷的。真正到了工作岗位,你就会发现,自己在学校学的那些知识是十分有限的,根本不足以应对工作。例如,C语言中的指针、结构体、异常保护这些,学校里面讲得很少或者不深入,大家也没有太注意,只是应付了考试,但工作中我们需要时时与它们打交道。你还说自己学得好吗?因此,为了个人的技术积累和职业发展,我们一定要谦虚,要虚心学习。错误观念二:编程是很简单的事情。持这种观点的人,也是受到了学校教育的影响,因为书本上面的代码都很短,而且比较简单。但在工作中,也这么简单吗?非也。我总结了一下,教材上的程序与实际工作中的程序至少有以下几点不同。第一,代码行数的多少。教材中的代码一般为几十行,多则一两百行,大家当然会觉得简单;而工作中的代码少则几千行,多则上万行,两者根本不是同一个数量级的。我最开始拿到程序的时候,脑袋就晕了:怎么这么多代码呢?我从没看到过。第二,变量及函数的命名。这是两者的最大不同,也是“专业”和“业余”的重要区别。在教材中,经常的命名有这几个:“inti;”、“char*p;”、“floatf;”、“intf(inta,intb)”等,大家都已经习以为常了。但变量及函数的命名不能想当然。这在后续的章节中会有详细的说明。第三,程序的注释。附近,一定要有注释。不仅如此,注释的写法也有多种,在不同的地方,写法是不一样的。简短而清晰的注释可以提高大家阅读代码的速度,进而提高了工作效率。第四,输入/输出语句。在教材上,几乎每个程序都有“scanf”和“printf”这两个函数,用于读入和输出数据,大家用得是津津有味,如果哪个程序没有这两个函数,反而会觉得奇怪。但在实际的项目代码中,几乎不存在这两个函数的,而代之以其他方式来进行输入和输出。在刚开始的时候,你也许会觉得难以接受,但慢慢熟悉之后,你就会知道这是什么原因了。第五,程序的样式。解,认为编程只注重功能,其他什么的都可以“随心所欲”。但在工作中,对于程序的版式、布局都是有严格规定的,哪里应该缩进(以及缩进几个空格)里应该留空行,都是要注意的。这就像一个人一样,光说自己肚子里“有货”还不行,还需要注意外表,要让大家看起来觉得很舒服,所谓的“内外兼修”,就是这个道理。错误观念三:我只要把代码写好就行了,其他的就不用管了。大家也许会认为,开发工程师只负责写程序,其他的什么测试啊、写文档啊,就不必自己操心了。其实不然。在工作中,开发工程师的工作是很多的,编写代码只是一小部分。在编写代码之前,我们要对软件进行详细设计;在代码写完之后,不能马上把它交给测试人员来测试。很多新手写完代码就了事,这是不对的。我们要首先进行自测,这会花费比较长的时间,甚至比写代码的时间还要长很多,等自测无误之后,才能正式提交。除了写代码和自测,我们还要编写相关的开发文档。你也许会认为写文档是文档工程师的事情,非也,这是开发工程师要干的。另外,我们从开始写代码到最后提交,都要严格遵守项目的管理流程,不能放任自流,要在规则之下来做事情。错误观念四:公司会安排好我的职业道路。每个人进入公司,都会有相应的入职培训,这其实就是公司对应届毕业生进行所谓的“洗脑”的过程。培训老师会给大家讲,公司是多么多么好,公司会针对每个员工制定好培养计划,让大家在适合自己的职业轨道上发展。但是,当你发现坐在你旁边的员工已经入职10年,可是还做着和你一样的工作时,你对公司美好的幻想瞬间就破灭了。确实,不管是在学校,还是在工作单位,我们不要指望学校或公司能够将未来的道路给安排好,而要靠自己不断地努力去实现自身的价值。科学技术日新月异,新的软件开发技术层出不穷。从事软件开发这一行,我们就要马不停蹄地学习,任何寄希望于他人或公司的想法都是不可取的。“磨刀不误砍柴工”,在树立了正确的观念之后,我们学习工作中的C语言就容易多了。工作所需软技能的培养在新员工刚进入公司的时候,一般都会有一段时间的试用期,也叫做培训期。对于大部分IT企业来说,这个试用期大体分为3个阶段:第一阶段,企业文化、办事流程、公司业务范围等的培训;第二阶段,工作所需专业知识的培训;第三阶段叫做“以师带徒”,也就是由一位老员工带着来从事具体的开发工作。但是,我们不能奢望通过这个短短的培训期就能够将工作中所需的技能全部掌握,因为学习重在长期的积累,个人习惯的改变更是一个漫长而痛苦的过程。这就需要我们在学校里面就有目的性地培养工作所需的方方面面的东西。总的说来,工作所需的一些软技能(即除专业技能之外的一些影响个人工作和发展的技能)如图2.2所示。图2.2 工作所需的一些软技能那么,我们如何在学校里面有针对性地培养如图2.2所示的各种能力呢?第一,对于实践性较强的一些课程(如程序设计课程、算法课程、网络课程、数据库课程等),一定不能只求考试通过,要多问为什么、多动手编写程序。有一位学弟发来邮件向我咨询一些问题,其中有个问题是这样的:看书学技术的时候有时还是很有成就感的,特别是敲代码实现一些小的算法的时候,感觉很舒服。但是看得时间长了偶尔就会感觉枯燥,耐不住寂寞。想必很多人都有类似的感触。我的答复是这样的:如果你在学校写点程序就会觉得枯燥的话,在工作中你会觉得更枯燥。如果你从事软件开发工作,那么几乎每天都要和程序打交道,需要相当大的韧性才能坚持得住。如何才能既学到技术,又不感觉到枯燥呢?根据我个人的经验,可以参考图2.3。图2.3 一个学习的良性循环打个比方来说,你要学习C语言,那么首先要选一本好的参考书,对于书上的程序或课后的习题,你要亲自敲到电脑里面来运行。慢慢熟悉之后,你对编程会有一些心得体会,这时你就可以将这些心得体会写成博客发表出去。写博客又会促使你去学习新的东西,别人的评论也会让你受益。如此不断地循环(根据个人的经验这是一个良性循环),自身能力会不断提高,你会发现学习技术是一件很有趣的事情。如果你觉得书本上的题目太简单,可以利用我们最强大的老师(网络)去寻找一些实际的软件开发项目来做。此外,很多开源社区也是一个很不错的选择。“问渠那得清如许,为有源头活水来”,我们只有不断地输入和输出知识,才能让自身充满活力。第二,适当地参加一些社团活动或集体活动,利用假期(如寒假或暑假)到外面去做兼职。末了。通过恰当的兼职及社团活动,我们不仅能够学到一些书本上没有的知识(够看到书本知识在实际中的应用),动。第三,打好专业基础,在高年级的时候争取能够到企业里面去实习。绝大部分学生在学校学习的最终目的是就业,也就是要走出校门,进入企业。因此,如果你在毕业之前能够有一段到企业里面去实习的经历,那么这必将丰富你的人生经历,让你在毕业求职的路上快人一步。能够去单位实习,从侧面来说也是对你在校学习成果的一种认可。因此,大家一定要将自己的专业课学好,让企业认为你是一个可以培养的人。通过一份比较有份量的实习,我们不仅能够学到专业知识、企业运作流程,还能够提高自己的动手能力、表达能力、团队协作能力等,同时也可以为自己的简历增加亮点。李开复老师也多次强调了大学生实习的重要性。小结本章作为一个过渡章节,从认清自身所学C语言知识的不足入手,接着让大家破除几个有关软件开发的错误观念,然后让在校学生有意识地培养工作所需的一些软技能。认清自身的不足让人谦虚,破除错误观念让人不惑,培养技能让人信心百倍。现在,我们可以正式开启软件项目实践中C语言的学习征程了。第3章 程序的样式在《高质量程序设计指南(C++/C语言)》中,作者说:可以把程序的版式比喻为“书法”,好的“书法”先看到的便是程序的排版,我们的第一印象便是程序写得是工整还是凌乱。都说第一印象很重要,为了给大家留下好的第一印象,我们一定要注重程序的版式。此外,好的注释能够帮助读者更快地理解程序,提高工作效率。也许是因为工作比较忙的缘故,很多软件工程师不喜欢为自己的程序写注释,认为这样做是没有必要的。那么,如果给他一份毫无注释的代码,他会有什么样的感受呢?在程序中,优美的、得当的注释能够起到锦上添花的作用,更能够体现出一个工程师的专业素质。因此,写注释实在是很有必要的。本章介绍头文件、源文件(也被称作定义文件)的样式,空格、空行、大括号的使用和注释的书写。本章中的示例代码均是基于开发项目实践中的编码规范来编写的。头文件头文件起到一个辅助的作用,简要地反应出本程序的基本功能。采用以下的样式来书写头文件:/***************************************************************版权所有(C)2015,公司(或个人)名称。*文件名称:内容摘要:其他说明:当前版本:作 者:完成日期:*修改记录1:修改日期:修改内容:*修改记录2:修改日期:修改内容:#ifndef_XXX_H //防止头文件被重复引用#define_XXX_H/**************************************************************相关宏定义**************************************************************//**************************************************************相关结构体定义**************************************************************//**************************************************************源程序中出现的函数声明#endif说明:在头文件开始的地方,一定要有注释。这里的注释主要是版权、版本、作者等相关在单位为软件产品写的每一行代码都要有版权声明,这也是对一个职业人的基本要求。的。为了便于理解,我们会将很多诸如数字等信息用宏来代替,就像C语言课上我们用“PI”来代表圆周率的值一样。此时,就需要在头文件中对源文件中需要用到的宏进行定义,并给出适当的注释,方便理解。在实际的C语言程序中,结构体是经常会用到的。例如,某个消息结构体包含了很的所有结构体。在学校里,很多人都不习惯对函数进行声明。为了防止函数在没有定义之前就被引数后面一定要写上恰当的注释。源文件源文件文件是程序的核心,所有的工作都是在该文件里面完成的。采用以下的样式来书写源文件:/***************************************************************版权所有(C)2015,公司(或个人)名称。*文件名称:内容摘要:其他说明:当前版本:作 者:完成日期:*修改记录1:修改日期:修改内容:*修改记录2:修改日期:修改内容:***************************************************************//**************************************************************头文件引用**************************************************************//**************************************************************全局变量定义**************************************************************//**************************************************************函数实现**************************************************************/说明:函数头部的版权、版本、作者等相关的信息与头文件的类似,也是必不可少的。函数包括进来。怎么办呢?办法就是引用定义这些函数的头文件,像我们很熟悉的“#include<stdio.h>”。当源程序中的函数比较多时,会出现很多函数都需要使用同一个变量的情况,这就何?函数是程序的核心,我们开头做了那么多的工作,都是为实现函数功能服务的。那部的注释可采用如下的样式:/**********************************************************************功能描述:输入参数:输出参数:其他说明:修改日期 版本号 修改人 修改内容* YYYYMMDD XXX Name YYY***********************************************************************/“YYYYMMDD”表示“年月日”,“XXX”是创建或修改函数时的版本号,“Name”是函数创建或修改人的名字,“YYY”是对函数修改内容的简要描述(如果该函数是第一次创建,那么“YYY”就可以写成“创建”)。在实际的开发工作中,很多软件程序都比较复杂,其中涉及的宏定义、结构体、函数等非常多,大家一定要按照规范的头文件及源文件的样式来书写程序,以利于代码的阅读及后期维护。本书中的大部分示例程序针对的是具体的知识点,因此与实际开发工作中的很多程序相比,要简单很多。为了便于说明,本书大部分示例程序都以源文件的形式呈现,文件中代码布局的先后顺序为:文件说明、头文件引用、数据类型或结构体定义、函数声明、函数实现。空格和空行在程序代码中,如果善用空格和空行,可使程序的版式更加的优美。本小节说明空格和空行的使用方法。空格在C语言的关键字(像if、for、while、switch等)之后要留有空格,以突出该关键字;在函数名之后不要留空格,紧跟左括号“(”间,要留有空格,如Function(x,y,z)。赋值操作符、算术操作符、比较操作符、逻辑操作符、位域操作符等,如“=”、“+=”、“>=”、“<=”、“+”、“*”、“%”、“&&”、“||”、“<<”,“^”等二元操作符的前后应当加空格。但一元操作符如“!”、“~”、“++”、“−−”、“&”(地址运算符)等前后不加空格。在一行代码的结尾之后不要留空格。在代码中,使用空格进行缩进(一般缩进为4个空格),不要使用制符表(即Tab键来缩进。空行空行起着分隔程序段落的作用,适当的空行将使程序的布局更加清晰。在每个函数定义结束之后都要加空行(两个函数之间建议添加两个以上的空行)。隔关系不是很大的代码段。大括号在C语言中,大括号“{}”是一类比较特殊的符号。如果能够在适当的地方利用它,可使代码看起来非常整洁,也能够从侧面看出一个编程人员的专业素养。那么,在C语言中,大括号应该用在哪些地方呢?初始化数组变量在实际的软件开发项目中,变量在使用前应初始化,防止未经初始化的变量被引用。对于数组变量来说,恰当的初始化样例如下:charszString[100]={0};定义了一个名为szString的包含100个字节的数组变量,并将该数组中每个变量的初始值赋为0。定义和初始化结构体变量结构体变量的定义方法样例如下:typedefstruct{……}T_Struct;该结构体变量的初始化样例如下:T_StructtStruct={0};很多开发人员都不注重对结构体变量进行初始化,这是不对的。要牢记的是,任何变量在使用前,都应进行初始化。用在if、else、elseif、for、while、do等语句中在实际的软件开发项目中,if、else、elseif、for、while、do等语句用得较多,对这些语句的书写要求如下。自占一行,执行语句不得紧跟其后。不论执行语句有多少都要加这样做的目的是便于阅读,同时也有利于代码的维护。假设定义了两个整型变量iIntVal1和iIntVal2,如果iIntVal1的值小于iIntVa2,那么就将iIntVal2的值赋给iIntVal1,则正反示例为:反例:if(iIntVal1<iIntVal2)iIntVal1=iIntVal2;这样写出来的程序可读性很差,不利于对流程的跟踪及对版本的维护。正例:if(iIntVal1<iIntVal2){iIntVal1=iIntVal2;}该代码和反例中的代码相比,简洁清晰,让人一目了然。程序的分界符“{”和“}”齐。之内的代码块使用缩进规则对齐(一般缩进4个空格)。同样以两个整型变量iIntVal1和iIntVal2的比较来说明,正例如上面(1)所示。反例:if(iIntVal1<iIntVal2){iIntVal1=iIntVal2;}该代码看起来给人一种很凌乱的感觉,不便于阅读和维护。用在switch语句中switch语句也经常出现在产品代码中,要想写出逻辑清晰、可阅读性强的switch语句,需要遵循以下规则。一定要加上default分支,即使case分支已经将全部情况都包括了。这样做是为了防止其他代码阅读者误以为漏写了default分支,也可表现出开发人员思维的全面性。一个case分支和default分支要用括起来,中的内容需要缩进(一般缩进4个空格)。这样做可使程序逻辑清晰,可读性更好。假设定义了一个整型变量iSwitchFlag,可取值1、2、3,用switch语句对每种可取值的情况分别进行处理,则正反示例为:反例:switch(iSwitchFlag){ //“{”没有和switch对齐case1: //“case”没有缩进{ //“{”没有和case对齐DoSomething1(); //缩进空格数太多break; //“break;”没有和上一条语句对齐} //“}”没有和本case语句的“{”对齐case2:{DoSomething2();break;}case3:DoSomething3(); //没有用“{}”将语句括起来,且case执行结束后无break;//缺少了default分支}以上反例中的switch语句可读性很差,不利于代码的维护。正例:switch(iSwitchFlag){case1:{DoSomething1(); //缩进4个空格break;}case2:{DoSomething2(); //缩进4个空格break;}case3:{DoSomething3(); //缩进4个空格break;}default: //一定要有default分支{DoNothing();break;}}正例中的代码逻辑清晰,有利于代码的修改和维护。break语句要写到“{}”如下的代码是不规范的:switch(iSwitchFlag){case1:{DoSomething1();}break; //break语句放到了“{}”外面,不规范case2:{DoSomething2();}break;case3:{DoSomething3();}break;default:{DoNothing();}break;}用在函数中大家都知道,一个函数中的所有语句是包括在“{}”之中的。除此之外,“{}”在函数之中还有其他用武之地。分隔功能关联不大的语句块在某些函数中,可能包含了很多功能,但这些功能之间的关联性很小,可以当作独立的代码来对待。这时,可以用“{}”将这些不同功能的代码块区分开来,增强代码的可读性,也便于对函数的维护和修改。假设有一个函数ExampleFun,包含了3个较为独立的功能A、B和C,则可以如下组织该函数的代码。voidExampleFun(void){//功能A代码块开始{//功能A的实现代码}//功能A代码块结束//功能B代码块开始{//功能B的实现代码}//功能B代码块结束//功能C代码块开始{//功能C的实现代码}//功能C代码块结束}这样的代码具有自说明性,便于阅读和维护。突出添加或修改的代码在代码行数较多的函数中,如果要添加或修改的代码量很少,即与原本已有的代码比起来,显得“很渺小”。这时,可以用“{}”方便阅读及对代码进行走查等。同样以函数ExampleFun为例来说明,如下所示:voidExampleFun(void){…………//修改或添加代码块开始{//修改或添加的代码}//修改或添加代码块结束…………}这样,不管是代码编写者,还是代码阅读者,都很容易发现代码的改动,阅读或维护起来也比较的容易。总的说来,善于在代码中运用“{}”,可以使得程序的样式更加美观。这样也可以增强代码的规范性,进而提高代码质量及工作的效率。注释在程序中,注释并非可有可无,软件开发人员应该将注释置于与代码等同的地位上。那么,如何正确书写注释呢?在C语言程序中,注释的书写有两种方式,一种是用“//”来标注,一种是用“/…/”来标书写,或对多行代码进行添加、删除时,可以采用第二种方式。方。阅读和理解。要尽量避免在注释中使用缩写,特别是不常用的缩写,以让人产生疑惑。性。如果注释不再有用,那么要删除掉。巧妙或复杂的代码段前要添加注释,比较隐晦的地方要在代码适当的位置添加注释。到底是使用中文还是英文对代码进行注释呢?对于常用的代码编辑器(如SourceInsight、MicrosoftVisualStudio等)来说,中英文的注释均能够正确显示。因此,书写注释要遵循“内容重于形式”的原则,要在恰当的地方使用恰当的注释。小结本章从程序给人的第一印象入手,介绍了头文件和源文件的样式、空格、空行、大括号的使用和注释的书写。当我们看到排版工整、注释规范的代码时,会不自然地产生继续读下去的想法,这也在无形中提高了工作的效率。因此,注意程序的样式是十分重要的。坚持不懈地努力。广大的软件开发工程师在提高自己编程水平的同时,也要注重编程规范,让自己的代码更易于阅读和维护。第4章 变量和函数路人甲到电信营业厅去交电话费,给营业员说要充50块钱,那个营业员问了一句“Howmuch?”于是便以不是很流利的口语说了一句“FiftyYUAN”。那个营业员一头雾水地看着他,说道“电话号码多少?”路人甲这才恍然大悟,原来是问我电话号码多少,而非多少钱。不要让别人感到疑惑。这个原理同样适用于软件开发过程,适用于编写代码的过程。我们在编写程序的过程中,要保证自己写的每一行代码都表意准确,让别人一看就能够明白,特别是对于变量和函数的命名。某些不规范的变量命名,诸如“inti,j;”、“charc;”等,严重影响了工作的效率。本章首先介绍实际软件开发项目中的数据类型,然后介绍变量和函数的命名规范,最后介绍一类特殊变量——静态变量的使用。数据类型大家都知道,要定义一个变量是很容易的。要定义整型变量,直接用“inti;”语句就可以了;要定义字符型变量,直接用“charc;”就可以了。确实,这能够达到定义变量的目的,但在实际工作中却没有这么简单。在实际工作中,我们需要对一些基本数据类型进行重定义(规范化),才能够满足编程规范的要求,才能够用于定义变量。本节以整型和字符型的重定义来进行说明。整型整型,以在内存中占数据位数来划分,包括短整型(shortint)、整型(int)和长整型(longint);以有无符号来划分,包括无符号整型(unsigned)和有符号整型(signed)。各类整型的重定义规则如图4.1所示。图4.1 各类整型的重定义规则从图4.1可以看出,各类整型的重定义规则如下。对于无符号短整型,其重定义为:typedefunsignedshortintUINT16;对于有符号短整型,其重定义为:typedefsignedshortintINT16;对于无符号整型,其重定义为:typedefunsignedintUINT32;对于有符号整型,其重定义为:typedefsignedintINT32;对于无符号长整型,其重定义为:typedefunsignedlongULONG;对于有符号长整型,其重定义为:typedefsignedlongLONG;通过以上重定义之后,我们就可以用UINT16、INT16、UINT32、INT32、ULONG和LONG来代替相应的整型类型了。这里拿UINT32来说明:“U”代表“unsigned”,“INT”代表“int”,“32”表示“32位”,从这个定义一眼就可以看出这表示32位的无符号整型数据类型,如果要定义这样的一个变量X,用“UINT32X;”语句就可以了。字符型在C语言中,字符型和整型可以相互转换。因此,也可以用类似的办法来重定义字符型。字符型分为有符号和无符号两种类型,它们的重定义规则如图4.2所示。图4.2 各类字符型的重定义规则从图4.2可以看出,各类字符型的重定义规则如下。对于无符号字符型,其重定义为:typedefunsignedcharUINT8;对于有符号字符型,其重定义为:typedefsignedcharINT8;由于一个字符型变量在内存中占据一个字节,因此可以用8位来表示。通过我们的重定义,也能够很清楚地看出来。如果要定义一个无符号字符型变量Y,用“UINT8Y;”语句就可以了。在实际的开发项目中,其他数据类型的重定义也可以参照整型和字符型的重定义来完成。对基本数据类型进行重定义也就是在进行代码编写的规范化。在大型代码文件中,按照这个规范编写的程序阅读起来比较方便,同时也易于理解,提高了工作效率,让读者一看到就觉得十分专业。此外,这样做也会间接提升开发工程师在客户心中的地位,能够获得他们比较好的评价。变量及函数函数是程序的核心,而变量又是函数的核心。程序的各种操作,其实就是对函数中变量进行的操作。变量及函数命名规范与否,直接影响到了代码的质量。因此,对变量及函数进行规范化的命名具有很重要的意义。本节以一个实际的例子来为大家展示如何命名变量和函数是恰当的。这里用2.1节中出现的程序代码为例,将该代码按照编码规范修改后,如下所示:/***************************************************************版权所有(C)2015,ZhouZhaoxiong。*文件名称:example.c内容摘要:用于示范变量和函数的规范化命名其他说明:无当前版本:V1.0作 者:周兆熊*完成日期:20150120****************************************************************/#include<stdio.h>typedefsignedintINT32; //重定义数据类型typedeffloat FLOAT; //重定义数据类FLOATProcessFactorial(INT32iInputValue); //函数声明INT32main(void); //函数声明/**********************************************************************功能描述:主函数输入参数:无输出参数:无其他说明:无修改日期 版本号 修改人 修改内容* *20150120 V1.0 周兆熊 创建***********************************************************************/INT32main(void){INT32iInputValue =0;FLOATfResult =printf("inputanintegernumber:");scanf("%d",&iInputValue);fResult=ProcessFactorial(iInputValue); //调用求阶乘的函数printf("%d!=%10.0f\n",iInputValue,fResult);return0;}/**********************************************************************功能描述:求一个数的阶乘输入参数:iInputValue-输入值输出参数:无返回值:求阶乘后的结果其他说明:无修改日期 版本号 修改人 修改内容* *20150120 V1.0 周兆熊 创建***********************************************************************/FLOATProcessFactorial(INT32iInputValue){FLOATfResult =0.0;//先判断输入值是否小于0if(iInputValue<0){printf("iInputValue<0,dataerror!");return-1;}else{if(iInputValue==0||iInputValue==1)//0和1的阶乘是1{fResult=1;}else{fResult=ProcessFactorial(iInputValue-1)*iInputValue;//执行递归调用}return(fResult);}}该代码和2.1节中的代码相比,是不是有很大的不同?有关变量和函数的命名,我们要遵循以下原则。变量命名和函数命名应具备描述性,不要过度缩写。变量的命名应该使用名词,如fResult;函数的命名应该使用“命令性”动词,如ProcessFactorial。不管是函数还是变量,它们的命名只有一个原则:让读者一眼就能够看出它们表达的意思。如ProcessFactorial函数,一看到它,就大概能够明白这是在求阶乘;iInputValue变量,表示输入值;fResult的费心解释。为了让读者看到一个变量就知道其类型,在变量的最前面,通常会有一个标识类型的字母。如iInputValue中的第一个字母“i”表示这是一个整型变量(“i”代表“int”),fResult中的第一个字母“f”表示这是一个浮点型变量(“f”代表“float”)。这样做,也是为了更进的时间,可谓是“大家皆方便”。函数的功能要单一,不要设计多用途的函数;函数体的规模要小,将函数内的代码行数控制在项目规定的范围之内。此外,要尽量避免函数带有“记忆”该产生相同的输出。懂的代码,不是好代码,也无法体现出一个编程人员的水平。对于函数的调用,需要注意以下几点。代码检查工具(如Pclint)是很容易发现的。如果确实需要传入该参数,可使用强制数据类型转换。对于有返回值的函数,尽量在被调用的时候对返回值进行处理。在实际的软件开发没有对返回值进行处理,这是不规范的。例如,定义一个返回整型值的函数ExampleFun,如下所示:intExampleFun(…){//执行代码return0;}而调用代码如下:……ExampleFun(…);……没有考虑到返回值。规范的做法是:同样定义一个整型变量,用于表示该函数的返回值,如下代码所示:intiRetVal=0;……iRetVal=ExampleFun(…);……很多开发人员认为写代码很枯燥,其实不然。如果你每天写出来的代码排版不工整、变量和函数命名不规范,当然会觉得枯燥。也许你昨天写的代码,今天就不知道它们是什么意思了。但如果你时刻牢记编程规则,写出“自己能够说话的代码”(即排版工整,变量和函数的命名很恰当),那么你就不会觉得这份工作很枯燥,反而会觉得它很有趣。这可能就是所谓的“编程境界”吧。“熟能生巧”,只有通过不断地练习,我们才能够懂得编写代码的诀窍,也才能够写得出好的、高质量的代码。静态变量及其应用在实际的软件开发中,有一类变量非常特殊,它就是静态变量。该变量用关键字static进行声明,主要应用于函数中。说静态变量特殊,是因为该变量的值具有“记忆性”,即本次函数调用时使用的变量值是上一次函数执行结束时该变量的值。该变量的重要用途之一便是生成唯一序列号。唯一序列号的形式为:“Time+N”。其中,“Time”表示时间,而“N”表示流水号,其实就是一个静态变量的值。每次调用序列号生成函数的时候,“N”的值都不同,这样可以保证序列号的唯一性。以下代码展示了唯一序列号的生成过程,其中序列号的样式为:MMDDHHMISSXXXXXX(即“月日时分秒流水号”的形式)。/**********************************************************************版权所有(C)2014,ZhouZhaoxiong。*文件名称:SerialNo.cpp文件标识:无内容摘要:用于演示序列号的创建方法其他说明:无当前版本:V1.0作 者:周兆熊*完成日期:20141122**********************************************************************/#include<afxinet.h>//数据类型typedefunsignedchar UINT8;typedefunsignedchar typedefunsignedint UINT32;typedefsigned int INT32;//时间信息结构体typedefstruct{UINT8 second; //0-59UINT8 minute; //0-59UINT8 hour; //0-23UINT8 day; //1-31UINT8 month; //1-12UINT16year; //1994-2099UINT8 week; //1-7UINT8 Count10ms; //0-99}ClockStruc;//函数声明voidGetCurTime(ClockStruc*pCurrentTime); //获取当前时INT32CreateSerial(UINT8*pSerialID,UINT32iSerialSize);INT32main(void); //主函数/**********************************************************************功能描述:获取当前时间输入参数:无输出参数:pCurrentTime-当前时间结构体其他说明:无修改日期 版本号 修改人 修改内容* *20141122 V1.0 周兆熊 创建**********************************************************************/voidGetCurTime(ClockStruc*pCurrentTime){SYSTEMTIMEtCurrentTime;GetLocalTime(&tCurrentTime);pCurrentTime->month =(UINT8)tCurrentTime.wMonth;pCurrentTime->day =(UINT8)tCurrentTime.wDay;pCurrentTime->hour =(UINT8)tCurrentTime.wHour;pCurrentTime->minute =(UINT8)tCurrentTime.wMinute;pCurrentTime->second =(UINT8)tCurrentTime.wSecond;pCurrentTime->week =(UINT8)tCurrentTime.wDayOfWeek;if(pCurrentTime->week==0) //表示星期天{pCurrentTime->week=7;}}/**********************************************************************功能描述:创建序列号输入参数:iSerialSize-序列号长度输出参数:pSerialID-序列号返回值:0-成功-1-失败其他说明:序列号的样式:MMDDHHMISS_XXXXXX修改日期 版本号 修改人 修改内容* *20141122 V1.0 周兆熊 创建***********************************************************************/INT32CreateSerial(UINT8*pSerialID,UINT32iSerialSize){ClockStruc tClock ={0};**static****UINT32****iTailNum**=**0**;if(NULL==pSerialID){printf("CreateSerial:inputparameterisNULL.\n");return-1;}GetCurTime(&tClock);_snprintf((char*)pSerialID,iSerialSize,"%02d%02d%02d%02d%02d_%06d",tClock.month,tClock.day,tClock.hour,tClock.minute,tClock.second,iTailNiTailNum++;if(iTailNum>999999){iTailNum=0;}return0;}/****************************************************************功能描述:主函数输入参数:无输出参数:无返回值:0-执行成功-1-执行失败其他说明:无修改日期 版本号 修改人 修改内容* *20141122 V1.0 周兆熊 创建****************************************************************/INT32main(void){UINT32iLoopFlag =0; //该变量用于表示循环标志INT32iRetValue =0; //该变量用于表示调用CreateSerial函数返回的值UINT8szSerialID[50{0}; //该变量用于存放生成的序列号//生成10个序列号,并打印出来for(iLoopFlag=0;iLoopFlag<10;iLoopFlag++){iRetValue=CreateSerial(szSerialID,sizeof(szSerialID));if(iRetValue!=0){printf("execCreateSerialfailed.\n");return-1;}printf("第%d个序列号为:%s\n",iLoopFlag+1,szSerialID);}return0;}程序的运行结果如图4.3所示。图4.3 唯一序列号的生成结对于此示例程序,说明如下:在实际软件开发项目的程序中,生成序列号中的时间会有各种不同的样式,如“YYYYMMDDHHMISS”(年月日时分秒)、“HHMISS”(时分秒)等,这要根据实际的软件需求来决定。GetLocalTime函数来生成序列号中的时间,该函数用来获取当地的当前系统日期和时间。本程序中的流水号(即序列号中下划线后面的部分)是用静态变量iTailNum的。在调用CreateSerial函数的过程中,这个变量会不断增长,在达到了最大值999999之后,又从0开始,如此周而复始。这样设计,确保了每一个序列号的唯一性。小结看过电视剧《楚汉传奇》的人应该对一个场面有印象。当刘邦第一次去找项羽帮忙的时种差别移植到软件开发上来,就是“业余”与“专业”的差别。这个比喻虽然可能有点不恰业与否的表现。本章介绍了数据类型,变量和函数的命名规范及静态变量的使用。掌握了这些基础知识之后,我们才能够更加深入地学习实际软件开发项目中的C语言知识。第5章 内存操作在实际的软件开发项目中,内存操作随处可见,这也是程序编写的难点所在。如果内存操作处理不好,极易造成程序崩溃,并耗费大量的时间来排查问题。本章介绍4组与内存操作相关的函数及其用法。这4组函数是:memset和memcpy、strcat和strncat、strcpy和strncpy、strcmp和strncmp。memset和memcpymemset函数原型voidmemset(voiddest,intc,size_tcount);函数作用在MSDN中,该函数的作用描述为:Setsbufferstoaspecifiedcharacter,即:将缓存设定为一个专门的字符。对照函数原型,就是将已开辟内存空间dest的首count个字节的值设为c。示例代码/***************************************************************版权所有(C)2014,ZhouZhaoxiong。*文件名称:memset.c内容摘要:用于测试memset函数其他说明:无当前版本:V1.0作 者:周兆熊*完成日期:20141121****************************************************************/#include<string.h>#include<stdio.h>typedefsignedcharINT8; //重定义数据类型typedefsignedintINT32; //重定义数据类型/**********************************************************************功能描述:主函数输入参数:无输出参数:无返回值:0-执行完成其他说明:无修改日期 版本号 修改人 修改内容* *20141121 V1.0 周兆熊 创建***********************************************************************/INT32main(void){INT8szTestStr[100]="AAAAAAAAAA";printf("Theoriginalstringis:%s\n",szTestStr);memset(szTestStr,'B',5); //调用memset函数printf("Thechangedstringis:%s\n",szTestStr);return0;}该程序的输出结果如图5.1所示。图5.1 memset函数的示例程序输出结该程序将原字符串的前5个字符设为B。重要应用除了对指定位置设定值之外,该函数还可以用于内存空间初始化、内存复制、清空一个结构类型的变量或数组等。memcpy函数原型voidmemcpy(voiddest,constvoid*src,size_tcount);函数作用在MSDN中,该函数的作用描述为:Copiescharactersbetweenbuffers,即:在缓存之间复制字符。对照函数原型,memcpy函数用来复制src所指的内存内容的前count个字节到dest所指的内存地址上。示例代码/***************************************************************版权所有(C)2014,ZhouZhaoxiong。*文件名称:memcpy.c内容摘要:用于测试memcpy函数其他说明:无当前版本:V1.0作 者:周兆熊*完成日期:20141121****************************************************************/#include<string.h>#include<stdio.h>typedefsignedcharINT8; //重定义数据类型typedefsignedintINT32; //重定义数据类型/**********************************************************************功能描述:主函数输入参数:无输出参数:无返回值:0-执行完成其他说明:无修改日期 版本号 修改人 修改内容* *20141121 V1.0 周兆熊 创建***********************************************************************/INT32main(void){INT8szTestStr[100]="AAAAAAAAAA";INT8szCopyStr[100]="BBBBBBBBBB";printf("Theoriginalstringis:%s\n",szTestStr);memcpy(szTestStr+1,szCopyStr+5,3); //调用memcpyprintf("Thechangedstringis:%s\n",szTestStr);return0;}该程序的输出结果如图5.2所示。图5.2 memcpy函数的示例程序输出结果该程序将原字符串的第二个到第四个字符设为B。重要说明src和dest所指内存区域不能重叠,函数返回值为指向dest的指针。在实际的开发项目中,memset与memcpy函数经常同时使用,即先用memset函数来初始化某数组或结构体变量,然后用memcpy函数将内容复制到被初始化的变量中。例如,定义一数组变量szStringContent,要将“zhou”复制到szStringContent中去,则示例代码如下:charszStringContent[1024]={0};……memset(szStringContent,0x00,sizeof(szStringContent));memcpy(szStringContent,"zhou",strlen("zhou"));……strcat和strncat在实际的软件开发项目中,程序经常会对字符串进行操作。为此,C函数库中提供了一些用来对字符串进行处理的函数,使用起来非常的方便。但由于字符串都有长度,如果随意对不同的字符串进行连接和复制等操作,就可能出现意想不到的后果。因此,在实际开发中,十分强调对字符串处理函数进行异常保护。本节介绍strcat和strncat的使用方法,5.3节和5.4节分别介绍strcpy和strncpy、strcmp和strncmp的使用方法。strcat函数的作用是连接两个字符数组中的字符串。在MSDN中,其定义为:char*strcat(char*strDestination,constchar*strSource);Remarks:ThestrcatfunctionappendsstrSourcetostrDestinationandterminateststrcat函数将strSource字符串拼接到strDestination后面,最后的返回值是拼装完成之后的字符串strDestination。这里有一个问题,如果字符串strSource的长度大于strDestination数组的长度,就会出现数组越界的错误,程序就会崩溃。如下代码所示:/***************************************************************版权所有(C)2014,ZhouZhaoxiong。*文件名称:StrcatTest.c内容摘要:用于测试strcat函数其他说明:无当前版本:V1.0作 者:周兆熊*完成日期:20141121****************************************************************/#include<stdio.h>#include<string.h>typedefsignedcharINT8; //重定义数据类型typedefsignedintINT32; //重定义数据类型/**********************************************************************功能描述:主函数输入参数:无输出参数:无返回值:0-执行完成其他说明:无修改日期 版本号 修改人 修改内容* *20141121 V1.0 周兆熊 创建***********************************************************************/INT32main(void){INT8szStrDestination[10]="Hello";INT8szStrSource[10] ="Hello123";//先打印源字符串和目的字符串printf("Thesourcestringis:%s\n",szStrSource);printf("Thedestinationstringis:%s\n",szStrDestination);strcat(szStrDestination,szStrSource); //调用strcat函数//打印拼装完成之后的字符串printf("Thechangeddestinationstringis:%s\n",szStrDestination);return0;}在该段代码中,szStrDestination数组的长度小于szStrSource中字符串的长度,当利用strcat函数进行字符串的连接操作时,异常就出现了。执行代码后弹出的异常框如图5.3所示。图5.3 strcat测试程序异常提示框为了解决这个问题,在使用strcat函数之前,需要先对字符串和字符数组的长度进行比较,让字符串函数进行安全的连接操作,即保证最终字符串的长度不超过目的字符数组的长度。按照此思路编写的代码如下所示:/***************************************************************版权所有(C)2014,ZhouZhaoxiong。*文件名称:StrcatTest.c内容摘要:用于测试strcat函数其他说明:无当前版本:V1.0作 者:周兆熊*完成日期:20141121**************
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2025-2030中国跑腿服务行业市场深度调研及发展前景与投资前景预测研究报告
- 和店铺合租协议书合同
- 2024年北京中日友好医院招聘笔试真题
- 成人教育线上学习模式创新与远程教育平台建设报告
- 2025-2030中国螺旋填装机行业市场现状供需分析及投资评估规划分析研究报告
- 2025-2030中国蛋白质添加剂行业市场现状供需分析及投资评估规划分析研究报告
- 2025年教育质量评估与认证体系教育质量评价体系改革研究报告
- 事业编专业面试题及答案
- 潍坊电工试题及答案
- 2025年绿色低碳城市规划:大连实践案例分析报告
- 2025年输变电电力变压器行业市场分析现状
- 专题19 介词和介词短语(清单+专练)-中考英语一轮复习知识清单
- 2025年医院基建科面试题及答案
- (一模)临沂市2025届高三高考第一次模拟考试历史试卷(含标准答案)
- 2026年版广西高等职业教育考试(新职教高考)普高生专用升高职大专《职业适应性测试》模拟试卷(第1套)
- 企业营销战略咨询服务协议
- 人教版(2024)七年级下册英语Unit 7 A Day to Remember 单元教学设计(共6课时)
- 基于机器视觉的焊缝缺陷检测方法及其应用研究
- 行测5000题电子版2025
- P6运行操作手册
- 考生所在单位考核意见填写模板
评论
0/150
提交评论