1 #include<stdio.h>
2 #include<stdlib.h>//malloc
3 #include<stdbool.h>
4 #include<string.h>
5 #include<ctype.h>
6 #define SIZE 12 //姓名字符串大小为12个字符,包含空字符
7 #define SEX 6 //性别字符串大小为6个字符,包含空字符
8 typedef struct item{
9 int number;
10 char name[SIZE]; //创建一个储存姓名的成员
11 char sex[SEX]; //创建一个储存性别的成员
12 int age; //创建一个储存年龄的成员
13 struct item * next; //指向自身的结构的指针用以指向下一个item结构
14 }Item; //利用typdef定义一个Item类型,其结构为item
15 typedef struct node{
16 Item item; //创建一个Item结构的成员
17 struct node * next; //创建一个指向下一个节点的节点指针
18 }Node; //利用typdef定义一个Node类型,其结构为node
19 typedef Node * List; //定义List为一个指向Node节点的指针类型
20 void InitializeList(List * p){ //接受一个(指向Node节点的指针)的指针
21 *p=NULL; //将指向Node节点的指针设为空(*号解引用指向Node节点的指针的指针得到Node节点的指针)
22 }
23 bool IsListEmpty(List *p){ //接受一个(指向Node节点的指针)的指针
24 return *p==NULL?true:false; //如果Node节点为空返回真否则返回假
25 }
26 void CopyToNode(Item item,Node *p){ //接受一个Item结构参数和一个指向Node节点的指针
27 p->item=item; //Node节点的item成员获得传来的item信息
28 }
29 bool AddItem(Item item,List *p){ //接受一个Item结构参数和一个指(向Node节点的指针)的指针
30 Node * pnew; //声明一个指向Node节点类型的指针pnew
31 Node * scan=*p; //声明一个指向Node节点类型的指针scan,该指针获得传来的节点的指针地址
32 pnew=(Node *)malloc(sizeof(Node)); //为pnew分配空间
33 if(pnew==NULL) //如果分配失败
34 return false; //返回假
35 CopyToNode(item,pnew); //将item结构信息和已分配好空间的pnew作为参数传送以将item作为pnew节点的一部分
36 pnew->next=NULL; //将pnew的下一个节点设为空
37 if(scan==NULL) //如果传来的Node节点为空(代表尚无信息录入))
38 *p=pnew; //则该Node节点获得pnew这个已获取信息的Node节点的地址
39 else{ //如果传来的Node节点不为空
40 while(scan->next!=NULL) //当传来的Node节点的next指针指向不为空时
41 scan=scan->next; //该节点等于下一个节点
42 //循环结束得到一个节点的下一个节点为空
43 scan->next=pnew; //节点的下一个节点获得pnew这个节点的地址以形成链接
44 }
45 return true; //返回真
46 }
47 void ShowItems(Item item){ //接受一个Item结构类型
48 printf("姓名:%s 性别:%s 年龄:%d\n",item.name,item.sex,item.age); //打印该结构的成员信息
49 }
50 void whi1e(const List *pt,void (*p) (Item item)){ //接受一个(指向Node节点的指针)的指针和一个函数指针(该函数指针,接受一个Item结构参数,其返回值为空)
51 Node * look=*pt; //创建一个指向Node节点的指针,该指针获得解析的来的指向(Node结构的指针的指针)的地址,即节点的指针
52 while(look!=NULL){ //当Node节点指针不为空时
53 p(look->item); //调用传来的函数即ShowItems,将当前Node节点的item成员作为参数传送过去以打印
54 look=look->next; //节点指向下一个节点以打印下一个节点的信息
55 }
56 }
57 void DeList(List *p){ //接受一个指向(Node节点的指针)的指针以删除储存节点信息的列表
58 List * replace=p; //创建一个指向(Node节点的指针)的指针repalce来获得传来的指针p
59 while(replace!=NULL){ //如果该指向(Node节点的指针)的指针不为空
60 free(*replace); //释放该指针指向的节点空间
61 (*p)=(*p)->next; //传来的指针p指向的节点等于下一个节点
62 *replace=*p; //replace指向的节点等于p指针指向的节点
63 }
64 }
65 unsigned int ListCounter(const List *p){ //接受一个只读类型的(指向Node节点的指针)的指针
66 Node * example = *p; //创建一个指向Node节点的指针来获取传来的p指针指向的节点
67 unsigned int counter=0; //计数器置0
68 while(example!=NULL){ //当这个节点不为空
69 counter++; //计数器+1
70 example=example->next; //该节点等于下一个节点
71 }
72 return counter; //返回结果
73 }
74 bool DeNode(List *p,char *pt){ //接受一个(指向Node节点的指针)的指针p和一个字符串pt以删除指定姓名的信息
75 Node * front=NULL; //创建一个指向Node节点结构类型的指针front,初始化为空,该指针用以指向rear这个节点的上一个节点来进行删除节点后的连接工作
76 Node * rear=*p; //创建一个指向Node节点结构类型的指针rear并获得传来的节点
77 while(rear!=NULL){ //当节点不为空时进行循环
78 if(strcmp(rear->item.name,pt)==0){ //如果找到姓名相同的
79 if(front==NULL){ //如果这个节点是第一个节点时
80 *p=(*p)->next; //该指针指向的节点等于下一个节点
81 free(rear); //释放该节点
82 return true; //返回真
83 }
84 else{ //当找到的不是第一个节点时
85 front->next=rear->next; //上一个节点的next指向已找到的当前节点的下一个节点
86 free(rear); //释放当前节点
87 return true; //返回真
88 }
89 }
90 else{//没找到时
91 front=rear; //front等于当前节点
92 rear=rear->next; //rear等于当前节点的下一个节点
93 }
94 }
95 return false; //返回假
96 }
97 bool InsertNode(List *p,Item item,int pos){//接收一个(指向Node结构的指针)的指针p和要插入的信息item,与位置信息pos
98 Node *rear=*p;//创建一个指向Node节点类型的指针指向位置节点来进行链接
99 if(pos>item.number||rear==NULL)//如果要插入的位置大于结点数返回的节点为空
100 return false;//插入位置失败
101 Node *instead=(Node *)malloc(sizeof(Node));//为接收item创建一个指向Node的指针并分配空间
102 instead->item=item;//该Node节点的item接收传来的item信息
103 if(pos>0){//如果位置不在链表头
104 Node *front=NULL;//创建一个指向Node节点类型的指针指向位置节点的上一个节点来进行链接
105 for(int a=0;a<pos;a++){//循环直到pos指定位置
106 front=rear;//前结点
107 rear=rear->next;//目标位置节点
108 }
109 instead->next=rear;//该Node节点指向的下一个结点为原始列表中位置的节点
110 front->next=instead;//原始列表中位置的节点指向该Node节点
111 return true;
112 }
113 else{//如果要插入的位置在链表头
114 instead->next=rear;//将新节点的下一个节点指向链表头结点
115 *p=instead;//将头指针指向新节点
116 return true;
117 }
118 }
119 void menu(void){ //打印菜单
120 printf("a:添加信息\n");
121 printf("c:插入信息\n");
122 printf("d:删除信息\n");
123 printf("p:打印信息\n");
124 printf("q:退出并清空列表\n");
125 }
126 void main(){
127 Item item; //创建一个item结构以获取输入并作为数据传送
128 List info; //创建一个指向Node类型的指针,Node类型包含一个item结构成员和一个指向下一个节点的指针
129 char ch='y'; //初始化ch
130 char name[SIZE]; //获取要删除的姓名
131 InitializeList(&info); //将指向Node的指针的地址作为参数传送(因该函数要求接受一个指向Node的指针的指针,而info为一个指向Node节点的指针,该函数的指针通过*号解引用便获得了该指针指向的Node节点)
132 menu(); //打印菜单
133 int number=0;
134 while(ch!='q'){
135 switch (tolower(ch)) { //将字母小写
136 case 'a':{
137 printf("请输入你的姓名:");
138 scanf("%s",item.name); //获取信息以存储到item结构的成员中
139 printf("请输入你的性别:");
140 scanf("%s",item.sex); //获取信息以存储到item结构的成员中
141 printf("请输入你的年龄:");
142 scanf("%d",&item.age); //获取信息以存储到item结构的成员中
143 item.number=number;
144 number++;
145 AddItem(item,&info); //将item和指向节点的指针的地址作为参数传送以形成连接
146 menu(); //打印菜单
147 break;
148 }
149 case 'c':{
150 printf("请输入你的姓名:");
151 scanf("%s",item.name); //获取信息以存储到item结构的成员中
152 printf("请输入你的性别:");
153 scanf("%s",item.sex); //获取信息以存储到item结构的成员中
154 printf("请输入你的年龄:");
155 scanf("%d",&item.age); //获取信息以存储到item结构的成员中
156 printf("请输入要插入的位置:");
157 int pos;
158 scanf("%d",&pos);
159 printf("%s",InsertNode(&info,item,pos)?"插入成功":"插入失败");
160 menu(); //打印菜单
161 break;
162 }
163 case 'd':{
164 printf("你想删除哪个人的信息(键入此人姓名):");
165 scanf("%s",name);
166 printf("%s",DeNode(&info,name)?"删除成功\n":"删除失败\n"); //如果返回为真则删除成功,否则失败
167 menu(); //打印菜单
168 break;
169 }
170 case 'p':{
171 printf("共有%d条信息\n",ListCounter(&info)); //将指向节点的指针的地址作为参数传送,该函数接受一个(指向Node节点的指针)的指针,该指针指向节点的指针的地址,通过*号解引用获得对应的节点信息
172 whi1e(&info,ShowItems); //将指向节点的指针的地址作为参数传送,同时将一个函数作为参数传送
173 menu(); //打印菜单
174 break;
175 }
176 }
177 setbuf(stdin,NULL); //将标准输入的文件指针指向的缓冲区设为空
178 ch=getchar();
179 setbuf(stdin,NULL); //将标准输入的文件指针指向的缓冲区设为空
180 }
181 DeList(&info); //删除列表
182 printf("再见!\n");
183 }