[C]实现能在本地存储的简易通讯录

作者 华丞臧.
专栏【C语言】
各位读者老爷如果觉得博主写的不错,请诸位多多支持(点赞+收藏+关注)。如果有错误的地方,欢迎在评论区指出。



一、文件动态通讯录

前面写过一个静态通讯录,静态通讯录的容量是固定的,存放联系人达到最大容量就不能再存放了,并且在程序运行结束通讯录就销毁了;静态通讯录缺点很多,既不能根据用户需求扩容又不能在本地保存。

这次在学习相关文件操作后,我们来尝试写一个可以再本地文件保存数据的可动态增长的通讯录。

二、相关代码解析

2.1 初始化

初始化函数不仅要初始化data数组,还需要把本地保存的联系人数据加载到通讯录当中;而加载数据到data数组中去需要我们在堆上开辟空间,并且我们并不知道本地存储了多少字节的数据,所以写一个检查扩容的函数,当data数组没有开辟内存或者存满了就扩容,一次扩容两倍。

使用的是fread库函数,其函数原型如下:
在这里插入图片描述

//检查扩容
void CheckContactCapacity(CT* con)
{
	assert(con);

	//判断是否需要扩容
	if (con->size == con->capacity)
	{
		int newCapacity = con->capacity * 2;
		PeoInfo* tmp = (PeoInfo*)realloc(con->data, newCapacity * sizeof(PeoInfo));
		if (tmp == NULL)
		{
			perror("realloc fail");
			exit(-1);
		}
		con->data = tmp;
		con->capacity = newCapacity;
		printf("扩容成功\n");
	}	
}


//初始化
void ContactInit(CT* con)
{
	assert(con);
	
	con->data = (PeoInfo*)malloc(4 * sizeof(PeoInfo));
	con->size =  0;
	con->capacity = 4;
	//memset(con->data, 0, con->capacity * sizeof(PeoInfo));

	FILE* pf = fopen("contact.txt", "rb");
	PeoInfo s = { 0 };
	while (fread(&s, sizeof(PeoInfo), 1, pf))
	{
		CheckContactCapacity(con);
		con->data[con->size] = s;
		con->size++;
	}
	fclose(pf);
}

2.2 销毁通讯录

销毁通讯录,把通讯录当中的数据写入到本地文件当中并且释放动态内存开辟的空间。
在这里我使用的是fwrite库函数,其函数原型如下:
在这里插入图片描述

//通讯录销毁
void ContactDestroy(CT* con)
{
	assert(con);
	if (con->size != 0)
	{
		FILE* pf = fopen("contact.txt", "wb");

		int i = 0;
		PeoInfo s = { 0 };
		while (i < con->size)
		{
			s = con->data[i];
			fwrite(&s, sizeof(PeoInfo), 1, pf);
			i++;
		}

		fclose(pf);
	}

	free(con->data);
	con->data = NULL;
	con->size = con->capacity = 0;
}

2.3 增加联系人

通讯录是用来存储联系人信息的,那么就必然需要等一系列接口,通过这些接口来对通讯录进行操作。那么在通讯录中增加一个新的联系人,首先需要判断是否需要扩容;在初始化函数当中已经写了CheckContactCapacity()的函数直接调用即可,然后输入要增加的人的信息依次输入,用scanf函数存入对应的data数组当中。

//增加
void ContactAdd(CT* con)
{
	assert(con);
	
	//判断是否需要扩容
	CheckContactCapacity(con);
	
	//输入联系人信息
	printf("请输入姓名->");
	scanf("%s",con->data[con->size].name);

	printf("请输入性别->");
	scanf("%s", con->data[con->size].sex);

	printf("请输入年龄->");
	scanf("%d", &(con->data[con->size].age));

	printf("请输入电话->");
	scanf("%s", con->data[con->size].tele);

	printf("请输入地址->");
	scanf("%s", con->data[con->size].addr);
	
	con->size++;
}

2.4 查找指定联系人

查找指定联系人,需要知道该联系人至少一个信息。既然是按照姓名查找,就写一个FindByName()函数用来查找联系人,找到了返回下标找不到返回-1;找到了,就根据返回的下标把其对应的信息打印出来。


//按照名字查找,找到返回下标,找不到返回-1
int FindByName(CT* con,char* name)
{
	assert(con);
	
	PeoInfo* cur = con->data;

	//遍历查找
	int i = 0;
	while (i < con->size)
	{
		if (strcmp(name, (cur + i)->name) == 0)
		{
			return i;  //
		}
		i++;
	}
	return -1;
}

//查找
void ContactFind(CT* con)
{
	assert(con);

	char* name[NAME_MAX] = { 0 };

	printf("请输入要查找人的姓名->");
	scanf("%s",name);

	int n = FindByName(con,name);
	if (-1 == n)
	{
		printf("查找的人不存在\n");
		return;
	}

	printf("%-20s\t %-5s\t %-3s\t %-12s\t %-30s\t\n", 
		"姓名", 
		"性别", 
		"年龄", 
		"电话", 
		"地址");

	printf("%-20s\t %-5s\t %-3d\t %-12s\t %-30s\t\n"
		, con->data[n].name
		, con->data[n].sex
		, con->data[n].age
		, con->data[n].tele
		, con->data[n].addr);
}

2.5 删除指定联系人

通过姓名删除指定联系人,调用FindByName()函数找出要删除的人的下标,再挪动数据data数组处于下标位置的数据就可以达到删除的效果。

//删除
void ContactDel(CT* con)
{
	assert(con);
	assert(con->size);

	char name[NAME_MAX] = { 0 };

	printf("请输入要删除人的姓名->");
	scanf("%s",name);

	//查找
	int  n = FindByName(con, name);
	if (-1 == n)
	{
		printf("删除的人不存在\n");
	}
	else
	{
		//挪动数据
		while (n < con->size - 1)
		{
			con->data[n] = con->data[n + 1];
			n++;
		}

		con->size--;
	}
	printf("删除成功\n");
}

2.6 修改指定联系人

这里也是通过姓名来查找并且修改联系人的信息,同样调用FindByName()函数找出要修改的练习人的下标,通过返回的下标对其进行修改操作。

//修改
void ContactModify(CT* con)
{
	assert(con);

	char* name[NAME_MAX] = { 0 };

	printf("请输入要修改人的姓名->");
	scanf("%s",name);

	int n = FindByName(con, name);
	if (-1 == n)
	{
		printf("要修改的人不存在\n");
		return;
	}

	//输入联系人信息
	printf("请输入姓名->");
	scanf("%s", con->data[n].name);

	printf("请输入性别->");
	scanf("%s", con->data[n].sex);

	printf("请输入年龄->");
	scanf("%d", &(con->data[n].age));

	printf("请输入电话->");
	scanf("%s", con->data[n].tele);

	printf("请输入地址->");
	scanf("%s", con->data[n].addr);

	printf("修改成功\n");
}

2.7 通讯录清空

通讯录清空只需要把con->size置为0即可,con->size表示data数组中有效数据的个数。

//清空
void ContactClear(CT* con)
{
	assert(con);

	con->size = 0;
	
	printf("清空成功\n");
}

2.8 按照姓名排序

利用qsort函数,按照姓名对data中存放的数据进行排序;这里需要我们写一个比较字符串大小的函数,而strcmp()是用来比较字符串大小的库函数,且其返回值与qsort的要求一致。
qsort的说明和使用可见👉:qsort的使用和实现

int cmp_by_name(char* str1, char* str2)
{
	return strcmp(str1, str2);
}

//按照姓名排序
void ContactSortByName(CT* con)
{
	assert(con);

	qsort(con->data, con->size, sizeof(PeoInfo), cmp_by_name);

	ContactShow(con);
}

三、代码

3.1 main.c

#include "Contact.h"

void menu()
{
	printf("***** ***** ***** ***** *****\n");
	printf("***** 0.退出     1.添加 *****\n");
	printf("***** 2.删除     3.查找 *****\n");
	printf("***** 4.修改     5.展示 *****\n");
	printf("***** 6.排序     7.清空 *****\n");
	printf("***** ***** ***** ***** *****\n");
}

int main()
{
	
	CT con;
	ContactInit(&con);

	int input = 0;
	do
	{
		menu();
		printf("请选择->");
		scanf("%d",&input);
		switch (input)
		{
		case EXIT:
			ContactDestroy(&con);
			break;
		case ADD:
			ContactAdd(&con);
			break;
		case DEL:
			ContactDel(&con);
			break;
		case SEARCH:
			ContactSearch(&con);
			break;
		case MODIFY:
			ContactModify(&con);
			break;
		case SHOW:
			ContactShow(&con);
			break;
		case SORT:
			ContactSortByName(&con);
			break;
		case CLEAR:
			ContactClear(&con);
			break;
		default:
			break;
		}
	} while (input);
	return 0;
}

3.2 Contact.h

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include <string.h>


#define NAME_MAX 20
#define SEX_MAX 5
#define TELE_MAX 12
#define ADDR_MAX 30


typedef struct PeopleInfo
{
	char name[NAME_MAX];
	char sex[SEX_MAX];
	int age;
	char* tele[TELE_MAX];
	char* addr[ADDR_MAX];
}PeoInfo;

typedef struct Contact
{
	PeoInfo* data;
	int size;     //联系人个数
	int capacity; //容量
}CT;

enum Operations
{
	EXIT,
	ADD,
	DEL,
	SEARCH,
	MODIFY,
	SHOW,
	SORT,
	CLEAR
};

//初始化
void ContactInit(CT* con);

//打印通讯录信息
void ContactShow(CT* con);

//增加
void ContactAdd(CT* con);

//删除
void ContactDel(CT* con);

//查找
void ContactSearch(CT* con);

//修改
void ContactModify(CT* con);

//清空
void ContactClear(CT* con);

//按照姓名排序
void ContactSortByName(CT* con);

//通讯录销毁
void ContactDestroy(CT* con);

3.3 Contact.c

#include "Contact.h"

//检查扩容
void CheckContactCapacity(CT* con)
{
	assert(con);

	//判断是否需要扩容
	if (con->size == con->capacity)
	{
		int newCapacity = con->capacity * 2;
		PeoInfo* tmp = (PeoInfo*)realloc(con->data, newCapacity * sizeof(PeoInfo));
		if (tmp == NULL)
		{
			perror("realloc fail");
			exit(-1);
		}
		con->data = tmp;
		con->capacity = newCapacity;
		//memset(tmp+con->size, 0, (con->capacity-con->size) * sizeof(PeoInfo));
		printf("扩容成功\n");
	}	
}


//初始化
void ContactInit(CT* con)
{
	assert(con);
	
	con->data = (PeoInfo*)malloc(4 * sizeof(PeoInfo));
	con->size =  0;
	con->capacity = 4;
	//memset(con->data, 0, con->capacity * sizeof(PeoInfo));

	FILE* pf = fopen("contact.txt", "rb");
	PeoInfo s = { 0 };
	while (fread(&s, sizeof(PeoInfo), 1, pf))
	{
		CheckContactCapacity(con);
		con->data[con->size] = s;
		con->size++;
	}

	fclose(pf);

}
//打印通讯录信息
void ContactShow(CT* con)
{
	assert(con);

	PeoInfo* cur = con->data;

	//遍历打印
	printf("%-20s\t %-5s\t %-3s\t %-12s\t %-30s\t\n", "姓名", "性别", "年龄", "电话", "地址");
	int i = 0;
	while (i < con->size)
	{
		printf("%-20s\t %-5s\t %-3d\t %-12s\t %-30s\t\n", con->data[i].name
		, con->data[i].sex
		, con->data[i].age
		, con->data[i].tele
		, con->data[i].addr);
		i++;
	}
}

//增加
void ContactAdd(CT* con)
{
	assert(con);
	
	//判断是否需要扩容
	CheckContactCapacity(con);
	
	
	//输入联系人信息
	printf("请输入姓名->");
	scanf("%s",con->data[con->size].name);

	printf("请输入性别->");
	scanf("%s", con->data[con->size].sex);

	printf("请输入年龄->");
	scanf("%d", &(con->data[con->size].age));

	printf("请输入电话->");
	scanf("%s", con->data[con->size].tele);

	printf("请输入地址->");
	scanf("%s", con->data[con->size].addr);
	
	con->size++;
}

//按照名字查找,找到返回下标,找不到返回-1
int FindByName(CT* con,char* name)
{
	assert(con);
	
	PeoInfo* cur = con->data;

	//遍历查找
	int i = 0;
	while (i < con->size)
	{
		if (strcmp(name, cur->name) == 0)
		{
			return i;  //
		}
		i++;
	}
	return -1;
}

//删除
void ContactDel(CT* con)
{
	assert(con);
	assert(con->size);

	char name[NAME_MAX] = { 0 };

	printf("请输入要删除人的姓名->");
	scanf("%s",name);

	//查找
	int  n = FindByName(con, name);
	if (-1 == n)
	{
		printf("删除的人不存在\n");
	}
	else
	{
		//挪动数据
		while (n < con->size - 1)
		{
			con->data[n] = con->data[n + 1];
			n++;
		}

		con->size--;
	}
	printf("删除成功\n");
}


//查找
void ContactSearch(CT* con)
{
	assert(con);

	char* name[NAME_MAX] = { 0 };

	printf("请输入要查找人的姓名->");
	scanf("%s",name);

	int n = FindByName(con,name);
	if (-1 == n)
	{
		printf("查找的人不存在\n");
		return;
	}

	printf("%-20s\t %-5s\t %-3s\t %-12s\t %-30s\t\n", 
		"姓名", 
		"性别", 
		"年龄", 
		"电话", 
		"地址");

	printf("%-20s\t %-5s\t %-3d\t %-12s\t %-30s\t\n"
		, con->data[n].name
		, con->data[n].sex
		, con->data[n].age
		, con->data[n].tele
		, con->data[n].addr);
}

//修改
void ContactModify(CT* con)
{
	assert(con);

	char* name[NAME_MAX] = { 0 };

	printf("请输入要修改人的姓名->");
	scanf("%s",name);

	int n = FindByName(con, name);
	if (-1 == n)
	{
		printf("要修改的人不存在\n");
		return;
	}
	
		//输入联系人信息
		printf("请输入姓名->");
		scanf("%s", con->data[n].name);

		printf("请输入性别->");
		scanf("%s", con->data[n].sex);

		printf("请输入年龄->");
		scanf("%d", &(con->data[n].age));

		printf("请输入电话->");
		scanf("%s", con->data[n].tele);

		printf("请输入地址->");
		scanf("%s", con->data[n].addr);
		printf("修改成功\n");
}


//清空
void ContactClear(CT* con)
{
	assert(con);

	con->size = 0;

	printf("清空成功\n");
}

int cmp_by_name(char* str1, char* str2)
{
	return strcmp(str1, str2);
}

//按照姓名排序
void ContactSortByName(CT* con)
{
	assert(con);

	qsort(con->data, con->size, sizeof(PeoInfo), cmp_by_name);

	ContactShow(con);
}


//通讯录销毁
void ContactDestroy(CT* con)
{
	assert(con);
	if (con->size != 0)
	{
		FILE* pf = fopen("contact.txt", "wb");

		int i = 0;
		PeoInfo s = { 0 };
		while (i < con->size)
		{
			s = con->data[i];
			fwrite(&s, sizeof(PeoInfo), 1, pf);
			i++;
		}

		fclose(pf);
	}

	free(con->data);
	con->data = NULL;
	con->size = con->capacity = 0;
}
  • 18
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 13
    评论
实现CGI通讯录并能在局域网访问的全过程,需要涉及到以下几个步骤: 1. 编写通讯录的HTML页面,包括添加联系人、删除联系人、修改联系人和查询联系人等功能。 2. 编写CGI程序,对来自HTML页面的请求进行处理,并将结果返回给HTML页面。CGI程序可以使用C语言编写。 3. 配置Web服务器,将CGI程序与HTML页面放置在正确的目录下,并将CGI程序注册到Web服务器中。 下面是一个简单C语言实现CGI通讯录的示例代码,可以供参考: ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #include <mysql/mysql.h> //需要安装MySQL数据库 #define DBHOST "localhost" //数据库主机名 #define DBUSER "root" //数据库用户名 #define DBPASS "123456" //数据库密码 #define DBNAME "address_book" //数据库名称 //添加联系人 void add_contact(char *name, char *tel, char *email) { MYSQL *conn = mysql_init(NULL); if (mysql_real_connect(conn, DBHOST, DBUSER, DBPASS, DBNAME, 0, NULL, 0) == NULL) { printf("Error connecting to database: %s\n", mysql_error(conn)); return; } char query[1024]; sprintf(query, "INSERT INTO contacts(name, tel, email) VALUES('%s', '%s', '%s')", name, tel, email); if (mysql_query(conn, query) != 0) { printf("Error inserting contact: %s\n", mysql_error(conn)); return; } printf("Contact added successfully!\n"); mysql_close(conn); } //删除联系人 void del_contact(char *name) { MYSQL *conn = mysql_init(NULL); if (mysql_real_connect(conn, DBHOST, DBUSER, DBPASS, DBNAME, 0, NULL, 0) == NULL) { printf("Error connecting to database: %s\n", mysql_error(conn)); return; } char query[1024]; sprintf(query, "DELETE FROM contacts WHERE name='%s'", name); if (mysql_query(conn, query) != 0) { printf("Error deleting contact: %s\n", mysql_error(conn)); return; } printf("Contact deleted successfully!\n"); mysql_close(conn); } //修改联系人 void update_contact(char *name, char *tel, char *email) { MYSQL *conn = mysql_init(NULL); if (mysql_real_connect(conn, DBHOST, DBUSER, DBPASS, DBNAME, 0, NULL, 0) == NULL) { printf("Error connecting to database: %s\n", mysql_error(conn)); return; } char query[1024]; sprintf(query, "UPDATE contacts SET tel='%s', email='%s' WHERE name='%s'", tel, email, name); if (mysql_query(conn, query) != 0) { printf("Error updating contact: %s\n", mysql_error(conn)); return; } printf("Contact updated successfully!\n"); mysql_close(conn); } //查询联系人 void query_contact(char *name) { MYSQL *conn = mysql_init(NULL); if (mysql_real_connect(conn, DBHOST, DBUSER, DBPASS, DBNAME, 0, NULL, 0) == NULL) { printf("Error connecting to database: %s\n", mysql_error(conn)); return; } char query[1024]; sprintf(query, "SELECT * FROM contacts WHERE name='%s'", name); if (mysql_query(conn, query) != 0) { printf("Error querying contact: %s\n", mysql_error(conn)); return; } MYSQL_RES *result = mysql_store_result(conn); if (result == NULL) { printf("Error storing result: %s\n", mysql_error(conn)); return; } MYSQL_ROW row; while ((row = mysql_fetch_row(result))) { printf("Name: %s\n", row[1]); printf("Telephone: %s\n", row[2]); printf("Email: %s\n", row[3]); } mysql_free_result(result); mysql_close(conn); } int main(void) { char *method = getenv("REQUEST_METHOD"); //获取请求方法 if (strcmp(method, "GET") == 0) { //处理GET请求 char *query = getenv("QUERY_STRING"); //获取查询字符串 char name[1024]; sscanf(query, "name=%s", name); //解析查询字符串 query_contact(name); //查询联系人 } else if (strcmp(method, "POST") == 0) { //处理POST请求 char *content_len = getenv("CONTENT_LENGTH"); //获取POST数据长度 int len = atoi(content_len); char *post_data = (char *)malloc(len + 1); //分配内存 fgets(post_data, len + 1, stdin); //读取POST数据 char name[1024], tel[1024], email[1024]; sscanf(post_data, "name=%[^&]&tel=%[^&]&email=%s", name, tel, email); //解析POST数据 char *action = getenv("HTTP_ACTION"); //获取操作类型 if (strcmp(action, "add") == 0) { add_contact(name, tel, email); //添加联系人 } else if (strcmp(action, "del") == 0) { del_contact(name); //删除联系人 } else if (strcmp(action, "update") == 0) { update_contact(name, tel, email); //修改联系人 } free(post_data); } return 0; } ``` 在上述代码中,我们使用了MySQL数据库来存储联系人信息。需要注意的是,需要安装MySQL数据库,并在代码中正确地设置数据库主机名、用户名、密码和名称。 在编译代码时,需要使用CGI编译器将代码编译成可执行文件,并将其放置在Web服务器的CGI目录下。例如,在Apache服务器上,需要将可执行文件放置在“/var/www/cgi-bin/”目录下,并将其注册到服务器中。可以在HTML页面中使用表单来向CGI程序发送请求,并接收返回的结果。 希望这个示例代码能够帮助你实现CGI通讯录并能在局域网访问。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

华丞臧.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值