标签:gdb
1,先设置
chunli@ubuntu:~/makefile$ ulimit -c unlimited
安装gdb
chunli@ubuntu:~/makefile$ sudo apt-get install gdb
源文件 main.c
#include <stdio.h> int main() { int *i ; *i = 100; return 0; }
makefile文件:
.SUFFIXES:.c .o CC=gcc EXEC=app SRCS=main.c OBJS=$(SRCS:.c=.o) #跟随SRCS的文件名前缀,相当于字符串替换 FLAGS1=-o FLAGS2=-c start:$(OBJS) $(CC) $(FLAGS1) $(EXEC) $(OBJS) @echo "-------------OK---------" .c.o: $(CC) -g $(FLAGS1) $@ $(FLAGS2) $< clean: rm -rf $(OBJS) rm -rf $(EXEC)
编译:
chunli@ubuntu:~/makefile$ make gcc -o main.o -c main.c gcc -g -o app main.o -------------OK---------
运行
chunli@ubuntu:~/makefile$ ./app Segmentation fault (core dumped) chunli@ubuntu:~/makefile$ ll total 288K -rwxrwxr-x 1 chunli chunli 8.4K Jun 10 15:05 app -rw------- 1 chunli chunli 256K Jun 10 14:58 core -rw-rw-r-- 1 chunli chunli 67 Jun 10 14:56 main.c -rw-rw-r-- 1 chunli chunli 1.3K Jun 10 15:05 main.o -rw-rw-r-- 1 chunli chunli 305 Jun 10 14:59 makefile chunli@ubuntu:~/makefile$
运行gdb :
chunli@ubuntu:~/makefile$ gdb app core
查看哪儿出错了
(gdb) where #0 0x00000000004004f5 in main ()
==========================================================
项目源文件:
这是一个可以正常编译,但执行就出错的程序:
修改了delete函数部分信息,调用时删除一个不存在的节点
chunli@ubuntu:~/gdb$ cat main.c //单向链表 #include <stdio.h> #include <stdlib.h> struct list //链表结构体 { int data; // 数据 struct list *next; //指针域,指向一下个域的指针 }; struct list *create_list()//创建一个节点,返回值为list结构体指针 { return calloc(sizeof(struct list),1); } void traverse(struct list *ls) //遍历链表 { if(ls) //只要地址不为NULL { //先序递归 printf("地址 %p,本节点的值 %d \n",ls,ls->data); traverse(ls->next); } } struct list *insert_list(struct list *ls,int n,int data) //在指定位置插入元素,(首节点,在第几个节点插入,这个节点的data值) { struct list *p = ls; while(p && n--) { p = p->next; } if(!p) return NULL;//n指向了一个无效的位置 else { struct list *node = create_list(); node->data = data; //掐断原来的链表,重新组合 node->next = p->next; p->next = node; return node; } } int delete_list(struct list *ls,int n) //删除链表元素,1链表首元素,要删除第几个? { struct list *p = ls; while(p && n--) { p = p->next; } //if(!p) return 0;//n指向了一个无效的位置 //else { struct list *node = p->next; //记录待删除节点的地址 //if(!node) return 0; //如果这个节点是无效的,就返回无效 p->next = node->next; //将该节点next指向待删除节点的next节点的next节点 free(node); return 1; //操作成功! } } int count_list(struct list *ls) //返回链表元素个数,包括首节点 { struct list *p = ls->next; int count = 0; while(p) { count++; p = p->next; } return count; } void clear_list(struct list *ls) //清空链表,保留首节点 { struct list *p = ls->next; //要跳过首节点,进入该链表的第一个有效元素 struct list *tmp; while(p) { tmp = p->next; //记录当前节点的next free(p); //释放这个有效的元素 p = tmp; } ls->next = NULL; //链表清空后,首节点就是尾节点,一定设置为NULL } int empty_list(struct list *ls) //返回链表是否为空 { if(ls->next) //如果不为空,返回1 return 1; else //如果 为空,返回0 return 0; } struct list *local_list(struct list *ls,int n) //返回链表对应的第N个节点的地址 { struct list *p = ls->next; //立即指向首节点的下一个元素 while(p && n--) { p = p->next; } return p; } struct list *elem_local(struct list *ls,int data) //返回链表中数据域值data的节点地址 { struct list *p = ls->next; //立即指向首节点的下一个元素 while(p) { if(p ->data == data) {break;} p = p->next; } return p; } int elem_pos(struct list *ls,int data) //返回链表中数据域值data的节点的序号 { struct list *p = ls->next; //立即指向首节点的下一个元素 int count = 0; while(p) { if(p ->data == data) {break;} p = p->next; count++; } return count; } struct list *last_list(struct list *ls) //返回链表的最后一个元素 { struct list *p =ls->next; struct list *back = p; while(p) { back = p; p = p->next; } return back; } void merge_list(struct list *ls1,struct list *ls2) //把链表2的有效元素合并到链表1 { struct list *last = last_list(ls1); last->next = ls2->next; } void reverse_list(struct list *ls) //逆置链表 { if(!(ls || ls->next || ls->next->next)) {return ;} //只有大于1个有效节点,才需要逆置 struct list *left = NULL; //记录上一个节点的地址,初始值的NULL刚好可以作为尾节点的next的NULL struct list *curr = ls->next; //记录当前节点的地址 struct list *right = NULL; //遍历完原链表的所以元素 while(curr) //遍历完原链表的所有元素 { right = curr->next; //下一个节点就是当前节点的next curr->next = left; //第一次执行的时候,curr节点就是尾节点了,就将尾节点的next指向了NULL left = curr; //把当前的节点作为上一个节点 curr = right; //把下一个节点作为当前节点 } ls->next = left; //原链表的最后的一个有效元素就已经变为left了,让链表节点指向这个left就好了。 } int main() { /* 链表ADT操作的代码实现 */ printf("\n\n\n开始批量创建链表\n"); struct list *node_start = create_list(); //此时链表的长度只有1个,有效元素个数为0 for(int i=0;i<4;i++) //在原来的首节点上插入10个,结果就是11个 { //链表插入只能在首节点之后 //insert_list(node_start,i,i+100); //每次都在第i个位置插入,越后来插入的越靠后 insert_list(node_start,0,i+100); //每次都在第0个位置插入,越后来插入的越靠前 } delete_list(node_start,30); //在指定位置删除节点 insert_list(node_start,2,666); //在指定位置插入节点 traverse(node_start); //遍历链表 printf("链表有效元素有%d个(不包括首节点)\n",count_list(node_start)); //返回这个链表元素的个数 printf("第2个节点的数据是%d\n",local_list(node_start,2)->data); //返回链表第N个有效元素的地址 printf("最后一个元素的数据域是 %d\n",last_list(node_start)->data); //返回链表 最后一个元素的地址 printf("\n\n链表合并,结果输出\n"); struct list *node2 = create_list(); for(int i=0;i<8;i++) { insert_list(node2,0,i+33); } merge_list(node_start,node2); //把node2合并到node_start traverse(node_start); //遍历链表 printf("\n逆置链表,结果输出\n"); reverse_list(node_start); traverse(node_start); //遍历链表 printf("\n\n\n清空链表\n"); clear_list(node_start); //清空链表 traverse(node_start); //遍历链表 return 0; }
提供makefile文件
chunli@ubuntu:~/gdb$ cat makefile .SUFFIXES:.c .o CC=gcc -std=c99 EXEC=app SRCS=main.c OBJS=$(SRCS:.c=.o) #跟随SRCS的文件名前缀,相当于字符串替换 FLAGS1=-o FLAGS2=-c start:$(OBJS) $(CC) $(FLAGS1) $(EXEC) $(OBJS) @echo "-------------OK---------" .c.o: $(CC) -g $(FLAGS1) $@ $(FLAGS2) $< clean: rm -rf $(OBJS) rm -rf $(EXEC) chunli@ubuntu:~/gdb$
1【利用内核的信息查看错误】
[打开core] chunli@ubuntu:~/gdb$ ulimit -c unlimited [编译] chunli@ubuntu:~/gdb$ make gcc -std=c99 -g -o main.o -c main.c gcc -std=c99 -o app main.o -------------OK--------- [运行] chunli@ubuntu:~/gdb$ ./app Segmentation fault (core dumped) [开始调试] chunli@ubuntu:~/gdb$ gdb app core [输入where,告诉你哪儿错了,在主程序的177行,在delete_list函数,55行] (gdb) where #0 0x0000000000400723 in delete_list (ls=0x1305010, n=25) at main.c:55 #1 0x0000000000400a16 in main () at main.c:177
【gdb查错】
chunli@ubuntu:~/gdb$ gdb app [键入run] (gdb) run Starting program: /home/chunli/gdb/app 开始批量创建链表 Program received signal SIGSEGV, Segmentation fault. 0x0000000000400723 in delete_list (ls=0x603010, n=25) at main.c:55 55 struct list *node = p->next; //记录待删除节点的地址 [键入where] (gdb) where #0 0x0000000000400723 in delete_list (ls=0x603010, n=25) at main.c:55 #1 0x0000000000400a16 in main () at main.c:177 (gdb) [可以很清晰的看到在主程序的第55行,出了问题] [列出出错的上下文] (gdb) list 50 p = p->next; 51 } 52 //if(!p) return 0;//n指向了一个无效的位置 53 //else 54 { 55 struct list *node = p->next; //记录待删除节点的地址 56 //if(!node) return 0; //如果这个节点是无效的,就返回无效 57 p->next = node->next; //将该节点next指向待删除节点的next节点的next节点 58 free(node); 59 return 1; //操作成功!
【设置断点】
[运行gdb] chunli@ubuntu:~/gdb$ gdb app [设置断点]从上面可以看出55行出错 (gdb) break 55 [让程序跑] (gdb) run [停下来了,看看此时p的是多少] (gdb) print p $1 = (struct list *) 0x0 [查看变量类型] (gdb) whatis p type = struct list * [在指定文件的行数加入断点] (gdb) break main.c:100 [info 提供信息] 当前在第一个断点,还有一个断点 (gdb) info break Num Type Disp Enb Address What 1 breakpoint keep y 0x000000000040071f in delete_list at main.c:55 breakpoint already hit 1 time 2 breakpoint keep y 0x0000000000400812 in local_list at main.c:100
【把上面原程序中的delete_list换成下面的】
int delete_list(struct list *ls,int n) //删除链表元素,1链表首元素,要删除第几个? { struct list *p = ls; while(p && n--) { p = p->next; } if(!p) return 0;//n指向了一个无效的位置 else { struct list *node = p->next; //记录待删除节点的地址 if(!node) return 0; //如果这个节点是无效的,就返回无效 p->next = node->next; //将该节点next指向待删除节点的next节点的next节点 free(node); return 1; //操作成功! } } 主函数的delete也换换 delete_list(node_start,0);
重新编译:
delete的调用显示在主函数的200行 [运行gdb] chunli@ubuntu:~/gdb$ gdb app (gdb) break main.c:200 【在主函数的第200行设置断点】 (gdb) run (gdb) list 【列出上下文】 (gdb) set variable node_start=0x0000【修改一个变量的值】 (gdb) step 【当遇到函数,step就是进入函数】 delete_list (ls=0x0, n=0) at main.c:47 47 struct list *p = ls; (gdb) step 【进入函数内部】 48 while(p && n--) (gdb) next 【下一步,不会进入函数内部】 202 traverse(node_start); //遍历链表
【gdb return 的使用】
chunli@ubuntu:~/gdb$ gdb app (gdb) break main.c:169 (gdb) run (gdb) return 0 Make main return now? (y or n) y
本文出自 “魂斗罗” 博客,请务必保留此出处http://990487026.blog.51cto.com/10133282/1787808
标签:gdb
原文地址:http://990487026.blog.51cto.com/10133282/1787808