关键词:
这几章从注释、程序格式、对象与数据结构的规范以及错误处理四个方面介绍了如何使代码变得简洁易懂。不同于上次摘抄的方法,这一次我会结合第一次个人作业的代码进行分析。
第四章 注释
这一章告诉我们,好的注释要满足以下三点要求:
- 尽量避免用注释解释程序意图
- 注释要精练简洁
- 注释要明确,不能给人误导
好的程序往往通过代码就能告诉程序员这段代码要做什么,注释只能出现在可能出现歧义的地方以及需要特别注意的地方。当你想通过添加注释来解释意图的时候,不妨先想一想将功能分块、修改函数名、封装类等方法能不能帮助你更好地表达。万不得已必须要加注释的话,那你一定要注意注释的简洁性与明确性。下面我分析一下第一次个人作业中Linux平台下遍历文件夹的程序注释部分。
1 void traverseFileandCount(char* path, struct alphaArray* dictionary) 2 3 DIR *pDir; //定义一个DIR类的指针 4 struct dirent *ent=NULL; //定义一个结构体 dirent的指针,dirent结构体见上 5 int i = 0; 6 char childpath[512]; //定义一个字符数组,用来存放读取的路径 7 pDir = opendir(path); // opendir方法打开path目录,并将地址付给pDir指针 8 memset(childpath, 0, sizeof(childpath)); //将字符数组childpath的数组元素全部置零 9 while ((ent = readdir(pDir)) != NULL) 10 //读取pDir打开的目录,并赋值给ent, 同时判断是否目录为空,不为空则执行循环体 11 12 if (ent->d_type&DT_DIR) 13 /*读取 打开目录的文件类型 并与 DT_DIR进行位与运算操作,即如果读取的d_type类型为DT_DIR 14 (=4 表示读取的为目录)*/ 15 16 if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0) 17 //如果读取的d_name为 . 或者.. 表示读取的是当前目录符和上一目录符, 18 //则用contiue跳过,不进行下面的输出 19 continue; 20 sprintf(childpath, "%s/%s", path, ent->d_name); 21 //如果非. ..则将 路径 和 文件名d_name 付给childpath, 并在下一行prinf输出 22 //printf("path:%s\n",childpath);原文链接这里是要打印出文件夹的地址 23 traverseFileandCount(childpath, dictionary); 24 //递归读取下层的字目录内容, 因为是递归,所以从外往里逐次输出所有目录(路径+目录名), 25 //然后才在else中由内往外逐次输出所有文件名 26 27 else 28 //如果读取的d_type类型不是 DT_DIR, 即读取的不是目录,而是文件, 29 //则直接输出 d_name, 即输出文件名 30 31 //cout<<ent->d_name<<endl; 输出文件名 32 //cout<<childpath<<"/"<<ent->d_name<<endl; 输出带有目录的文件名 33 sprintf(childpath, "%s/%s", path, ent->d_name); 34 //你可以唯一注意的地方是下一行 35 //目前childpath就是你要读入的文件的path了,可以作为你的读入文件的函数的参数 36 count(childpath, dictionary);//这里就是你的处理文件的接口!, 37 38 39
先声明一点:这位同学加这么多注释并不是他的编程习惯,只是为了其他使用这段程序的同学更好懂。
我们来看一看这些注释,很明显,介绍这段程序功能的是注释而非代码!而且,每一句都有注释,降低了程序的可读性和简洁性。如果这段程序出现在我的代码当中,估计助教会疯掉。下面我稍微修改一下这个程序。
#define childPathLength 512 //tranverse file recursively void traverseFileandCount(char* path, struct alphaArray* dictionary) DIR *filePoint; struct dirent *fileInfo = BULL; char childPath[childPathLength]; filePoint = opendir(path); memset(childPath,0,childPathLength);//init the childPath array with 0 while((fileInfo=readdir(filePoint)) != NULL) if(isDirectory(fileInfo)) if(isPresentOrPriorDirectory(fileInfo)) continue; sprintf(childpath, "%s/%s", path, ent->d_name);//create new path traverseFileandCount(childpath, dictionary); else sprintf(childpath, "%s/%s", path, ent->d_name);//create new path count(childpath, dictionary); bool isDirectory(struct dirent *fileInfo) return fileInfo->d_type&DT_DIR; bool isPresentOrPriorDirectory(struct dirent *fileInfo) return strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0;
首先,变量命名上我使用filePoint来表示指向文件的指针,使用fileInfo表示读取的文件信息。这样即使读者不知道DIR和dirent究竟是什么,也可以通过变量的名字猜出来变量的作用。如果此处使用注释,那么当读者看到下面的程序的时候(比如ent->d_type),可能会疑惑这个ent是什么,为了弄明白这个变量的意思,读者不得不返回定义的地方去看。相比之下,filePoint和fileInfo则清楚许多。
接着,我将ent->d_type&DT_DIR和strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0两句比较难懂的话包装成了两个函数,通过函数名来解释它们的作用。当读者读到isDirectory(fileInfo),更容易想到这个函数是用来判断这个文件路径是否是目录的,读到isPresentOrPriorDirectory(fileInfo)的时候,也会大致知道这个函数是判断这个文件路径是否是当前目录或者上一级目录。这样的做法虽然多出了两个小函数,但是省掉了文字注释,提高了程序的可读性,我觉得更好一点。
其他地方,我保留了初始化子路径数组的注释和创建新路径的注释,因为memset和sprintf这两个函数可能有些人不知道。我也试图将其包装成一个函数,但是由于要传输3个参数,这样很大的降低了可读性,所以没有这么做。
第五章 格式
这一章从垂直格式和水平格式两方面告诉读者如何构建一个良好的程序格式。
- 垂直方向,采取从上到下的编程模式。被调用函数紧跟在被调用函数后面。
- 水平方向,注意缩进要清晰,变量定义无需对齐,一行代码不要过长。
下面看一下第一次个人作业我的主函数。
int main() char filePath[filePathLength]; struct alphaArray dictionary[alphabet]; struct wordStatisticsResult topFrequencyWord[topFrequencyWordNum]; struct phaseStatisticsResult topFrequencyPhase[topFrequencyPhaseNum]; dictionaryInit(dictionary); getFilePath(filePath); traverseFileandCount(filePath, dictionary); outputResult(dictionary); topFrequencyWordStatistics(dictionary, topFrequencyWord); topFrequencyPhaseStatistics(dictionary, topFrequencyPhase); outputToFile(filePath,topFrequencyWord, topFrequencyPhase); dictionaryDestroy(dictionary); return 0;
我现在很喜欢这种编程方法:在主函数里面将不同的功能分块,然后逐个实现,实现过程中不断细分功能模块。这样从上到下的编程很高效,很清楚,而且程序阅读起来也有条理。垂直格式上我自认为做得不错,可是水平格式上就丑了许多。
(page->wordArray + hash)->wordStr = (char*)realloc((page->wordArray + hash)->wordStr, sizeof(char)*((page->wordArray + hash)->strlength) * 2);
很丑是吧。(page->wordArray + hash)->wordStr实在是太长了,为什么不用tempWordStr代替呢?第一次作业时间有点紧张所以没有优化,下次我会注意的。
良好的垂直和水平格式会使你的代码更清晰美观。试想一下有良好格式的代码是一位三围比例合适的美女,你忍心自己写出的代码是一位身体比例不协调的丑女吗?所以,一定要在这方面下功夫,你的程序会因此赏心悦目。
第六章 对象和数据结构
由于Java还不怎么会用,所以这一部分也是囫囵吞枣的读了一遍。大致意思就是,尽量抽象类的接口,将类内部的情况隐藏起来,问了同学,说这样做可以减少耦合。
第七章 错误处理
同样,在c里面没用过try/catch进行错误处理,所以这一部分也不是很明白。只记得里面说先写try/catch语句定义好范围,然后编写细节部分。
注:以上代码以及修改只是我现在能做到的水平,如有不足欢迎指点!
《代码整洁之道》读书笔记
第一章整洁代码 读完,个人觉得第一章的关键点在于让读者追求卓越,不仅仅满足于功能的实现,更要培养代码整洁的思维。所以对待你的代码就像去雕琢艺术品一样,不要把它当成垃圾,认真去雕琢每一个细节,另外,文... 查看详情
第九次读书笔记——读《代码整洁之道》有感
第九次读书笔记——读《代码整洁之道》有感“相对于任何宏伟景愿,对细节的关注甚至是更为关键的专业的基础。首先,开发者通过小型实践获得可用于大型实践的技能和信用度。其次,宏伟建筑中最细小的部分,比如关不紧... 查看详情
《代码整洁之道》读书笔记
...这句话的浓缩。 本书的第一章是关于什么是整洁代码的讨论,引用了Bjarne 查看详情
第五次读书笔记——robrtc.martin的《代码整洁之道》
本周我读的书是美国作者RobrtC.Martin的《代码整洁之道》。一周的时间,我主要阅读了本书的前五章,关于整洁代码、有意义的命名、函数、注释以及格式等内容。书中作者有个观点:优雅和高效。作者说:代码逻辑应当直... 查看详情
代码整洁之道读书笔记
代码整洁之道TableofContents1.原则1.1.单一权责1.1.1.一个类应该完成一个类型的任务1.1.2.內聚性要高,即每个函数使用类变量的多少1.2.开放封闭原则1.2.1.对内封闭对外开放2.军规2.1.只做好一件事2.2.短小精悍2.3.代码不要重复2.4.开... 查看详情
代码整洁之道读书笔记
代码整洁之道TableofContents1.原则1.1.单一权责1.1.1.一个类应该完成一个类型的任务1.1.2.內聚性要高,即每个函数使用类变量的多少1.2.开放封闭原则1.2.1.对内封闭对外开放2.军规2.1.只做好一件事2.2.短小精悍2.3.代码不要重复2.4.开... 查看详情
读书笔记3.29
本周大致翻看了一下《代码整洁之道》,着实学到了一些东西。在第一章里,BjarneStroustrup(C++发明者)便阐明了整洁的代码所蕴含的意义,他说:“我喜欢优雅和高效的代码,代码逻辑应当直接了当,叫缺陷难以隐藏;尽量减... 查看详情
《代码整洁之道》读书笔记
...状态,还是只对过程进行阐述,不下结论,《代码整洁之道》书中的观点亦是如此。一、感悟说实话这本书读起来没有太多的让我惊喜的时刻,一方面可能是因为和《重构》有重叠,导致很多东西都比较熟悉... 查看详情
《python黑帽子:黑客与渗透测试编程之道》读书笔记:基于github的木马(代码片段)
目录前言1、github的配置2、创建模块3、木马配置4、编写基于github通信的木马结语前言《Python黑帽子:黑客与渗透测试编程之道》的读书笔记,会包括书中源码,并自己将其中一些改写成Python3版本。书是比较老了,... 查看详情
架构整洁之道,看这一篇就够了!(代码片段)
阿里妹导读:程序的世界飞速发展,今天所掌握的技能可能明年就过时了,但有些知识历久弥新,掌握了它们,你在程序的海洋中就不会迷路,架构思想就是这样的知识。本文是《架构整洁之道》的读书心得,作者将书中内容拆... 查看详情
[阅读笔记]代码整洁之道
第一章: 1.混乱的代码难以维护,导致生产力越来越低。糟糕的代码引发混乱,越改越烂。2.整洁的代码:优雅,高效,少依赖,性能优,命名规范,清晰尽量少的api3.破窗理论:窗户破损的建筑让人觉得无人照管,于是别人... 查看详情
整洁架构之道--三种经典的编程范式(代码片段)
本文是《CleanArchitecture》--整洁架构之道中关于编程范式相关章节的笔记,首发于公众号「Go招聘」这和软件架构的三大关注重点不谋而合:功能性、组件独立性以及数据管理。的方式。回答此问题的同时另外还会搬出这三个词语... 查看详情
《python黑帽子:黑客与渗透测试编程之道》读书笔记:web攻击(代码片段)
目录前言1、urllib22、开源web应用安装3、破解目录和文件位置4、破解HTML表格认证结语前言《Python黑帽子:黑客与渗透测试编程之道》的读书笔记,会包括书中源码,并自己将其中一些改写成Python3版本。书是比较老了... 查看详情
《python黑帽子:黑客与渗透测试编程之道》读书笔记:自动化攻击取证(代码片段)
目录前言1、Volatility配置2、抓取口令的哈希值3、直接代码注入4、插入shellcode结语前言《Python黑帽子:黑客与渗透测试编程之道》的读书笔记,会包括书中源码,并自己将其中一些改写成Python3版本。书是比较老了... 查看详情
《python黑帽子:黑客与渗透测试编程之道》读书笔记:windows提权(代码片段)
目录前言1、进程监视器2、赢得竞争结语前言《Python黑帽子:黑客与渗透测试编程之道》的读书笔记,会包括书中源码,并自己将其中一些改写成Python3版本。书是比较老了,anyway,还是本很好的书本篇是第10章... 查看详情
《python黑帽子:黑客与渗透测试编程之道》读书笔记:扩展burp代理(代码片段)
目录前言1、burp的fuzz脚本2、burp中利用Bing服务3、利用网站内容生成密码字典结语前言《Python黑帽子:黑客与渗透测试编程之道》的读书笔记,会包括书中源码,并自己将其中一些改写成Python3版本。书是比较老了,... 查看详情
《python黑帽子:黑客与渗透测试编程之道》读书笔记:网络基础(代码片段)
目录前言1、网络基础(1)TCP客户端(2)UDP客户端(3)TCP服务器2、取代netcat(1)bhnet.py脚本(2)运行方法3、创建一个TCP代理(1)TCPproxy.py脚本(2)运行方法4 查看详情
《python黑帽子:黑客与渗透测试编程之道》读书笔记:scapy——网络的掌控者(代码片段)
目录前言1、窃取email认证2、ARP缓存投毒3、PCAP文件处理结语前言《Python黑帽子:黑客与渗透测试编程之道》的读书笔记,会包括书中源码,并自己将其中一些改写成Python3版本。书是比较老了,anyway,还是本很... 查看详情