前言
这一周很快又过去了,不够这周的速度实在是太慢了,一周进度一百页,我得赶紧加快进度了。
首先说说第六章使用curses函数库管理基于文本的屏幕。这一章主要的内容都是curses函数库了,基于这个函数库,已经可以完全的控制屏幕,在屏幕上加窗口,显示,说来我之前写C的时候还只会用printf输出空格键和换行来手动计算应该输出的位置,总算有了一个工具。
curses函数都挺人性化,命名也容易记。手敲了几个代码之后就熟悉了在特定位置,特定窗口输出的函数,然后reflash一下就行。关闭就endwin函数。非常的好用。
在敲完其中一个程序之后发现了书里代码有一个bug,P181页的程序显示出的字符少了第一个字母.原代码如下:
moveadd.c:
<pre name="code" class="html">scan_ptr = witch_one +strlen(witch_one) -1; while(scan_ptr!=witch_one) { move (10,10); insch(* scan_ptr --); }
scan_ptr = witch_one +strlen(witch_one) ; do(scan_ptr!=witch_one) { move (10,10); insch(* --scan_ptr ); }while(scan_ptr !=witch_one);
子窗口部分与pad模式让这个终端界面的显示更加有了一点自如的感觉,可以像window一样把方框移到屏幕之外了。可以把想显示的部分放在屏幕中。这一部分的代码入口参数很多,不过仔细想想这些参数是完全不能少的。
keypad模式,用来识别方向键和功能键,最开始学习的时候完全不明白要这个干吗,不过等到了后面做cd管理程序的时候发现这个东西不要太好用,可以用上下左右键来滚屏幕,真是很棒的体验。比起选定一个数字,然后输入进去的用户界面用起来舒服多了。
好了,话不多说,来到第一个算是真正有用户界面的linux程序吧。
这一部分的程序划分的规划让我感觉特别的认同,在刚刚开始研究生开发的时候,我写了一个DSP雷达算法的程序,差不多有1w行吧,不过在那个程序里只有一个.c文件,所有的头文件,预定义,地址规划,乱七八糟的东西都在里面,实现功能的代码也是上下文相关的,前面改了,后面也得跟着改,写到后面我都快继续不下去了。好在最后程序成功实现功能,可以丢下这堆烂摊子了。。如果让我重写这个程序的话,我第一件事情已经绝对不会上学就开始实现功能,而是会利用面向对象的编程思想,把这些要处理的部分都归类,减少他们之间的相互联系,这样不仅仅鞥减少代码量,提高可读性,最重要的是改起bug来不会一个bug改一天了
首先这个程序吧各吧菜单做一个程序,菜单里的选项做一个程序,然后像C++的成员函数访问成员一样,写了一堆控制数据文件的小函数,其他的程序调用这些小程序实现功能。最后代码量在700行左右,如果我以前的水平来写,估计要到2000行吧
对于实现滚屏,我也是没有想到居然可以如此实现,程序维护一个计数器,计数器的值代表着菜单选项的第几个选项。然后该选项高亮表示,使用keypad模式读取方向键,按下向上键,计数器减一,然后重新绘制窗口,刷新一下,高亮的选项就向上了。如果是我自己来做,肯定会写一个代码,只改当前和下一个选项的亮度值。我还是太年轻了。
同样书上的代码也出现了bug(话说我可是花大价钱买的正版啊!!!)
P204页 draw_menu程序中, 第一个
txt_ptr++;应该删掉。这是一句多余的话,导致字符串第一个字母被略过了。
第七章:数据管理
这一章首先是理解malloc的使用,手敲了几个代码之后很快就过去了。
第二部分文件锁定,这一个部分我早在我很久之前写代码的时候就一直在想,我写的东西别人正好也在写怎么办,答案就在这里,文件锁。
不过文件锁使用的函数真是不好记,敲代码的时候总是记不住需要一个什么参数,或者看到了参数还得回去前面看什么意思。不过这个部分的内容非常基础有用,现在勉强记住了,估计不久就会忘了,还得回来好好复习复习。
过了这一部分之后,来到了新的cd程序(话说上一个程序我敲代码就用了一天好吗!!),这一次是用餐dbm数据库了。
dbm数据库CentOS系统自带,问题不大,调用的几个函数也简单,主要需要牢牢记住datum结构体,使用key去配对数据。记牢这个使用就没问题了。
好了,到了cd程序了。这一个程序不再使用用户界面了,主要的内容集中在数据库之上,要我自己添加用户界面也简单,只要修改draw_menu函数就能完成。
首先,我花了一天时间敲好了代码,然后第二天,出现Segment Fault,,通过之前的内存学习,我知道这是linux之中出现了内存溢出的部分。然后对应着出错的代码回去写上printf()函数,用来判断是在哪一步程序中断的。
然后。。linux系统在终端界面弹出error文本,告诉我cpu已经100度,一摸出风口,直接吓尿,赶紧拔了电源卸了电池关机,然后开机linux告诉我内核出错。。。。我还是第一次出现这么大的bug,我感到这个bug肯定不好调了。
果然,我用了快半天的时间才成功的定位了错误出现的代码行,是调用get_confirm函数,返回到调用它的函数的时候出现了段错误。。。。
这一下我就蒙了,怎么从stack里退回到原函数还能出错?,没办法,只能上网找segment fault的资料查看,找了大半天还是没有找到合适的解决办法。于是只好和书上的代码一步一步对照。看了两遍,什么也没发现,然后上网上下载了源代码,编译运行成功。。
。看来还是我这里有问题。
再找了一遍,实在找不出来了。于是只好让完全不懂编程的女朋友给我看看。。还是不懂的人和我们的关注点不同,她发现在调用get_confirm函数之前大约20行左右的地方使用strncpy 函数时有一个名字不一样。我仔细一看,原来是我调用的strncpy时使用的字符串长度的宏定义用成了另外一个。。
但是奇怪的是,调用实际上已经越界了。但是没有报错。并且调用子函数时也没有出错,再返回的时候才出现了错误。我还是第一次遇到这样的情况,长见识了!改好这里之后,果然,这一部分运行正常了。
另一部分,与dbm数据库进行交接的部分也出错了。同样检查了半天,没能找出问题。使用源代码编译运行正常。于是又回到了苦逼的对照代码的阶段。对照了两遍,没找出来,于是只能再使用printf()函数来人工断点。 最后定位到了if语句之前。 怎么看不出问题啊,逻辑上这段if程序时不会进入的。然后交给女友,发现了
if((strlen(tmp_str) ==1 ) && tmp_str[0] == 'd')这个语句不同,我仔细一看,尼玛,写成这样了
if((strlen(tmp_str ==1 )) && tmp_str[0] == 'd')我在用char* 和int的1对比,对比结果进行strlen。我突然意识到这个没有报错啊,再次编译,发现是个warning, 使用char* 和int对比,默认允许。难怪没能发现,而且照理不会进入的if部分也不会去检查。所以一直找不到错误。
最后一个逗比的错误是宏定义里的字符串中的下划线写成了横杠。也是查了一个小时。。真是累觉不爱了
以后我一定要好好读warning,检查了宏定义才开始写代码!!!