综述
电话号码管理项目功能包括简易菜单、单链表、包括增删改查等基本操作。链表插入采用尾插法。
链表结构
每个节点中内容:
- id id号码
- name 姓名
- phone_number 电话号码
- home_address 家庭地址
- company_address 公司地址
init
int init(PHONE **head) { PHONE *newnode = (PHONE *)malloc(sizeof(PHONE)); if(NULL == newnode) { return -1; } //newnode->value = 0; newnode->next = NULL; *head = newnode; return 0; }
这段代码是一个函数,名称为 init,它接收一个指向 PHONE 指针的指针,用于指向一个链表的头节点。
这个函数首先使用 malloc 分配一个新的 PHONE 节点,如果分配失败,则返回 -1。
接着,这个函数初始化新节点的值为 0,将 next 指针设置为 NULL。
最后,将链表头节点指针指向新节点,即将 *head 设置为 newnode。
这个函数返回 0 表示初始化成功。
create
int create(PHONE *head) { PHONE *p; p = head; PHONE *newstudent = (PHONE *)malloc(sizeof(PHONE)); if(NULL == newstudent) { return -1; } 。。。。 newstudent->next = NULL; while(head->next != NULL) { head = head->next; } head->next = newstudent; 。。。。 head = p; }
这段代码是一个函数,名称为 create,它接收一个指向链表头节点的 PHONE 指针。
这个函数首先将指针 p 指向链表头节点 head,以便在后面将链表头节点指针传递回来。
然后,使用 malloc 分配一个新的 PHONE 节点 newstudent,如果分配失败,则返回 -1。
接着,初始化新节点的值,并将 next 指针设置为 NULL。
接下来的代码是在链表的尾部插入新节点,它使用一个循环将指针 head 移动到链表的末尾,即指向最后一个节点。
最后,将新节点插入链表的末尾,即将 head 指向的节点的 next 指针指向新节点。
最后,将指针 head 指向链表头节点,以便将链表头节点指针传递回来。
注意,该函数返回类型为 int,但是没有返回值。如果在分配新节点时发生错误,则返回 -1,否则函数将正常返回。
delete
int delete(PHONE *head) { PHONE *p; p = head; char name[20]; 。。。。。。 while(head->next != NULL) { if(strcmp(head->next->name,name) == 0) { count++; PHONE *ptr = head->next; head->next = ptr->next; free(ptr); } 。。。。。 head = p; printf("\n"); return 0; }
这段代码中的循环用于遍历链表,查找匹配输入的姓名的节点。
具体地,使用条件判断语句 while 和表达式 head->next != NULL 循环遍历链表,当 head 指向的节点不为 NULL 时,执行循环体内的代码。
循环体内部的条件判断语句 if 判断链表中下一个节点的姓名是否与输入的 name 相等,如果相等,则执行删除操作。
删除操作首先将指针 ptr 指向需要删除的节点,然后将链表中该节点的前一个节点的 next 指针指向该节点的后一个节点,即删除该节点。
最后,释放节点内存,将 head 指针指向下一个节点,继续循环遍历链表,直到遍历完整个链表。
在循环结束后,将指针 head 指向链表头节点,以便将链表头节点指针传递回来。
函数返回 0 表示删除成功。注意,该函数删除的是第一个匹配的节点,如果有多个节点匹配,则只删除第一个匹配的节点。如果链表中没有匹配的节点,则函数将正常返回。
allfree
PHONE *allfree(PHONE *head) { while(head->next != NULL) { PHONE *ptr = head; head = head->next; free(ptr); } free(head); head = NULL; return head; }
这段代码用于释放链表中所有节点占用的内存,同时将链表头节点指针置为 NULL。
具体地,使用条件判断语句 while 和表达式 head->next != NULL 循环遍历链表,当 head 指向的节点不为 NULL 时,执行循环体内的代码。
循环体内部的操作首先将指针 ptr 指向当前节点,然后将 head 指针指向下一个节点,最后释放节点内存。
在循环结束后,需要释放链表头节点占用的内存,然后将链表头节点指针置为 NULL。
最后,函数返回 NULL 指针,以便将链表头节点指针传递回来。
需要注意的是,该函数在释放内存时,必须保证链表中至少有一个节点。如果链表为空,或者链表中只有一个节点,需要特殊处理。如果链表中只有一个节点,释放内存后,需要将链表头节点指针置为 NULL,否则会出现野指针的问题。
ANSI颜色转义
printf("\033[1;33m Hello World. \033[0m \n");
颜色列表如下:
none = "\033[0m" black = "\033[0;30m" dark_gray = "\033[1;30m" blue = "\033[0;34m" light_blue = "\033[1;34m" green = "\033[0;32m" light_green -= "\033[1;32m" cyan = "\033[0;36m" light_cyan = "\033[1;36m" red = "\033[0;31m" light_red = "\033[1;31m" purple = "\033[0;35m" light_purple = "\033[1;35m" brown = "\033[0;33m" yellow = "\033[1;33m" light_gray = "\033[0;37m" white = "\033[1;37m"
字背景颜色范围:40–49 字颜色: 30–39
40: 黑 30: 黑 41:红 31: 红 42:绿 32: 绿 43:黄 33: 黄 44:蓝 34: 蓝 45:紫 35: 紫 46:深绿 36: 深绿 47:白色 37: 白色
输出特效格式控制:
\033[0m 关闭所有属性 \033[1m 设置高亮度 \03[4m 下划线 \033[5m 闪烁 \033[7m 反显 \033[8m 消隐 \033[30m -- \033[37m 设置前景色 \033[40m -- \033[47m 设置背景色
光标位置等的格式控制:
\033[nA 光标上移n行 \03[nB 光标下移n行 \033[nC 光标右移n行 \033[nD 光标左移n行 \033[y;xH设置光标位置 \033[2J 清屏 \033[K 清除从光标到行尾的内容 \033[s 保存光标位置 \033[u 恢复光标位置 \033[?25l 隐藏光标 \33[?25h 显示光标
Makefile
顶层Makefile
include scripts/Makefile #包含 scripts/Makefile 文件。它可能包含其他变量、目标和规则,以及其他可能需要在此Makefile中使用的脚本和功能。 modules_make = $(MAKE) -C $(1); modules_clean = $(MAKE) clean -C $(1); #这些是两个变量,用于执行每个模块的make命令和clean命令。这些变量可以通过参数传递需要操作的模块的名称。 .PHONY: all mm mc clean #这是一个特殊目标,告诉Make,这些目标不是文件名,而是伪目标。它告诉Make无论如何都要执行它们。 all: $(Target) #这是一个目标,告诉Make要构建$(Target)。它将在mm目标后执行。 mm: @ $(foreach n,$(Modules),$(call modules_make,$(n))) #这是一个目标,用于执行每个模块的make命令。它使用foreach循环来迭代所有的模块名称,并通过modules_make变量调用make命令。 mc: @ $(foreach n,$(Modules),$(call modules_clean,$(n))) #这是一个目标,用于执行每个模块的clean命令。它使用foreach循环来迭代所有的模块名称,并通过modules_clean变量调用clean命令。 $(Target) : mm $(CC) $(CFLAGS) -o $(Target) $(AllObjs) $(Libs) @ echo $(Target) make done! #这是一个目标,告诉Make要构建$(Target)。它在mm目标完成后执行。它使用$(CC)编译器,$(CFLAGS)编译选项和$(Libs)链接库来编译所有的目标文件,并将它们链接成可执行文件。 clean : mc rm -rf $(Target) @ echo clean done! #这是一个目标,告诉Make清理项目。它在mc目标完成后执行。它使用rm命令来删除$(Target)和其他生成的文件。 #这些是命令,用于输出构建和清理操作完成的消息。前面的@符号告诉Make不要输出命令本身,只输出命令的结果。
scripts Makefile
CC := gcc CFLAGS := -Wall -O3 Libs = -lpthread Target := phone Source := $(wildcard ./*.c) Objs := $(patsubst %.c,%.o,$(Source)) Modules += allfree create delete display init login menu search main AllObjs := $(addsuffix /*.o,$(Modules))
Makefile 文件中包含了一些特殊的变量和命令,可以指导 Make 工具根据代码的依赖关系自动化构建程序。
在这段代码中,首先定义了一些变量:
- CC:C 编译器名称;
- CFLAGS:编译器选项,包括 -Wall 和 -O3;
- Libs:需要链接的库文件,这里是线程库;
- Target:目标程序名,这里是 phone;
- Source:所有源文件的路径和名称;
- Objs:所有对象文件的路径和名称,通过把源文件的扩展名 .c 替换为 .o 得到;
- Modules:项目中所有模块的名称,这里是 allfree、create、delete、display、init、login、menu、search 和 main;
- AllObjs:所有模块的对象文件路径和名称,通过在模块名后加上 /* 和 .o 得到。
接下来是一些命令,以及命令的依赖关系和规则:
- .PHONY:声明了一个伪目标,表示这些目标不是实际存在的文件,只是用来作为 make * 的执行目标;
- all:构建目标程序 phone,依赖于所有对象文件 $(Objs) 和链接库 $(Libs);
- $(Target):生成目标程序 phone,依赖于所有对象文件 $(Objs) 和链接库 $(Libs);
- $(Objs):编译所有源文件 $(Source),每个源文件对应一个对象文件;
- $(Modules):每个模块都要编译成一个对象文件,依赖于对应的源文件;
- clean:删除所有对象文件 $(Objs) 和目标程序 $(Target)。
通过执行 make 命令,根据 Makefile 文件中的定义,自动编译源代码,并生成目标程序。
search main init include display delete create allfree 目录下Makefile
include ../scripts/Makefile all : $(Objs) clean : rm -rf $(Objs)
这是一个简单的 Makefile,它包含另一个 Makefile,该 Makefile 位于 scripts 目录中(假定为父目录级别),并定义了两个目标,all 和 clean。
all 目标依赖于目标文件($(Objs)),并仅构建它们。实际的构建命令没有在此 Makefile 片段中显示,但应该在包含的 Makefile(…/scripts/Makefile)中定义。
clean 目标删除目标文件
result