C语言笔记(通讯录)
目录
1.通讯录的架构
2.通讯录的功能
3.实现静态通讯录的功能步骤
3.1.创建通讯录数组
3.2.显示功能菜单
3.3.初始化通讯录
3.4.添加联系人的信息
3.5.显示联系人的信息
3.6.查找某个人的信息
3.7.删除某一个联系人信息
3.8.修改某一联系人的信息
3.9.按名字对联系人排序
3.10.清空通讯录
4.动态版本的实现
4.1.重新定义通讯录
4.2.初始换通讯录
4.3.扩容和写入信息函数
5.将通讯录存入文件中
6.代码
6.1.contact.h文件
6.2.test.c文件
6.3.contact.c文件
前言:
本片通讯录分为两个版本;静态和动态版本,区别在静态版本就像是纸质的通讯录一样,无法增加容量;而动态版本使用动态内存函数(malloc、realloc)来实现扩容,达到使多少扩多少的目的,以节省内存空间。若有错误请批评指正。
1.通讯录的架构
通讯录的编写分为了三个文件
1.test.c 主要编写 测试程序(程序运行的运行框架)
2.contact.c 主要编写测试程序中用到的自定义函数
3.contact.h (1)包含相关的头文件
(2)创建全局变量
(3)声明contact.c中的函数
2.通讯录的功能
存储信息: 姓名 年龄 性别 地址 电话
静态版本实现功能:
- 显示功能菜单;
- 添加联系人的信息;
- 显示联系人的信息;
- 查找某一个联系人信息;
- 删除某一联系人的信息;
- 修改某一联系人的信息;
- 按名字对联系人排序。
动态版本实现功能:
- 可以随着联系人的增多实现空间扩容。
3.实现静态通讯录的功能步骤
3.1.创建通讯录数组
创建存储联系人信息的结构体 ,并重新命名为PeoInfo
typedef struct PeoInfo
{
char name[20];
int age;
char sex[5];
char addr[30];
char tele[12];
}PeoInfo;
创建通讯录数组;使用宏定义的通讯录大小以便查找和修改
#define MAX 1000//静态情况下定义的通讯录最大容量
typedef struct Contact
{
PeoInfo data[MAX];//存放个人信息的
int sz; //当前已经存放几个人的信息
}contact;
3.2.显示功能菜单
函数较为简单不做过多的说明;仅仅时printf函数的应用
void menu()
{
printf("***********************************\n");
printf("****** 1.Add 2.Del *******\n");
printf("****** 3.Search 4.Modify *******\n");
printf("****** 5.Show 6.Sort *******\n");
printf("****** 7.Clear 0.Exit *******\n");
printf("***********************************\n");
}
3.3.初始化通讯录
初始化通讯录的目的就是将通讯录所占用的内存中的数据全部置为0。
void InitContact( contact* pc)
{
assert(pc);
pc->sz = 0;
memset(pc->data, 0, sizeof(pc->data));
}
memset函数 将 ptr 指向的内存块的前字节数设置为指定值
void * memset ( void * ptr, int value, size_t num );
ptr 指向要填充的内存块的指针
value 要设置的值。
num 要设置为该值的字节数
3.4.添加联系人的信息
简单的说就是给一个信息数组输入数据,核心为scanf函数。
第一个函数:判断通讯录是否还有空间;然后再调用信息输入函数;
第二个函数:信息输入函数。
//添加信息函数
void AddContact(contact* pc)
{
if (pc->sz == MAX)
{
printf("通讯录已满");
return;
}
ScanfInformation(pc);
}
//录入信息函数,调出来方便后续的使用
void ScanfInformation(contact* pc)
{
printf("请输入名字\n");
scanf("%s", pc->data[pc->sz].name);
printf("请输入年龄\n");
scanf("%d", &(pc->data[pc->sz].age));
printf("请输入性别\n");
scanf("%s", pc->data[pc->sz].sex);
printf("请输入地址\n");
scanf("%s", pc->data[pc->sz].addr);
printf("请输入电话\n");
scanf("%s", pc->data[pc->sz].tele);
printf("输入完成\n");
pc->sz++;
printf("录入成功\n");
}
3.5.显示联系人的信息
显示联系人的核心是printf函数应用;
- 为右对齐
+ 为左对齐
\t 为水平制表符
pc为结构体指针;使用->符号对结构体数据进行访问。
void ShowContact(const contact* pc)
{
printf("%-10s\t %-10s\t %-9s\t %-9s\t %-10s\n","姓名" ,"年龄"," 性别"," 地址"," 电话");
int i = 0;
for (i = 0; i < pc->sz; i++)
{
printf("%-10s\t %-10d\t %-10s\t %-10s\t %-10s\n",
pc->data[i].name,
pc->data[i].age,
pc->data[i].sex,
pc->data[i].addr,
pc->data[i].tele);
}
}
3.6.查找某个人的信息
思路
- 找到这个人
- 然后显示信息
void SearchContact(contact* pc)
{
//通过名字寻找联系人信息
printf("请输入要搜索联系人的姓名\n");
int pos = FindByName(pc);
ShowContactone(pc, pos);
}
int FindByName(contact* pc)
{
char name[20] = { 0 };
scanf("%s", name);
int i = 0;
for (i = 0; i < pc->sz; i++)
{
if (strcmp(pc->data[i].name, name) == 0)
{
return i;
}
}
return -1;
}
void ShowContactone(const contact* pc,int pos)//打印一个人的信息
{
printf("%-10s\t %-10s\t %-9s\t %-9s\t %-10s\n", "姓名", "年龄", " 性别", " 地址", " 电话");
printf("%-10s\t %-10d\t %-10s\t %-10s\t %-10s\n",
pc->data[pos].name,
pc->data[pos].age,
pc->data[pos].sex,
pc->data[pos].addr,
pc->data[pos].tele);
}
3.7.删除某一个联系人信息
按照名字来找联系人,并显示这个人的信息;主要就是strcmp函数比较
strcmp函数 比较两个字符串
int strcmp ( const char * str1, const char * str2 );
- 函数1:要找个人的大体思路;
- 函数2:按名字找人;
- 函数3:输出这个人的信息。
int FindByName(contact* pc)
{
char name[20] = { 0 };
scanf("%s", name);
int i = 0;
for (i = 0; i < pc->sz; i++)
{
if (strcmp(pc->data[i].name, name) == 0)
{
return i;
}
}
return -1;
}
void DelContact(contact* pc)//找到删除人的名字然后向前递增一下
{
printf("请输入要删除的人的名字\n");
int del = FindByName(pc);
//然后信息覆盖
if (del >= 0)
{
for (; del < pc->sz; del++)
{
pc->data[del] = pc->data[del + 1];
}
pc->sz--;
printf("删除成功\n");
}
else if (del < 0)
{
printf("未找到该联系人\n");
}
}
3.8.修改某一联系人的信息
思路
- 找到这个人
- 重新录入信息
void ModifyContact(contact* pc) { printf("请输入要修改联系人的姓名\n"); int pos = FindByName(pc); if (-1 == pos) { printf("未查找到此人\n"); } else //修改某人的信息 { printf("请输入名字\n"); scanf("%s", pc->data[pos].name); printf("请输入年龄\n"); scanf("%d", &(pc->data[pos].age)); printf("请输入性别\n"); scanf("%s", pc->data[pos].sex); printf("请输入地址\n"); scanf("%s", pc->data[pos].addr); printf("请输入电话\n"); scanf("%s", pc->data[pos].tele); printf("输入完成\n"); printf("修改成功,修改信息如下\n"); ShowContactone(pc, pos); } } int FindByName(contact* pc) { char name[20] = { 0 }; scanf("%s", name); int i = 0; for (i = 0; i < pc->sz; i++) { if (strcmp(pc->data[i].name, name) == 0) { return i; } } return -1; }
3.9.按名字对联系人排序
qsort函数
void qsort (void* base, size_t num, size_t size,
int (*compar)(const void*,const void*));
base 指向要排序的数组的第一个对象的指针,转换为 .
void*
num 指向的数组中的元素数。
size 指向的数组中的元素数。(以字节为单位)
int (*compar)(const void*,const void*)
指向比较两个元素的函数的指针。
此函数
int CompareByName(const void * a, const void * b)
{
return (((PeoInfo*)a)->name ,((PeoInfo*)b)->name);
}
void SortContact(contact* pc)
{
assert(pc);
if (pc->sz == 0)
{
printf("通讯录没有人\n");
return;
}
qsort(pc->data, pc->sz, sizeof(pc->data[0]),CompareByName);//数组 数组的大小 数组有几个元素,数组元素的大小
printf("排序完成\n");
}
3.10.清空通讯录
思路:通讯录不清零和初始化一样所以
void DestoryContact(contact* pc)
{
pc->data = NULL;
pc->sz = 0;
pc-capacity = 0;
}
4.动态版本的实现
4.1.重新定义通讯录
typedef struct Contact
{
PeoInfo* data;//存放个人信息的
int sz; //当前已经存放几个人的信息
int capacity; //目前通讯录的容量
}contact;
4.2.初始换通讯录
使用malloc函数开辟空间;
1.功能:
malloc:向内存申请一块连续可用的空间,返回指向这块空间起始的指针;
free: 释放动态开辟的内存。
2.使用形式
void* malloc (size_t size);
void free (void* ptr);
1.void* 返回值类型为空指针,需要强转换再使用,申请成功返回内存块起始指针,申请内存失败,返回位空指针;
2.size 内存块的大小,字节位单位,size_t无符号整型;
注意:
1.malloc函数申请的空间是不会初始化的,内存块不初始化是随机值。
2.在free释放内存块之后,void* 函数的返回值保留之前的开辟内存块的时候指针变量,
如果再访问就是非法访问了,因此使用完内存空间要将返回值置为NULL,可看示例。
#define DEFAULT_SZ 3 //初始开辟空间
#define INC_SZ 3 //每次扩容的大小
void InitContact2(contact* pc)
{
assert(pc);
pc->data = (PeoInfo*)malloc(DEFAULT_SZ * sizeof(PeoInfo));
if (pc == NULL)
{
perror("Init_Contact2:");
return;
}
pc->sz = 0;
pc->capacity = DEFAULT_SZ;
}
4.3.扩容和写入信息函数
- 判断通讯录是否还有空间
- 有空间录入信息,无空间扩容后再录入新信息
realloc函数
1.功能:Reallocate memory block,重新分配内存块的大小,扩展原有的内存块,或者申请新的内存块,
特点:保留之前的内存中的数据。
2.使用形式:
void* realloc (void* ptr, size_t size);
int Checkcapacity(contact* pc)
{
//判断是否要扩容
PeoInfo* str;
if (pc->sz == pc->capacity)
{
str = (PeoInfo*)realloc(pc->data, (pc->sz + INC_SZ) * sizeof(PeoInfo));
if (str==NULL)
{
perror("Check_capacity");
printf("扩容失败\n");
return 0;
}
else
{
pc->data = str;
pc->capacity += INC_SZ;
printf("扩容成功\n");
}
}
return 1;
}
void AddContact2(contact* pc)
{
assert(pc);
int ret = Checkcapacity(pc);
if (0 == ret)
{
return ;
}
//录入信息
else
ScanfInformation(pc);
}
5.将通讯录存入文件中
选择使用二进制的存储较为方便
void SaveContact(contact* pc)
{
assert(pc);
//打开文件
FILE* pf = fopen("contact.txt","wb");//二进制方打开
if (NULL == pf)
{
perror("SaveContact");
return;
}
else
{
int i = 0;
for (i = 0; i < pc->sz; i++)
{
fwrite(pc->data + i, sizeof(PeoInfo), 1, pf);//写入
}
fclose(pf);
pf == NULL;
}
}
6.代码
6.1.contact.h文件
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
//定义变量
#define MAX 1000//静态情况下定义的通讯录最大容量
#define DEFAULT_SZ 3
#define INC_SZ 3
typedef struct PeoInfo
{
char name[20];
int age;
char sex[5];
char addr[30];
char tele[12];
}PeoInfo;
//创建通讯录
//typedef struct Contact
//{
// PeoInfo data[MAX];//存放个人信息的
// int sz; //当前已经存放几个人的信息
//}contact;
typedef struct Contact
{
PeoInfo* data;//存放个人信息的
int sz; //当前已经存放几个人的信息
int capacity; //目前通讯录的容量
}contact;
//功能菜单
void menu();
//初始化通讯录
//静态版本
void InitContact( contact* pc);
//动态版本
void InitContact2(contact* pc);
//输入信息
void AddContact(contact* pc);
//动态版本在输入信息之前容量增大需要扩容
int Checkcapacity(contact* pc);
void AddContact2(contact* pc);
//显示通讯录
void ShowContact( contact* pc);
//删除指定人信息
void DelContact( contact* pc);
//寻找某一的联系人的联系方式
void SearchContact(contact* pc);
//修改某一的联系人的联系方式
void ModifyContact(contact* pc);
//排序
void SortContact(contact* pc);
//清空联系人 初始化
void DestoryContact(contact* pc);
//存储通讯录中的信息到文件中
void SaveContact(contact* pc);
6.2.test.c文件
使用了一个枚举变量,和do……while循环以及swich()分支语句
#define _CRT_SECURE_NO_WARNINGS
#include "contact.h"
enum
{
Exit = 0,
Add,
Del,
Search,
Modify,
Show,
Sort
};
void menu();
int main()
{
int input = 0;
contact con;
//初始化通讯录
InitContact2(&con);
do
{
menu();
printf(" 请选择模式\n");
scanf("%d", &input);
switch(input)
{
case Add:
AddContact2(&con);
break;
case Del:
DelContact(&con);
break;
case Search:
SearchContact(&con);
break;
case Modify:
ModifyContact(&con);
break;
case Show:
ShowContact(&con);
break;
case Sort:
SortContact(&con);
break;
case Exit:
SaveContact(&con);
DestoryContact(&con);
printf("退出编辑\n");
default:
printf("输入错误,请重新输入\n");
}
}
while (input);
return 0;
}
6.3.contact.c文件
contact.c文件起始就是函数来回调用;模块化更为简单易懂,看着方便。
#include "contact.h"
//功能菜单
void menu()
{
printf("***********************************\n");
printf("****** 1.Add 2.Del *******\n");
printf("****** 3.Search 4.Modify *******\n");
printf("****** 5.Show 6.Sort *******\n");
printf("****** 7.Clear 0.Exit *******\n");
printf("***********************************\n");
}
//按照名字寻找某人
int FindByName(contact* pc)
{
char name[20] = { 0 };
scanf("%s", name);
int i = 0;
for (i = 0; i < pc->sz; i++)
{
if (strcmp(pc->data[i].name, name) == 0)
{
return i;
}
}
return -1;
}
void ScanfInformation(contact* pc)
{
printf("请输入名字\n");
scanf("%s", pc->data[pc->sz].name);
printf("请输入年龄\n");
scanf("%d", &(pc->data[pc->sz].age));
printf("请输入性别\n");
scanf("%s", pc->data[pc->sz].sex);
printf("请输入地址\n");
scanf("%s", pc->data[pc->sz].addr);
printf("请输入电话\n");
scanf("%s", pc->data[pc->sz].tele);
printf("输入完成\n");
pc->sz++;
printf("录入成功\n");
}
//初始化通信录//清空通讯录
void InitContact( contact* pc)
{
assert(pc);
pc->sz = 0;
memset(pc->data, 0, sizeof(pc->data));
}
//动态版本
void InitContact2(contact* pc)
{
assert(pc);
pc->data = (PeoInfo*)malloc(DEFAULT_SZ * sizeof(PeoInfo));
if (pc == NULL)
{
perror("Init_Contact2:");
return;
}
pc->sz = 0;
pc->capacity = DEFAULT_SZ;
}
//录入信息 静态 不再扩容的情况
//检查容量
int Checkcapacity(contact* pc)
{
//判断是否要扩容
PeoInfo* str;
if (pc->sz == pc->capacity)
{
str = (PeoInfo*)realloc(pc->data, (pc->sz + INC_SZ) * sizeof(PeoInfo));
if (str==NULL)
{
perror("Check_capacity");
printf("扩容失败\n");
return 0;
}
else
{
pc->data = str;
pc->capacity += INC_SZ;
printf("扩容成功\n");
}
}
return 1;
}
void AddContact2(contact* pc)
{
assert(pc);
int ret = Checkcapacity(pc);
if (0 == ret)
{
return ;
}
//录入信息
else
ScanfInformation(pc);
}
void AddContact(contact* pc)
{
if (pc->sz == MAX)
{
printf("通讯录已满");
return;
}
ScanfInformation(pc);
}
//录入信息 静态 不再扩容的情况
//显示通讯录
void ShowContact(const contact* pc)
{
printf("%-10s\t %-10s\t %-9s\t %-9s\t %-10s\n","姓名" ,"年龄"," 性别"," 地址"," 电话");
int i = 0;
for (i = 0; i < pc->sz; i++)
{
printf("%-10s\t %-10d\t %-10s\t %-10s\t %-10s\n",
pc->data[i].name,
pc->data[i].age,
pc->data[i].sex,
pc->data[i].addr,
pc->data[i].tele);
}
}
void ShowContactone(const contact* pc,int pos)//打印一个人的信息
{
printf("%-10s\t %-10s\t %-9s\t %-9s\t %-10s\n", "姓名", "年龄", " 性别", " 地址", " 电话");
printf("%-10s\t %-10d\t %-10s\t %-10s\t %-10s\n",
pc->data[pos].name,
pc->data[pos].age,
pc->data[pos].sex,
pc->data[pos].addr,
pc->data[pos].tele);
}
//pos为位置信息
//删除某人的信息
void DelContact(contact* pc)//找到删除人的名字然后向前递增一下
{
printf("请输入要删除的人的名字\n");
int del = FindByName(pc);
//然后信息覆盖
if (del >= 0)
{
for (; del < pc->sz; del++)
{
pc->data[del] = pc->data[del + 1];
}
pc->sz--;
printf("删除成功\n");
}
else if (del < 0)
{
printf("未找到该联系人\n");
}
}
void SearchContact(contact* pc)
{
//通过名字寻找联系人信息
printf("请输入要搜索联系人的姓名\n");
int pos = FindByName(pc);
ShowContactone(pc, pos);
}
void ModifyContact(contact* pc)
{
printf("请输入要修改联系人的姓名\n");
int pos = FindByName(pc);
if (-1 == pos)
{
printf("未查找到此人\n");
}
else //修改某人的信息
{
printf("请输入名字\n");
scanf("%s", pc->data[pos].name);
printf("请输入年龄\n");
scanf("%d", &(pc->data[pos].age));
printf("请输入性别\n");
scanf("%s", pc->data[pos].sex);
printf("请输入地址\n");
scanf("%s", pc->data[pos].addr);
printf("请输入电话\n");
scanf("%s", pc->data[pos].tele);
printf("输入完成\n");
printf("修改成功,修改信息如下\n");
ShowContactone(pc, pos);
}
}
int CompareByName(const void * a, const void * b)
{
return (((PeoInfo*)a)->name ,((PeoInfo*)b)->name);
}
void SortContact(contact* pc)
{
assert(pc);
if (pc->sz == 0)
{
printf("通讯录没有人\n");
return;
}
qsort(pc->data, pc->sz, sizeof(pc->data[0]),CompareByName);//数组 数组的大小 数组有几个元素,数组元素的大小
printf("排序完成\n");
}
void DestoryContact(contact* pc)
{
InitContact(pc);
}
void SaveContact(contact* pc)
{
assert(pc);
//打开文件
FILE* pf = fopen("contact.txt","wb");
if (NULL == pf)
{
perror("SaveContact");
return;
}
else
{
int i = 0;
for (i = 0; i < pc->sz; i++)
{
fwrite(pc->data + i, sizeof(PeoInfo), 1, pf);
}
fclose(pf);
pf == NULL;
}
}