今天来diy一个通讯录,功能需求是从网上找的,然后这些功能恰好需要用到结构体、指针、链表这些功能,恰好可以练练手。
通讯录可以用来存储1000个人的信息,每个人的信息包括:
姓名、性别、年龄、电话、住址
实现功能:
- 添加联系人信息
- 删除指定联系人信息
- 修改指定联系人信息
- 查找指定联系人信息
- 显示所有联系人信息
- 清空所有联系人
- 以名字排序所有联系人
今天只实现了1和5的功能,其他的明天继续,贴代码:
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#define MAX 100
/*建立结构体链表,固定结构,背下来*/
typedef struct people
{
char name[MAX];
char sex[MAX];
int age;
long long int tel;
char addr[MAX];
struct people *pNext;
}Node, *pNode; /*Node为结构体变量,pNode为结构体指针变量,也可以只写Node,在定义指针的时候写成(Node *p)*/
/*定义全局变量,记录最后录入的联系人的节点数*/
int num = 0;
int main(void)
{
int flag;
char ch;
pNode pHead = NULL; /*首次定义头指针需要置零*/
pNode CreatList(void);
pNode reCreatList(pNode);
void TraverseList(pNode);
while (1)
{
printf("请输入要进行的操作:\n");
printf("1.添加联系人信息\n2.删除指定联系人信息\n3.修改指定联系人信息\n4.查找指定联系人信息\n5.显示所有联系人信息\n6.清空所有联系人\n7.以名字排序所有联系人\n");
scanf_s("%d", &flag);
while (getchar() != '\n')
{
ch = getchar();
}
switch (flag)
{
case 1:
{
/*首次录入联系人*/
if (pHead == NULL)
{
pHead = CreatList();
}
/*重复录入联系人*/
else
{
pHead = reCreatList(pHead);
}
printf("\n");
break;
}
case 2:
{
printf("2\n");
break;
}
case 3:
{
printf("3\n");
break;
}
case 4:
{
printf("4\n");
break;
}
case 5:
{
TraverseList(pHead);
printf("\n");
break;
}
case 6:
{
printf("6\n");
break;
}
case 7:
{
printf("7\n");
break;
}
}
}
return 0;
}
/*首次录入联系人,建立一个新的链表*/
pNode CreatList(void)
{
/*定义头节点、尾节点、新节点*/
pNode pHead, pTail, pNew;
pHead = (pNode)malloc(sizeof(Node)); /*为头指针开辟一块内存*/
pTail = pHead; /*空链表的头节点就是尾节点*/
pTail->pNext = NULL; /*尾节点指向空值*/
/*输入数据给新节点*/
pNew = (pNode)malloc(sizeof(Node)); /*为新节点开辟内存*/
printf("请输入联系人姓名:");
scanf_s("%s", &pNew->name, MAX);
printf("请输入联系人性别:");
scanf_s("%s", &pNew->sex, MAX);
printf("请输入联系人年龄:");
scanf_s("%d", &pNew->age);
printf("请输入联系人电话:");
scanf_s("%lld", &pNew->tel);
printf("请输入联系人地址:");
scanf_s("%s", &pNew->addr, MAX);
/*新节点接入链表*/
pTail->pNext = pNew; /*令原来的尾节点指向新节点*/
pNew->pNext = NULL; /*新节点指向空值*/
pTail = pNew; /*新节点成为新的尾节点,原来的尾节点成为中间节点*/
/*录入联系人+1*/
num++;
return pHead;
}
/*重复录入联系人,将新的联系人接到原有的链表中*/
pNode reCreatList(pNode p)
{
/*定义新链表的头节点、尾节点、新节点*/
pNode pHead, pTail, pNew;
pHead = p; /*将原有的链表赋给pHead*/
/*寻找原有链表的最后一个节点*/
pNode pVal = NULL; /*定义一个pVal来临时保存最后一个节点的数据*/
while (p != NULL)
{
pVal = p; /*pVal始终为p的前一个节点,当遍历结束时,p为空,pVal即为最后一个节点*/
p = p->pNext;
}
pTail = pVal; /*令pTail成为链表最后一个节点*/
pTail->pNext = NULL; /*尾节点指向空值*/
/*输入数据给新节点*/
pNew = (pNode)malloc(sizeof(Node));
printf("请输入联系人姓名:");
scanf_s("%s", &pNew->name, MAX);
printf("请输入联系人性别:");
scanf_s("%s", &pNew->sex, MAX);
printf("请输入联系人年龄:");
scanf_s("%d", &pNew->age);
printf("请输入联系人电话:");
scanf_s("%lld", &pNew->tel);
printf("请输入联系人地址:");
scanf_s("%s", &pNew->addr, MAX);
/*新节点接入链表*/
pTail->pNext = pNew; /*令原来的尾节点指向新节点*/
pNew->pNext = NULL; /*新节点指向空值*/
pTail = pNew; /*新节点成为新的尾节点,原来的尾节点成为中间节点*/
/*录入联系人+1*/
num++;
return pHead;
}
/*遍历输出所有联系人*/
void TraverseList(pNode pHead)
{
/*定义临时节点*/
pNode p;
p = pHead->pNext; /*把pHead->pNext而不是pHead赋给p,是因为pHead的数据域本身没有意义,因此只需要赋值pHead->pNext,即将第一个节点的数据域和指针域赋给p*/
/*执行遍历*/
while (p != NULL)
{
printf("%s ", p->name);
printf("%s ", p->sex);
printf("%d ", p->age);
printf("%lld ", p->tel);
printf("%s\n", p->addr);
p = p->pNext;
}
return 0;
}
刚刚也说了,这部分内容主要训练链表方面的知识,但又与其他的链表建立不太一样,因为通讯录的录入联系人并不是一次性把多有的联系人都录入,中间会有间断,因此通讯录的链表不是一次建成的,而是需要后续数据不断接到原有链表之上。这就在后续录入的时候,需要知道之前录入过多少次,以便统计总人数,不超过1000。因此这边是定义了一个全局变量num,在每次子函数对成员操作的时候都会有num的加加减减。
收获:
- 链表到底是个什么样的结构,链表该怎么建立,主要步骤都在代码的注释中有所体现;
- p = pHead表示把头指针赋值给p,p = pHead->pNext表示把头指针之后的链表第一个节点赋值给p,详见代码132和173行。
今天就到这儿了,明天不一定有时间继续看这个,Socket那个程序还需要继续完善,从最初网上下的100多行写到300,再到500,再到现在的700,估计这次完善之后有可能破千了,或许真应该庆幸自己对这个比较感兴趣,或者终于在学习这条路上找到了自己感兴趣的点了。