基于Linux中的通讯录管理系统(C语言+双向循环链表+MySQL)

这个通讯录管理系统是我5月份对于C语言和数据结构复习做的一个小项目和总结,后来这几天对数据库起了兴趣自己又重新补上了数据库(MySQL)的部分,让通讯录管理系统真正地可以存储数据。

基于自己还是大学生的关系,代码的逻辑方面和实现方面可能有所出错,如果有哪里不对的地方请大家在评论写上,我会一一回复。

系统功能实现

  1. 通讯录联系人信息有:姓名(中文)、公司、职位、电话号码、备注
  2. 可对通讯录联系人实现增、删、查、改操作
  3. 支持中文联系人输入
  4. 可实现电话号码与姓名查找联系人
  5. 通过姓名拼音进行排序
  6. 有快速浏览联系人的功能
  7. 增加、删除、修改联系人的时候,会将数据放到数据库中存储,下次重新打开程序时,会将数据库表中的数据重新加载到链表上

相关软件前提

  1. 编程语言:C语言,并使用Ubuntu中的gcc编译器进行编译和链接
  2. 操作系统:Ubuntu18.04版本
  3. Ubuntu下要安装MySQL数据库,详细安装步骤可以查看我写的另一篇文章: Ubuntu18.04安装Mysql8.0的详细步骤.
  4. 注意要提前安装好Linux下的一个库:在这里插入图片描述
    安装这个库之后,/usr/include文件夹内才有mysql文件夹,里面带了mysql.h这个含有MySQL官方的C语言API接口函数的头文件。我们要使用这个头文件调用里面的接口从而访问到MySQL数据库。

部分重要的功能代码

详细的代码可以参考下面的附录,也可以直接在下面的链接进行下载。
这里只是挑比较重要的代码进行部分讲解。

Makefile

使用了Makefile来实现自动化编译。

-I选项是指定了mysql.h头文件所在的位置
mysql.h是MySQL官方提供的一些C语言函数的库,没有这个头文件我们无法将自己的程序与MySQL连接起来。

-L是指定库的所在目录,我们要用到MySQL的库,也就是它的某个dll文件

test:main.o list.o keyboard.o menu.o
	gcc -o test $^ -I/usr/include/mysql  -L/usr/lib/mysql -lmysqlclient

%.o:%.c
	gcc -c -o $@ $< -I/usr/include/mysql  -L/usr/lib/mysql -lmysqlclient



.PHONY:
clean:
	rm -r *.o *.c *.h

menu.c

menu.c上面只有一个menu函数,用来输出总菜单提示用户通过键盘输入菜单值,从而到达不同的菜单里面。
menu.h:

#ifndef __MENU_H__
#define __MENU_H__

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

//菜单
int menu(void);

#endif

menu.c:

#include "menu.h"


int menu(void)
{
	int menu = 0;//菜单值

	printf("------欢迎来到通讯录系统------\n");
	printf("------1.增加联系人------\n");
	printf("------2.删除联系人------\n");
	printf("------3.查询联系人------\n");
	printf("------4.修改联系人------\n");
	printf("------5.快速浏览联系人------\n");
	printf("------6.退出通讯录------\n");
	printf("请输入菜单值:");
	scanf("%d",&menu);
	return menu;
} 

MySQL API函数使用

C语言连接MySQL:

  1. mysql_init函数:用来初始化一个MySQL连接的实例对象

    MYSQL *sql;//创造一个MySQL句柄
    	
    	sql = mysql_init(NULL);//初始化一个MySQL连接的实例对象
    	if(sql == NULL)//如果内存不足返回一个NULL
    	{
    		printf("初始化MySQL数据库连接失败!\r\n");
    		return -1;
    	}
    
  2. 使用mysql_real_connect函数与MySQL的某个数据库进行连接:
    注意:连接之前你要在MySQL的中创建好你要连接的库,否则有可能会连接失败。建库的命令请上网自行搜索(我也是百度来的)。
    在这里插入图片描述

    	/*用MySQL句柄与MySQL数据库发生连接*/
    	/*MySQL句柄 IP地址 用户名 用户名密码 要连接的数据库 端口 套接字 flag选项*/
    	sql = mysql_real_connect(sql,"localhost","root","123456","address_list",0,NULL,0);
    	if(sql == NULL)//连接失败返回NULL
    	{
    		printf("连接MySQL数据库失败!失败原因:%s\r\n",mysql_error(sql));
    		return -1;
    	}
    	else//连接成功
    	{
    		printf("连接MySQL数据库成功!\r\n");
    	}
    
    //..........
    
  3. 在主函数最后记得用mysql_close()函数来释放句柄

    mysql_close(sql);//释放一个MySQL句柄
    

调用SQL命令

调用sql命令实际上使用了mysql_query函数:

int mysql_query(MYSQL* mysql,const char* query)

query是SQL命令的字符串,我是用sprintf格式化了字符串SQL语句。
如果调用成功,返回0,如果出现错误,返回非0值。

  1. 插入数据到数据库

    /*插入数据到数据库*/
    void insert_into_mysql(MYSQL *sql,char *name,char *company,char *work,char *remarks,unsigned long phonenumber)
    {
    	char qs[1000];//用来存放mysql命令
    
    	sprintf(qs,"insert into test values('%s','%s','%s','%s','%ld')",name,company,work,remarks,phonenumber);
    	if(mysql_query(sql,qs)!=0)//返回值不等于0,操作失败
    	{
    		printf("增加失败!\r\n");
    		exit(1);//直接退出进程
    	}
    	else
    	{
    		printf("插入数据到数据库成功!\r\n");
    	}
    }
    
  2. 根据姓名删除数据库表中某一行

    /*根据姓名删除MySQL数据库数据*/
    void delete_name_mysql(MYSQL *sql,char *name)
    {
    	char qs[100];//存放MySQL命令
    
    	sprintf(qs,"delete from test where 姓名='%s'",name);
    	if(mysql_query(sql,qs) != 0)
    	{
    		printf("根据姓名删除MySQL数据时失败!\r\n");
    		exit(1);//退出异常进程
    	}
    	else
    	{
    		printf("根据姓名删除MySQL数据时成功!\r\n");
    	}
    }
    
  3. 根据电话号码删除数据表中某一行

    /*根据电话号码删除MySQL表中数据*/
    void delete_phonenumber_mysql(MYSQL *sql,unsigned long phonenumber)
    {
    	char qs[100];//存储MySQL命令
    
    	sprintf(qs,"delete from test where 电话号码='%ld'",phonenumber);
    	if(mysql_query(sql,qs) != 0)
    	{
    		printf("根据电话号码删除MySQL数据时失败!\r\n");
    	}
    	else
    	{
    		printf("根据电话号码删除MySQL数据时成功!\r\n");
    	}
    }
    
  4. 修改数据库表中姓名为xx的某一行

    /*根据姓名更新MySQL数据表*/
    void update_name_mysql(MYSQL *sql,char *name,char *company,char *work,char *remarks,unsigned long phonenumber)
    {
    	char qs[1000];//存储的sql语句
    
    	sprintf(qs,"update test set 公司='%s',职位='%s',备注='%s',电话号码='%ld' where 姓名='%s'",company,work,remarks,phonenumber,name);
    
    	if(mysql_query(sql,qs) != 0)
    	{
    		printf("根据姓名更改MySQL信息失败!\r\n");
    		exit(1);
    	}
    	else
    	{
    		printf("根据姓名更改MySQL信息成功!\r\n");
    	}
    }
    
  5. 修改数据库表中电话号码为xx的某一行

    /*根据电话号码修改MySQL数据表*/
    void update_phonenumber_mysql(MYSQL *sql,char *name,char *company,char *work,char *remarks,unsigned long phonenumber)
    {
    	char qs[1000];//存储的sql语句
    
    	sprintf(qs,"update test set 姓名='%s',公司='%s',职位='%s',备注='%s' where 电话号码='%ld'",name,company,work,remarks,phonenumber);
    
    	if(mysql_query(sql,qs) != 0)
    	{
    		printf("根据电话号码更改MySQL信息失败!\r\n");
    		exit(1);
    	}
    	else
    	{
    		printf("根据电话号码更改MySQL信息成功!\r\n");
    	}
    }
    
  6. 清空数据库表中所有数据

    /*清空MySQL数据表中的所有数据*/
    void delete_all_mysql(MYSQL *sql)
    {
    	char qs[100];//存储MySQL命令
    
    	sprintf(qs,"TRUNCATE TABLE test");
    	if(mysql_query(sql,qs)!= 0)
    	{
    		printf("删除MySQL表中所有数据失败!\r\n");
    		exit(1);
    	}
    	else
    	{
    		printf("删除MySQL表中所有数据成功!\r\n");
    	}
    }
    
  7. 查询数据表

    我程序并没有调用这个函数,但功能是可以实现的

    /*查询数据表*/
    void select_mysql(MYSQL *sql)
    {
    	char qs[100];//用来存放mysql命令
    	MYSQL_RES *result;//用于存放查询的全部结果
    	MYSQL_ROW row;//用来保存一行中的结果
    
    	/*以名字拼字升序查询数据库表test*/
    	sprintf(qs,"select * from test order by CONVERT(姓名 USING GBK) asc");
    	if(mysql_query(sql,qs)!= 0)//出现错误,返回非0值
    	{
    		printf("查询数据表失败!\r\n");
    		exit(1);//异常退出
    	}
    	else
    	{
    		if((result = mysql_store_result(sql)) == NULL)//出现错误返回NULL
    		{
    			printf("保存结果集失败!\r\n");
    			exit(1);
    		}
    		else
    		{
    			printf("\n名字\t公司\t职位\t备注\t电话号码\r\n");
    			while ((row = mysql_fetch_row(result)) != NULL)
    		 	{
    		 		printf("%s\t%s\t%s\t%s\t%s\r\n",row[0],row[1],row[2],row[3],row[4]);
    		 	}
    		 	printf("\r\n");
    		}
    	}
    	memset(qs,'\0',100);//清空qs字符串
    	mysql_free_result(result);//释放查询的所有结果
    }
    
  8. 读取数据表中数据并将每一行的数据放入链表节点里面
    这个函数是在程序运行一开始时使用,来读取MySQL数据库中test表的数据,并将每一行数据放入链表内。

    /*将读取到的内容放入链表的函数*/
    void list_add_for_read_mysql(node_pt head,char *name,char *company,char *work,char *marks,char *phonenumber)
    {
    	unsigned long phone_number;
    	
    	/*初始化节点*/
    	node_pt new_node = malloc(sizeof(node_st));
    	if(new_node == NULL)
    	{
    		printf("error!读取MySQL数据时新节点初始化失败!\n");
    		free(new_node);
    		return ;
    	}
    
    	node_pt pos = head;
    
    	/*将读取到的名字、公司、职位、备注、电话号码等信息赋给新节点*/
    	strcpy(new_node->name,name);
    	strcpy(new_node->company,company);
    	strcpy(new_node->work,work);
    	strcpy(new_node->remarks,marks);
    	phone_number = atol(phonenumber);//将字符串转换为长整型
    	new_node->phone_number = phone_number;
    			
    	new_node->next = pos->next;
    	new_node->prev = pos->next->prev;
    
    	pos->next->prev = new_node;
    	pos->next = new_node;
    }
    
    /*从MySQL读取数据到链表*/
    void read_for_mysql(MYSQL *sql,node_pt head)
    {
    	int i = 0;
    	char qs[100];//用来存放mysql命令
    	MYSQL_RES *result;//用于存放查询的全部结果
    	MYSQL_ROW row;//用来保存一行中的结果
    
    	/*以名字拼字升序查询数据库表test*/
    	sprintf(qs,"select * from test order by CONVERT(姓名 USING GBK) asc");
    	if(mysql_query(sql,qs)!= 0)//出现错误,返回非0值
    	{
    		printf("查询数据表失败!\r\n");
    		exit(1);//异常退出
    	}
    	else
    	{
    		if((result = mysql_store_result(sql)) == NULL)//出现错误返回NULL
    		{
    			printf("保存结果集失败!\r\n");
    			exit(1);
    		}
    		else
    		{
    			while ((row = mysql_fetch_row(result)) != NULL)
    		 	{
    		 		//调用这个函数将表中的每一行数据放进链表
    				list_add_for_read_mysql(head,row[0],row[1],row[2],row[3],row[4]);
    		 		i++;
    		 	}
    		 	printf("\r\n");
    		}
    	}
    	printf("读出数据库内一共有%d位联系人!\r\n",i);
    	memset(qs,'\0',100);//清空qs字符串
    	mysql_free_result(result);//释放查询的所有结果
    }
    

调用MySQL接口函数实际上非常简单,参考着上面的程序基本没有什么问题。

双向循环列表功能

初始化头节点:

/*初始化头节点*/
node_pt list_init(void)
{
	node_pt new_list = malloc(sizeof(node_st));//分配空间
	if(new_list == NULL)
	{
		printf("error!头节点初始化失败!\n");
		free(new_list);
		return NULL;
	}	
	else
	{
		new_list->next = new_list;
		new_list->prev = new_list;
		//printf("头节点初始化成功!\n");	
	}
	return new_list;
}

判断节点个数:

/*判断结点个数*/
int list_sum(node_pt head)
{
	int i = 0;
	node_pt pos = head->next;
	while(pos!=head)
	{
		i++;
		pos = pos->next;
	}
	return i;
}

头插法插入数据到节点:同时也插入数据到数据库

/*头插*/
int list_add_head(MYSQL *sql,node_pt head)
{
	int flag;

	node_pt new_node = malloc(sizeof(node_st));
	if(new_node == NULL)
	{
		printf("error!新节点初始化失败!\n");
		free(new_node);
		return -1;
	}

	node_pt pos = head;
	flag = get_string(head,new_node->name,new_node->company,new_node->work,new_node->remarks);//获取字符串类型的数据
	if(flag == -1)
	{
		printf("插入数据失败!\r\n");
		return -1;
	}
	new_node->phone_number = get_phonenum();//获取电话号码

	new_node->next = pos->next;
	new_node->prev = pos->next->prev;

	pos->next->prev = new_node;
	pos->next = new_node;

	/*插入刚刚的节点数据到MySQL*/
	insert_into_mysql(sql,new_node->name,new_node->company,new_node->work,new_node->remarks,new_node->phone_number);
	return 0;
}

显示所有节点:

/*遍历*/
void list_show(node_pt head)
{
	node_pt pos = head->next;
	int i;
	for(i = 1; pos!= head; pos = pos->next,i++)
	{
		printf("%d:姓名:%s\t公司:%s\t职位:%s\t备注:%s\t电话号码:%ld\n",i,pos->name,pos->company,pos->work,pos->remarks,pos->phone_number);
	}
}

按姓名查找节点数据:

/*按姓名查找*/
void list_search_for_name(node_pt head)
{
	node_pt pos = head->next;
	int i = 1;
	char flag = 0;
	char name[100];
	printf("请输入你要查找的姓名:");
	scanf("%s",name);
	while(pos != head)
	{
		if(strcmp(name,pos->name) == 0)
		{
			printf("%d:姓名:%s\t公司:%s\t职位:%s\t备注:%s\t电话号码:%ld\n",i,pos->name,pos->company,pos->work,pos->remarks,pos->phone_number);
			i++;
			flag = 1;
			pos = pos->next;
			continue;
		}
		pos = pos->next;
		i++;
	}
	if(flag == 0)
	{
		printf("找不到是该姓名的联系人!\n");
	}
}

按电话号码查找数据:

/*按电话号码查找*/
void list_search_for_phonenumber(node_pt head)
{
	node_pt pos = head->next;
	unsigned long phone_number;
	int i = 1;
	char flag = 0;
	printf("请输入你要查找的电话号码:");
	scanf("%ld",&phone_number);
	while(pos != head)
	{
		if(pos->phone_number == phone_number)
		{
			printf("%d:姓名:%s\t公司:%s\t职位:%s\t备注:%s\t电话号码:%ld\n",i,pos->name,pos->company,pos->work,pos->remarks,pos->phone_number);
			i++;
			flag = 1;
			pos = pos->next;
			continue;
		}
		pos = pos->next;
		i++;
	}
	if(flag == 0)
	{
		printf("找不到是该电话号码的联系人!\n");
	}
}

按姓名删除节点数据:同时MySQL数据库根据姓名删除数据库表中某一行

/*按姓名删除*/
void list_delete_for_name(MYSQL *sql,node_pt head)
{
	node_pt pos;
	char name[100];//存储输入的名字
	char flag;
	int i = 1;

	printf("输入你要删除的姓名:");
	scanf("%s",name);

	/*从头结点的下一个结点开始找是否有同名的*/	
	for(pos = head->next; pos != head; pos = pos->next,i++)
	{
		if(strcmp(name,pos->name) == 0)//如果找到同名的,立即退出循环
		{
			break;
		}
		if(i > list_sum(head))//如果找的次数比节点个数多
		{
			printf("根据姓名删除节点寻找同名节点时发生错误!\n");
			return ;
		}
	}

	if(pos == head)//如果没有找到同名的节点数据
	{
		printf("没有找到该姓名的联系人!\n");
		return ;
	}

	/*如果找到*/	
	printf("%d:姓名:%s\t公司:%s\t职位:%s\t备注:%s\t电话号码:%ld\n",i,pos->name,pos->company,pos->work,pos->remarks,pos->phone_number);
	printf("已找到该姓名%s,该节点位与%d位,是否删除(y/n):",pos->name,i);
	flag = getchar();
	scanf("%c",&flag);
	if(flag == 'y')//y删除
	{
		if(i == 1)//删除第一个
		{
			head->next=pos->next;
			pos->next->prev=head;
			printf("删除姓名为%s的联系人成功!\n",pos->name);
			delete_name_mysql(sql,pos->name);
			free(pos);
		}
		else//删除除了第一个之外的其它
		{
			pos->prev->next = pos->next;
			pos->next->prev = pos->prev;
			printf("删除姓名为%s的联系人成功!\n",pos->name);
			delete_name_mysql(sql,pos->name);
			free(pos);
		}
	}
	else if(flag == 'n')//n不删除
	{
		return ;
	}
}

按电话号码删除节点数据:同时MySQL也根据电话号码删除数据表中某一行

/*按电话号码删除*/
void list_delete_for_phonenumber(MYSQL *sql,node_pt head)
{
	node_pt pos;
	unsigned long phone_number;//存储输入的电话号码
	char flag;
	int i = 1;//节点下标

	printf("输入你要删除的电话号码的联系人:");
	scanf("%ld",&phone_number);

	/*从头节点的下一个节点进行寻找*/
	for(pos = head->next; pos != head; pos = pos->next,i++)
	{
		if(pos->phone_number == phone_number)//找到同电话号码的,退出循环
		{
			break;
		}
		if(i > list_sum(head))//如果找的次数比节点个数多
		{
			printf("根据电话号码删除节点寻找同电话号码节点时发生错误!\n");
			return ;
		}
	}

	if(pos == head)//如果找不到同电话号码的联系人
	{
		printf("没有找到该电话号码的联系人!\n");
		return ;
	}

	printf("%d:姓名:%s\t公司:%s\t职位:%s\t备注:%s\t电话号码:%ld\n",i,pos->name,pos->company,pos->work,pos->remarks,pos->phone_number);
	printf("已找到该电话号码%ld,该节点位与%d位,是否删除(y/n):",pos->phone_number,i);
	flag = getchar();
	scanf("%c",&flag);
	if(flag == 'y')//删除
	{
		if(i == 1)//删除第一个
		{
			head->next=pos->next;
			pos->next->prev=head;
			printf("删除电话号码为%ld联系人成功!\n",pos->phone_number);
			delete_phonenumber_mysql(sql,pos->phone_number);
			free(pos);
			
		}
		else//删除其它
		{
			pos->prev->next = pos->next;
			pos->next->prev = pos->prev;
			printf("删除电话号码为%ld联系人成功!\n",pos->phone_number);
			delete_phonenumber_mysql(sql,pos->phone_number);
			free(pos);
		}
	}
	else if(flag == 'n')
	{
		return ;
	}
}

修改链表中姓名为xx的某个节点的数据:同时也修改数据库表中姓名为xx的某一行:

/*按姓名修改*/
void list_motify_name(MYSQL *sql,node_pt head)
{
	int i = 1;
	char flag;//存放y or n
	char name[100];//存放输入的姓名
	char company[100];
	char work[100];
	char remarks[200];
	unsigned long phonenumber;
	node_pt pos;
	

	printf("输入你要修改的姓名:");
	scanf("%s",name);

	/*从头结点的下一个结点开始找是否有同名的*/	
	for(pos = head->next; pos != head; pos = pos->next,i++)
	{
		if(strcmp(name,pos->name) == 0)//如果找到同名的,立即退出循环
		{
			break;
		}
		if(i > list_sum(head))//如果找的次数比节点个数多
		{
			printf("根据姓名修改节点寻找同名节点时发生错误!\n");
			return ;
		}
	}

	if(pos == head)//如果没有找到同名的节点数据
	{
		printf("没有找到该姓名的联系人!\n");
		return ;
	}

	/*如果找到*/	
	printf("%d:姓名:%s\t公司:%s\t职位:%s\t备注:%s\t电话号码:%ld\n",i,pos->name,pos->company,pos->work,pos->remarks,pos->phone_number);
	printf("已找到该姓名%s的联系人节点,该节点位与%d位,是否修改(y/n):",pos->name,i);
	flag = getchar();
	scanf("%c",&flag);
	if(flag == 'y')
	{
		printf("输入公司:");
		scanf("%s",company);
		printf("输入职位:");
		scanf("%s",work);
		printf("输入备注:");
		scanf("%s",remarks);
		printf("输入电话号码:");
		scanf("%ld",&phonenumber);

		strcpy(pos->company,company);
		strcpy(pos->work,work);
		strcpy(pos->remarks,remarks);
		pos->phone_number = phonenumber;

		update_name_mysql(sql,pos->name,pos->company,pos->work,pos->remarks,pos->phone_number);

		printf("根据姓名修改节点信息成功!\r\n");

	}
	else if(flag == 'n')
	{
		printf("不修改节点名字为%s的联系人\r\n",pos->name);
		return ;
	}
}

修改链表中电话号码为xx的某个节点的数据:同时也修改数据库表中电话号码为xx的某一行:

/*按电话号码修改*/
void list_motify_phonenumber(MYSQL *sql,node_pt head)
{
	int i = 1;
	char flag;//存放y or n
	char name[100];
	char company[100];
	char work[100];
	char remarks[200];
	unsigned long phonenumber;//存放输入的电话号码
	node_pt pos;

	printf("输入你要修改的电话号码的联系人节点:");
	scanf("%ld",&phonenumber);

	/*从头节点的下一个节点进行寻找*/
	for(pos = head->next; pos != head; pos = pos->next,i++)
	{
		if(pos->phone_number == phonenumber)//找到同电话号码的,退出循环
		{
			break;
		}
		if(i > list_sum(head))//如果找的次数比节点个数多
		{
			printf("根据电话号码修改节点寻找同电话号码节点时发生错误!\n");
			return ;
		}
	}

	if(pos == head)//如果找不到同电话号码的联系人
	{
		printf("没有找到该电话号码的联系人!\n");
		return ;
	}

	printf("%d:姓名:%s\t公司:%s\t职位:%s\t备注:%s\t电话号码:%ld\n",i,pos->name,pos->company,pos->work,pos->remarks,pos->phone_number);
	printf("已找到该电话号码%ld的联系人节点,该节点位与%d位,是否修改(y/n):",pos->phone_number,i);
	flag = getchar();
	scanf("%c",&flag);
	if(flag == 'y')
	{
		printf("输入姓名:");
		scanf("%s",name);
		printf("输入公司:");
		scanf("%s",company);
		printf("输入职位:");
		scanf("%s",work);
		printf("输入备注:");
		scanf("%s",remarks);

		strcpy(pos->name,name);
		strcpy(pos->company,company);
		strcpy(pos->work,work);
		strcpy(pos->remarks,remarks);

		update_phonenumber_mysql(sql,pos->name,pos->company,pos->work,pos->remarks,pos->phone_number);

		printf("根据电话号码修改联系人节点信息成功!\r\n");

	}
	else if(flag == 'n')
	{
		printf("不修改电话号码为%ld的联系人节点\r\n",pos->phone_number);
		return ;
	}
}

清空所有节点函数:同时MySQL数据库也清空表中的所有数据

/*清空所有联系人*/
void list_delete_all(MYSQL *sql,node_pt head)
{
	node_pt pos = head->next;
	node_pt temp;
	while(pos!= head)
	{
		temp = pos->next;
		free(pos);
		pos = temp;
	}
	free(head);

	/*清空MySQL表中所有数据*/
	delete_all_mysql(sql);
}

排序函数:
每次进行插入节点、删除节点、修改节点时,最后都会调用这个函数以节点的姓名拼音进行升序排序。

/*对链表中所有数据根据姓名的首字拼音进行排序*/
void sort(node_pt head)
{
	setlocale(LC_ALL, "");//配置地域信息 使用系统默认设置
	
	int i = 0;//infor数组的下标
	int j;

	node_pt pos = head->next;//指向头节点的下一个节点

	while(pos != head)
	{
		/*将名字、公司、职位、备注、电话号码全部复制一遍*/
		strcpy(infor[i].name,pos->name);
		strcpy(infor[i].company,pos->company);
		strcpy(infor[i].work,pos->work);
		strcpy(infor[i].remarks,pos->remarks);
		infor[i].phone_number = pos->phone_number;

		i++;//下标+1
		pos = pos->next;
	}
	printf("通讯录人数:%d\n",i);//打印出通讯录人数

	/*下面三种情况皆可
	*通过C语言编译器函数库自带的排序函数qsort对infor数组进行排序	
	*/
	//qsort(infor[0].name,i,sizeof(informations),(void *)strcoll);
	qsort(infor,i,sizeof(informations),(void *)strcoll);
	//qsort(&infor[0],i,sizeof(informations),(void *)strcoll);

	pos = head->next;//重新指向头节点
	i = 0;//infor数组下标置0
	while(pos != head)
	{
		/*将节点的所有字符串类型数据清空(名字、公司、职位、注释)*/
		memset(pos->name,0,sizeof(pos->name));
		memset(pos->company,0,sizeof(pos->company));
		memset(pos->work,0,sizeof(pos->work));
		memset(pos->remarks,0,sizeof(pos->remarks));

		/*将排序好的数据重新赋予给各节点*/
		pos->phone_number = infor[i].phone_number;
		strcpy(pos->name,infor[i].name);
		strcpy(pos->company,infor[i].company);
		strcpy(pos->work,infor[i].work);
		strcpy(pos->remarks,infor[i].remarks);
		
		i++;
		pos = pos->next;
	}

	pos = head->next;
	i = 1;
	while(pos != head)
	{
		printf("%d:姓名:%s\t公司:%s\t职位:%s\t备注:%s\t电话号码:%ld\n",i,pos->name,pos->company,pos->work,pos->remarks,pos->phone_number);
		pos = pos->next;
		i++;
	}	
}

效果实现

进入程序:
在这里插入图片描述
增加节点数据:
在这里插入图片描述
数据库里面也有数据:
在这里插入图片描述
查询节点数据:
之前我已经提前添加节点数据。
查询所有节点:
在这里插入图片描述
按照姓名查询单个节点:
在这里插入图片描述
按照电话号码查询单个节点:
在这里插入图片描述
按姓名删除节点:
在这里插入图片描述
数据库内也被删除:
在这里插入图片描述

修改节点:
在这里插入图片描述
数据库中也被修改
在这里插入图片描述
退出重新进入后,数据依然存在,并重新加载到节点里面:
在这里插入图片描述
按电话号码删除节点:
在这里插入图片描述
数据库中也被删除:
在这里插入图片描述

其它功能我就不一一验证了,大家可以下载验证(下载不用钱)。

下载地址:通讯录管理系统.zip(Linux-C语言+数据结构+MySQL).
https://download.csdn.net/download/weixin_41363159/12574223

  • 2
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值