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
















