Linux C语言编程基础
安装和配置OpenEuler
使用前几天安装的OpenEuler完成了本次作业。安装OpenEuler的详细步骤可以参见我这一篇博客:https://www.cnblogs.com/Ressurection-20191320/p/15321497.html
二叉树
选择二叉树的相关知识和内容完成了本次作业。本次作业实现了二叉树的存储,以及二叉树的相关功能的实现。包括:
- 二叉树的数据结构和结构体实现
- 二叉树的先序、中序、后序遍历
- 队列的存储和二叉树的层序遍历
练习过程
项目目录的构建
首先创建项目文件夹,然后创建项目内的各个文件夹。下图为创建过程和文件目录树:
编写各模块
头文件
首先编写二叉树的数据结构存储和结构体定义的模块。
写一个btree.h,放在include中,此为二叉树的头文件。
btree.h:
#ifndef __BTREE_H__
#define __BTREE_H__
typedef struct BinTreeNode
{
char data;
struct BinTreeNode *Left;
struct BinTreeNode *Right;
} * BinTree; //二叉树结构定义,数据类型是字符型
BinTree CreateBinTree();
void LevelOrder(BinTree t);//层序遍历
void PreOrder(Bintree t); //先序遍历
void InOrder(Bintree t); //中序遍历
void PostOrder(Bintree t); //后序遍历
#endif
再写一个用于二叉树层序遍历的队列用的头文件
queue.h:
#ifndef __QUEUE_H__
#define __QUEUE_H__
typedef struct SeqQueue
{
int max;
int f, r;
BinTree *q;
} * Queue; //队列结构定义
Queue CreatQueue(int m);//创建队列
void AddQueue(Queue paqu, BinTree x);//将一个二叉树指针压入队列
int IsEmptyQueue(Queue paqu);//判断队列是否为空
BinTree DeleteQueue(Queue paqu);//从队尾删除并取出元素
#endif
模块
编写各个模块实现不同的功能。
模块很多,代码不一一列出。需要代码可在最后的码云链接找到。
模块列表和功能:
create_bin_tree.c
创建一个二叉树并返回
inorder.c
二叉树的中序遍历
levelorder.c
二叉树的层序遍历
postorder.c
二叉树的后序遍历
preorder.c
二叉树的先序遍历
queue.c
队列基本操作(层序遍历时使用)
gcc练习
gcc的ESc和iso
此练习使用一个简单的helloword程序。
gcc -E 生成.i文件,是编译预处理后的结果,文件内容是预处理后的C代码。
如执行完图中命令后,生成的.i文件就是包含了头文件后的C代码。
gcc -S 生成.s文件,是进行汇编后得到的汇编语言,我们知道汇编语言是和机器语言有很强对应的底层语言。
如图,就是生成的汇编程序。
gcc -c 生成.o文件,.o文件时二进制文件,是经过编译后得到的机器码,人一般无法阅读。
图为生成.o文件的gcc指令和部分.o文件内容。
库练习
生成.o文件:
使用命令gcc src/*.c -Iinclude -o lib/*.o
就可以生成对应.o并放在lib路径中(*应该替换为自己的文件名)
静态库:
将所有.o合成一个静态库,后面编译时就可以使用了,指令如下:
ar rcs lib/libbintree.a lib/*.o
注意后面跟随的.o文件可以是多个。
动态库:
动态库生成方式和静态库类似,但要求在生成.o的时候再gcc后加上-fPIC
参数,目的是保证地址不与文件相关,才可以使用动态库。
生成动态库的指令:
gcc -shared -o lib/libbintree.so *.o
练习截图就和makefile一起了。
makefile的编写
我的makefile
o=lib/create_bin_tree.o lib/inorder.o lib/preorder.o lib/postorder.o lib/levelorder.o lib/queue.o
OBJ:bin/test lib/libbintree.a lib/libbintree.so
bin/test:test/test.c lib/libbintree.a
gcc test/test.c -static -Iinclude -Llib -lbintree -o bin/test
lib/libbintree.a:$(o)
ar rcs lib/libbintree.a $(o)
lib/libbintree.so:$(o)
gcc -shared -o lib/libbintree.so $(o)
lib/create_bin_tree.o:src/create_bin_tree.c include/btree.h
gcc -c -fPIC -Iinclude src/create_bin_tree.c -o lib/create_bin_tree.o
lib/inorder.o:src/inorder.c include/btree.h
gcc -c -fPIC -Iinclude src/inorder.c -o lib/inorder.o
lib/preorder.o:src/preorder.c include/btree.h
gcc -c -fPIC -Iinclude src/preorder.c -o lib/preorder.o
lib/postorder.o:src/postorder.c include/btree.h
gcc -c -fPIC -Iinclude src/postorder.c -o lib/postorder.o
lib/levelorder.o:src/levelorder.c include/btree.h include/queue.h
gcc -c -fPIC -Iinclude src/levelorder.c -o lib/levelorder.o
lib/queue.o:src/queue.c include/btree.h include/queue.h
gcc -c -fPIC -Iinclude src/queue.c -o lib/queue.o
我对makefile的学习心得:
makefile可以设置常量,如我makefile中的.o就是案例。在有时,生成库的时候会用到很多很多的.o文件,每次都输入非常麻烦,而且每次新加入.o文件后都要全部修改,非常不简洁。可以设置一个.o变量,把所有.o文件写在后面,每次使用的时候用$(o)进行调用,这样就方便多了。这体现了编写代码的“不要重复自己”原则。
makefile原则上只以第一个文件为目标进行生成、编译,但如果需要同时生成多个文件怎么办?可以将第一个文件设置成一个类似“OBJ”的理想文件,实际上并没有这个文件,在OBJ后面再以它的依赖的形式写上每次需要生成的文件,make时就会自动生成这些文件了。
make截图
make后,所有文件都将被有序生成。
文件目录tree截图
功能测试
编写了main函数,测试所有功能。
test/test.c:
#include"btree.h"
#include"queue.h"
#include<stdio.h>
int main()
{
BinTree T;
printf("请以先序,字符型(不加空格,空用"#"表示)输入二叉树:
");
T = CreateBinTree();
printf("以先序输出二叉树结果如下:
");
PreOrder(T);
printf("
以中序输出二叉树结果如下:
");
InOrder(T);
printf("
以后序输出二叉树结果如下:
");
PostOrder(T);
printf("
以层序输出二叉树结果如下:
");
LevelOrder(T);
putchar('
');
return 0;
}
测试用二叉树:
测试结果:
gdb练习
4种断点:行断点、函数断点、条件断点、临时断点。
调试时,需要在编译gcc时加入-g参数,才能生成调试信息,进行调试。
CGDB调试界面:
设置函数断点: b 函数名
设置行断点:b 行号
设置临时断点:tb 行号
设置条件断点:break 行号 if 条件
开始运行:run
查看变量的值:disp 变量名
单步执行(进入函数):s
单步执行(不进入函数):n
跳出函数:finish
跳出循环:until
代码链接
代码已上传至码云:https://gitee.com/Ressurection20191320/code/tree/master/IS/20191320BinaryTree