《Linux下的C编程.ppt》由会员分享,可在线阅读,更多相关《Linux下的C编程.ppt(93页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。
1、Linux与与C编程基础编程基础测试一下测试一下C语言基本功语言基本功3思科面试题思科面试题用变量a给出下面的定义a)一个整型数(Aninteger)b)一个指向整型数的指针(Apointertoaninteger)c)一个指向指针的的指针,它指向的指针是指向一个整型数(Apointertoapointertoaninteger)d)一个有10个整型数的数组(Anarrayof10integerse)一个有10个指针的数组,该指针是指向一个整型数的(Anarrayof10pointerstointegers)4参考答案参考答案答案是:a)inta;/Anintegerb)int*a;/Apoi
2、ntertoanintegerc)int*a;/Apointertoapointertoanintegerd)inta10;/Anarrayof10integerse)int*a10;/Anarrayof10pointerstointegers5思科面试题思科面试题f)一个指向有10个整型数数组的指针(Apointertoanarrayof10integers)g)一个指向函数的指针,该函数有一个整型参数并返回一个整型数(Apointertoafunctionthattakesanintegerasanargumentandreturnsaninteger)h)一个有10个指针的数组,该指针指
3、向一个函数,该函数有一个整型参数并返回一个整型数(Anarrayoftenpointerstofunctionsthattakeanintegerargumentandreturnaninteger)6参考答案参考答案f)int(*a)10;/Apointertoanarrayof10integersg)int(*a)(int);/Apointertoafunctionathattakesanintegerargumentandreturnsanintegerh)int(*a10)(int);/Anarrayof10pointerstofunctionsthattakeanintegerarg
4、umentandreturnaninteger7死循环(死循环(Infiniteloops)2.嵌入式系统中经常要用到无限循环,你怎么样用C编写死循环呢?这个问题用几个解决方案。方案是:while(1)一些程序员更喜欢如下方案:for(;)您能写出更简洁的吗?8面试题面试题更简洁是while(1);for(;);下面语句编译能通过吗?inta;while(1);for(;);9华为面试题华为面试题1、语句for(;1;)有什么问题?它是什么意思?答:和while(1)相同。10华为面试题华为面试题2、dowhile和whiledo有什么区别?答:前一个循环一遍再判断,后一个判断以后再循环11华
5、为面试题华为面试题3、请写出下列代码的输出内容#includemain()inta,b,c,d;a=10;b=a+;c=+a;d=10*a+;printf(b,c,d:%d,%d,%d,b,c,d);return0;答:b,c,d:10,12,12012华为面试题华为面试题4:设有以下语句,说明其定义含义,:设有以下语句,说明其定义含义,并回答问题:并回答问题:typedefunionlongi;intk5;charc;DATE;structdataintcat;DATEcow;doubledog;too;DATEmax;则语句printf(%d,sizeof(structdata)+size
6、of(max);的执行结果是:13华为面试题华为面试题4:设有以下语句说明和定义,解释:设有以下语句说明和定义,解释各自的含义:各自的含义:答案:DATE是一个union,变量公用空间.里面最大的变量类型是int5,占用20个字节.所以它的大小是20data是一个struct,每个变量分开占用空间.依次为int4+DATE20+double8=32.所以结果是20+32=52.当然.在某些16位编辑器下,int可能是2字节,那么结果是int2+DATE10+double8=20145、请找出下面代码中的所有点错误,并给出修改方案、请找出下面代码中的所有点错误,并给出修改方案说明:以下代码是把一
7、个字符串倒序,如“abcd”倒序后变为“dcba”1、#includestring.h2、main()3、4、char*src=hello,world;5、char*dest=NULL;6、intlen=strlen(src);7、dest=(char*)malloc(len);8、char*d=dest;9、char*s=srclen;10、while(len-!=0)11、d+=s-;12、printf(%s,dest);13、return0;14、15方法1:intmain()char*src=hello,world;intlen=strlen(src);char*dest=(char*
8、)malloc(len+1);/要为0分配一个空间char*d=dest;char*s=&srclen-1;/指向最后一个字符while(len-!=0)*d+=*s-;*d=0;/尾部要加0printf(%sn,dest);free(dest);/使用完,应当释放空间,以免造成内存汇泄露return0;16方法2:#includestring.h#include“stdio.h”main()charstr=hello,world;intlen=strlen(str);chart;for(inti=0;i)t=stri;stri=strlen-i-1;strlen-i-1=t;printf(%
9、s,str);return0;17vim命令学习命令学习-11.欲进入vim编辑器(从命令行提示符),请输入vim文件名2.光标在屏幕文本中的移动既可以用箭头键,也可以使用hjkl字母键。h(左移)j(下行)k(上行)l(右移)3.欲退出vim编辑器,请输入以下命令放弃所有修改:q!或者输入以下命令保存所有修改:wq18vim命令学习命令学习-24.在正常模式下删除光标所在位置的字符,请按x5.在正常模式下要在光标所在位置开始插入文本,请按i输入必要文本特别提示按下键会带您回到正常模式或者取消一个不期望或者部分完成的命令19vim命令学习命令学习-31.欲从当前光标删除至单字/单词末尾,请输入
10、dw2.欲从当前光标删除至当前行末尾,请输入d$3.欲删除整行,请输入dd20vim命令学习命令学习-44.在正常模式下一个命令的格式是numbercommandobject或者commandnumberobject其意是number-代表的是命令执行的次数command-代表要做的事情,比如d代表删除.object-代表要操作的对象,比如w代表单字/单词,$代表到行末等等。$(totheendofline),etc.21vim命令学习命令学习-4dnw:删除n个单词dne:也可,只是删除到单词尾dnl:向右删除n个字母dnh:向左删除n个字母dnj:向下删除n行dnk:向上删除n行d$:删除
11、当前光标到改行的行尾的字母dd:删除一行22vim命令学习命令学习-45.欲撤消以前的操作,请输入u(小写的u)欲撤消在一行中所做的改动,请输入U(大写的U)欲撤消以前的撤消命令,恢复以前的操作结果,请输入CTRL-R23vim命令学习命令学习-5粘贴:p,这是粘贴用x或d删除的文本复制:ynw:复制n个单词yy:复制一行ynl:复制n个字符y$:复制当前光标至行尾处nyy:拷贝n行完了用p粘贴24vim命令学习命令学习-5:split:分割一个窗口:splitfile.c:为另一个文件file.c分隔窗口:nsplitfile.c:为另一个文件file.c分隔窗口,并指定其行数CTRLW在窗
12、口中切换:close:关闭当前窗口25C源程序的编译源程序的编译在Linux下面,如果要编译一个C语言源程序,我们要使用GNU的gcc编译器.下面我们以一个实例来说明如何使用gcc编译器.假设我们有下面一个非常简单的源程序(hello.c):#includeintmain()printf(WelcometoLinuxProgrammingn);return0;2627C源程序的编译源程序的编译要编译这个程序,我们只要在命令行下执行:gcc-ohellohello.cgcc编译器就会为我们生成一个hello的可执行文件.执行./hello就可以看到程序的输出结果了.28源程序的编译源程序的编译g
13、cc-ohellohello.c命令行中gcc表示我们是用gcc来编译我们的源程序,-o选项表示我们要求编译器给我们输出的可执行文件名为hello而hello.c是我们的源程序文件.gcc编译器有许多选项,一般来说我们只要知道其中的几个就够了.29gcc编译器选项编译器选项-o选项,表示我们要求输出的可执行文件名.-c选项表示我们只要求编译器输出目标代码,而不必要输出可执行文件.-g选项表示我们要求编译器在编译的时候提供我们以后对程序进行调试的信息.30gcc编译器选项编译器选项知道了这三个选项,我们就可以编译我们自己所写的简单的源程序了如果你想要知道更多的选项,可以查看gcc的帮助文档,那里
14、有着许多对其它选项的详细说明.31多源文件的编译方法多源文件的编译方法如果有多个源文件,基本上有两种编译方法:假设有两个源文件为test.c和testfun.ca.多个文件一起编译用法:#gcctestfun.ctest.c-otest作用:将testfun.c和test.c分别编译后链接成test可执行文件。32多源文件的编译方法多源文件的编译方法b.分别编译各个源文件,之后对编译后输出的目标文件链接。用法:#gcc-ctestfun.c/将testfun.c编译成testfun.o#gcc-ctest.c/将test.c编译成test.o#gcc-otestfun.otest.o-otes
15、t/将testfun.o和test.o链接成test33多源文件的编译方法多源文件的编译方法以上两种方法相比较,第一中方法编译时需要所有文件重新编译而第二种方法可以只重新编译修改的文件,未修改的文件不用重新编译。34补充:如何利用补充:如何利用gcc编译编译”C+”GCC是个功能很强大,但精通的掌握它也许需要几个月的时间。例如:编写my_class.cpp和my_class.h包含你自己创建的一个类。写一个test.cpp,里面包含main函数并且调用my_class。1、g+-cmy_class.cpp2、g+-otesttest.cppmy_class.o实际上对于C+程序员,只要记住g+
16、命令,记住-c和-o两个参数,就可以开始用gcc了。35Makefile的编写的编写假设我们有下面这样的一个程序,源代码如下:/*main.c*/#includemytool1.h#includemytool2.hintmain(intargc,char*argv)mytool1_print(hello);mytool2_print(hello);36Makefile的编写的编写/*mytool1.c*/#includemytool1.hvoidmytool1_print(char*print_str)printf(Thisismytool1print%sn,print_str);/*myto
17、ol1.h*/#ifndef_MYTOOL_1_H#define_MYTOOL_1_Hvoidmytool1_print(char*print_str);#endif/*mytool2.h*/#ifndef_MYTOOL_2_H#define_MYTOOL_2_Hvoidmytool2_print(char*print_str);#endif/*mytool2.c*/#includemytool2.hvoidmytool2_print(char*print_str)printf(Thisismytool2print%sn,print_str);37Makefile的编写的编写当然由于这个程序是
18、很短的我们可以这样来编译gcc-cmain.cgcc-cmytool1.cgcc-cmytool2.cgcc-omainmain.omytool1.omytool2.o这样的话我们也可以产生main程序,而且也不很麻烦.但是如果我们考虑一下如果有一天我们修改了其中的一个文件(比如说mytool1.c),那么我们还要重新输入上面的命令,非常的麻烦!3839Makefile的编写的编写当我们把事情想的更复杂一点,如果我们的程序有几百个源程序的时候,难道也要编译器重新一个一个的去编译?为此,聪明的程序员们想出了一个很好的工具来做这件事情,这就是make.我们只要执行以下make,就可以把上面的问题解
19、决掉.在我们执行make之前,我们要先编写一个非常重要的文件.-Makefile.40Makefile的编写的编写.在我们执行make之前,我们要先编写一个非常重要的文件.-Makefile.对于上面的那个程序来说,可能的一个Makefile的文件是:#注释行,这是上面那个程序的Makefile文件main:main.omytool1.omytool2.ogcc-omainmain.omytool1.omytool2.omain.o:main.cmytool1.hmytool2.hgcc-cmain.cmytool1.o:mytool1.cmytool1.hgcc-cmytool1.cmyto
20、ol2.o:mytool2.cmytool2.hgcc-cmytool2.c4142Makefile的编写的编写有了这个Makefile文件,不管我们什么时候修改了源程序当中的什么文件,我们只要执行make命令我们的编译器都只会去编译和我们修改的文件有关的文件,其它的文件不予理睬,节省了大量编译时间。43Makefile的编写的编写下面我们学习Makefile是如何编写的.在Makefile中#开始的行都是注释行.Makefile中最重要的是描述文件的依赖关系的说明.一般的格式是:target:componentsTABrule/第一行表示的是依赖关系./第二行是规则.44Makefile的编
21、写的编写比如说我们上面的那个Makefile文件的第二行main:main.omytool1.omytool2.o表示我们的目标(target)main的依赖对象(components)是main.omytool1.omytool2.o当倚赖的对象在目标修改后修改的话,就要去执行规则一行所指定的命令.就象我们的上面那个Makefile第三行所说的一样要执行gcc-omainmain.omytool1.omytool2.o注意规则一行中的TAB表示那里是一个TAB键45Makefile的编写的编写46Makefile的常用变量的常用变量Makefile有三个非常有用的变量:$,$,$。其意义为:
22、$:目标文件$:所有的依赖文件$:第一个依赖文件如果使用上面三个变量,上面那个Makefile文件可简化为:47#注释行,注释行,这是原来程序的这是原来程序的Makefile文件文件main:main.omytool1.omytool2.ogcc-omainmain.omytool1.omytool2.omain.o:main.cmytool1.hmytool2.hgcc-cmain.cmytool1.o:mytool1.cmytool1.hgcc-cmytool1.cmytool2.o:mytool2.cmytool2.hgcc-cmytool2.c#这是简化后的这是简化后的Makefile
23、main:main.omytool1.omytool2.ogcc-o$main.o:main.cmytool1.hmytool2.hgcc-c$mytool1.o:mytool1.cmytool1.hgcc-c$mytool2.o:mytool2.cmytool2.hgcc-c$:目标文件:目标文件$:所有的依赖文件:所有的依赖文件$:第一个依赖文件:第一个依赖文件484950Makefile的缺省规则的缺省规则.c.o:gcc-c$这个规则表示所有的所有的.o文件都是依赖于相应的文件都是依赖于相应的.c文件的文件的,例如mytool.o依赖于mytool.c。这样上面那个Makefile还可
24、以简化为:51#这是简化后的这是简化后的Makefilemain:main.omytool1.omytool2.ogcc-o$main.o:main.cmytool1.hmytool2.hgcc-c$mytool1.o:mytool1.cmytool1.hgcc-c$mytool2.o:mytool2.cmytool2.hgcc-c$#这是再一次简化后的这是再一次简化后的Makefilemain:main.omytool1.omytool2.ogcc-o$.c.o:gcc-c$:目标文件:目标文件$:所有的依赖文件:所有的依赖文件$:第一个依赖文件:第一个依赖文件#注释行,注释行,这是原来程序
25、的这是原来程序的Makefile文件文件main:main.omytool1.omytool2.ogcc-omainmain.omytool1.omytool2.omain.o:main.cmytool1.hmytool2.hgcc-cmain.cmytool1.o:mytool1.cmytool1.hgcc-cmytool1.cmytool2.o:mytool2.cmytool2.hgcc-cmytool2.c.c.o:gcc-c$#这个规则表示这个规则表示所有的所有的.o文件都是依赖于相应的文件都是依赖于相应的.c文件的文件的5253程序的调试程序的调试我们编写的程序不太可能一次性就会成功
26、的,在我们的程序当中,会出现许许多多我们想不到的错误,这个时候我们就要对我们的程序进行调试了.最常用的调试软件是gdb.GDB(GNUsymbolicdebugger)简单地说就是一个调试工具。它是一个受通用公共许可证即GPL保护的自由软件。记得要在编译的时候加入-g选项.54GDB概述概述GDB是GNU开源组织发布的一个强大的UNIX下的程序调试工具。或许,各位比较喜欢那种图形界面方式的,像VC、BCB等IDE的调试,但如果你是在UNIX/Linux平台下做软件,你会发现GDB这个调试工具有比VC、BCB的图形化调试器更强大的功能。所谓“寸有所长,尺有所短”就是这个道理。55GDB概述概述一
27、般来说,GDB主要帮忙你完成下面四个方面的功能:1、启动你的程序,可以按照你的自定义的要求随心所欲的运行程序。2、可让被调试的程序在你所指定的调置的断点处停住。(断点可以是条件表达式)3、当程序被停住时,可以检查此时你的程序中所发生的事。4、动态的改变你程序的执行环境。56一个调试示例一个调试示例/源程序:tst.c1#include23intfunc(intn)45intsum=0,i;6for(i=0;in;i+)78sum+=i;910returnsum;11121314main()1516inti;17longresult=0;18for(i=1;igcc-ghello.c-ohell
28、og+-ghello.cpp-ohello如果没有如果没有-g,将看不见程序的函数名、变量名,所,将看不见程序的函数名、变量名,所代替的全是运行时的代替的全是运行时的内存地址内存地址。当你用当你用-g把调试信息加入之后,并成功编译目标代把调试信息加入之后,并成功编译目标代码以后,让我们来看看如何用码以后,让我们来看看如何用gdb来调试程序。来调试程序。59启动启动GDB的方法有以下几种:的方法有以下几种:1、gdbprogram也就是你的也就是你的执行文件执行文件,一般在当然目,一般在当然目录下。录下。2、gdbcore用用gdb同时调试一个运行程序和同时调试一个运行程序和core文件,文件,
29、core是程序非法执行后是程序非法执行后coredump后产生的文件。后产生的文件。3、gdb如果你的程序是一个服务程序,那么你可以指如果你的程序是一个服务程序,那么你可以指定这个服务程序运行时的进程定这个服务程序运行时的进程ID。gdb会自动会自动attach上去,并调试他。上去,并调试他。program应该在应该在PATH环境变量中搜索得到。环境变量中搜索得到。60gdb基本命令基本命令gdb支持很多的命令使你能实现不同的功能.这些命令从简单的文件装入到允许检查所调用的堆栈内容的复杂命令,下表列出了在用gdb调试时会用到的一些命令.想了解gdb的详细使用请参考gdb的指南页.61gdb基本
30、命令基本命令62小技巧小技巧GDB启动后第一次list显示的是main函数的上下文6行可以用l行号,可以显示选定行的上下6行list可以指定打开位置的:list1,15也可以指定要打开的文件:listmain.c:1063使用使用GDB调试:调试:gdbtst-启动启动GDB(gdb)l-l命令相当于命令相当于list,从第一行开始例出原码。,从第一行开始例出原码。1#include23intfunc(intn)45intsum=0,i;6for(i=0;in;i+)78sum+=i;910returnsum;(gdb)-直接回车表示,重复上一次命令直接回车表示,重复上一次命令11121314
31、main()1516inti;17longresult=0;18for(i=1;i=100;i+)1920result+=i;6465(gdb)break16-设置断点,在源程序第设置断点,在源程序第16行处行处。Breakpoint1at0 x8048496:filetst.c,line16.(gdb)breakfunc-设置断点,在函数设置断点,在函数func()入口入口处处。Breakpoint2at0 x8048456:filetst.c,line5.(gdb)infobreak-查看断点信息。查看断点信息。NumTypeDispEnbAddressWhat1breakpointkee
32、py0 x08048496inmainattst.c:162breakpointkeepy0 x08048456infuncattst.c:5(gdb)r-运行程序,运行程序,run命令简写命令简写Startingprogram:/home/hchen/test/tstBreakpoint1,main()attst.c:17-在断点处停住。在断点处停住。17longresult=0;(gdb)n-单条语句执行,单条语句执行,next命令简写。命令简写。18for(i=1;i=100;i+)66(gdb)n20result+=i;(gdb)n18for(i=1;i=100;i+)(gdb)n20
33、result+=i;(gdb)c-继续运行程序,继续运行程序,continue命令简写。命令简写。Continuing.result1-100=5050-程序输出。程序输出。Breakpoint2,func(n=250)attst.c:55intsum=0,i;(gdb)n6for(i=1;i=n;i+)(gdb)pi-打印变量打印变量i的值,的值,print命令简写。命令简写。$1=1345138086768(gdb)n8sum+=i;(gdb)n6for(i=1;i=n;i+)(gdb)psum$2=1(gdb)n8sum+=i;(gdb)pi$3=2(gdb)n6for(i=1;i=n;
34、i+)(gdb)psum$4=3(gdb)bt-查看函数堆栈。查看函数堆栈。#0func(n=250)attst.c:5#10 x080484e4inmain()attst.c:24#20 x400409edin_libc_start_main()from/lib/libc.so.669(gdb)finish-退出函数。退出函数。Runtillexitfrom#0func(n=250)attst.c:50 x080484e4inmain()attst.c:2424printf(result1-250=%dn,func(250);Valuereturnedis$6=31375(gdb)c-继续运
35、行。继续运行。Continuing.result1-250=31375-程序输出。程序输出。Programexitedwithcode027.-程序退出,调试结束。程序退出,调试结束。(gdb)q70GDB的命令概貌的命令概貌启动启动gdb后,就你被带入后,就你被带入gdb的调试环的调试环境中,就可以使用境中,就可以使用gdb的命令开始调试的命令开始调试程序了,程序了,gdb的命令可以的命令可以使用使用help命令命令来查看来查看71gdb中,输入命令时,可以不用打全命令,只用打命令的前几个字中,输入命令时,可以不用打全命令,只用打命令的前几个字符就可以了,当然,命令的前几个字符应该要标志着一
36、个唯一的命符就可以了,当然,命令的前几个字符应该要标志着一个唯一的命令,在令,在Linux下,下,你可以敲击两次你可以敲击两次TAB键来补齐命令的全称键来补齐命令的全称,如果,如果有重复的,那么有重复的,那么gdb会把其例出来。会把其例出来。示例一:在进入函数示例一:在进入函数func时,设置一个断点。可以时,设置一个断点。可以敲入敲入breakfunc,或是直接就是,或是直接就是bfunc(gdb)bfuncBreakpoint1at0 x8048458:filehello.c,line10.示例二:敲入示例二:敲入b按两次按两次TAB键,你会看到所有键,你会看到所有b打头的命令:打头的命令
37、:(gdb)bbacktracebreakbt(gdb)72示例三:只记得函数的前缀,可以这样:示例三:只记得函数的前缀,可以这样:(gdb)bmake_(再按下一次(再按下一次TAB键,你会看到键,你会看到:)make_a_section_from_filemake_environmake_abs_sectionmake_function_typemake_blockvectormake_pointer_typemake_cleanupmake_reference_typemake_commandmake_symbol_completion_list(gdb)bmake_GDB把所有把所有m
38、ake开头的函数全部例出来给你查看。开头的函数全部例出来给你查看。要退出要退出gdb时,只用发时,只用发quit或命令简称或命令简称q就行了。就行了。73GDB中运行中运行Linux的的shell程序程序在在gdb环境中,你可以执行环境中,你可以执行Linux的的shell的命令,使用的命令,使用gdb的的shell命令来完成:命令来完成:shell调用调用Linux的的shell来执行来执行,环境变量,环境变量SHELL中定义的中定义的Linux的的shell将会被用来执行将会被用来执行如果如果SHELL没有定义,那就使用没有定义,那就使用Linux的标准的标准shell:/bin/sh。(
39、在(在Windows中使用中使用C或或cmd.exe)还有一个还有一个gdb命令是命令是make:make可以在可以在gdb中执行中执行make命令来重新命令来重新build自己的程序。这个命令等自己的程序。这个命令等价于价于“shellmake”。7475gdb应用举例应用举例下面一个实例教你一步步的用gdb调试程序.被调试的程序相当的简单,但它展示了gdb的典型应用.下面列出了将被调试的程序.这个程序被称为greeting,它显示一个简单的问候,再用反序将它列出.76案例讲解:案例讲解:gdb调试程序调试程序用一个实例教你一步步的用gdb调试程序.被调试的程序相当的简单,但它展示了gdb的
40、典型应用.下面列出了将被调试的程序.这个程序被称为greeting,它显示一个简单的问候,再用反序将它列出.77#includemain()charmy_string=hellothere;my_print(my_string);my_print2(my_string);voidmy_print(char*string)printf(Thestringis%sn,string);voidmy_print2(char*string)char*string2;intsize,i;size=strlen(string);string2=(char*)malloc(size+1);for(i=0;is
41、ize;i+)string2size-i=stringi;string2size+1=0;printf(Thestringbackwardis%sn,string2);78运行结果运行结果用下面的命令编译它:gcc-otesttest.c这个程序执行时显示如下结果:ThestringishellothereThestringprintedbackwardis输出的第一行是正确的但第二行打印出的东西并不是我们所期望的.我们所设想的输出应该是:Thestringprintedbackwardiserehtolleh79for(i=0;isize;i+)string2size-i=stringi;h
42、ellothere0size=11stringstring201234567891080调试调试由于某些原因,my_print2函数没有正常工作.让我们用gdb看看问题究竟出在哪儿,先键入如下命令:gdbgreeting注意:记得在编译greeting程序时把调试选项打开.81调试调试如果你在输入命令时忘了把要调试的程序作为参数传给gdb,你可以在gdb提示符下用file命令来载入它:(gdb)filegreeting这个命令将载入greeting可执行文件就象你在gdb命令行里装入它一样.这时你能用gdb的run命令来运行greeting了.当它在gdb里被运行后结果大约会象这样:82调试调
43、试(gdb)runStartingprogram:/root/greetingThestringishellothereThestringprintedbackwardisProgramexitedwithcode04183调试调试这个输出和在gdb外面运行的结果一样.问题是,为什么反序打印没有工作?为了找出症结所在,我们可以在my_print2函数的for语句后设一个断点,具体的做法是在gdb提示符下键入list命令三次,列出源代码:(gdb)list(gdb)list(gdb)list技巧技巧:在在gdbgdb提示符下按回车提示符下按回车健将重复上一个命令健将重复上一个命令.84调试调试第
44、一次键入第一次键入list命令的输出如下命令的输出如下:1#include23main()45charmy_string=hellothere;67my_print(my_string);8my_print2(my_string);91085调试调试如果按下回车如果按下回车,gdb将再执行一次将再执行一次list命令命令,给出下列输出给出下列输出:11my_print(char*string)1213printf(Thestringis%sn,string);141516my_print2(char*string)1718char*string2;19intsize,i;2086调试调试再按一
45、次回车将列出再按一次回车将列出greeting程序的剩余部分程序的剩余部分:21size=strlen(string);22string2=(char*)malloc(size+1);23for(i=0;isize;i+)24string2size-i=stringi;25string2size+1=0;26printf(Thestringprintedbackwardis%sn,string2);2787调试调试根据列出的源程序,你能看到要设断点的地方在第24行,在gdb命令行提示符下键入如下命令设置断点:(gdb)break24gdb将作出如下的响应:Breakpoint1at0 x139
46、:filegreeting.c,line24(gdb)88调试调试现在再键入run命令,将产生如下的输出:Startingprogram:/root/greetingThestringishellothereBreakpoint1,my_print2(string=0 xbfffdc4hellothere)atgreeting.c:2424string2size-i=stringi89调试调试你能通过设置一个观察你能通过设置一个观察string2size-i变量的值变量的值的观察点来看出错误是怎样产生的的观察点来看出错误是怎样产生的,做法是键入做法是键入:(gdb)watchstring2si
47、ze-igdb将作出如下回应将作出如下回应:Watchpoint2:string2size-i90调试调试现在可以用现在可以用next命令来一步步的执行命令来一步步的执行for循环了循环了:(gdb)next经过第一次循环后经过第一次循环后,gdb告诉我们告诉我们string2size-i的值是的值是h.gdb用如下的显示来告诉你这个信息用如下的显示来告诉你这个信息:Watchpoint2,string2size-iOldvalue=0000Newvalue=104hmy_print2(string=0 xbfffdc4hellothere)atgreeting.c:2323for(i=0;i
48、size;i+)91调试调试这个值正是期望的.后来的数次循环的结果都是正确的.当i=10时,表达式string2size-i的值等于e,size-i的值等于1,最后一个字符已经拷到新串里了.92调试调试如果你再把循环执行下去,你会看到已经没有值分配给string20了,而它是新串的第一个字符,因为malloc函数在分配内存时把它们初始化为空(null)字符.所以string2的第一个字符是空字符.这解释了为什么在打印string2时没有任何输出了.93调试调试为了使代码正常工作有很多种修改办法为了使代码正常工作有很多种修改办法.一一种是另设一个比串的实际大小小种是另设一个比串的实际大小小1的变量的变量.这是这种解决办法的代码这是这种解决办法的代码:size=strlen(string);size2=size-1;string2=(char*)malloc(size+1);for(i=0;isize;i+)string2size2-i=stringi;string2size=0;