这个题目要求我们实现一个通讯录,该通讯录要满足以下功能(全部使用c语言知识):
1、添加联系人(姓名,性别,年龄,电话,地址);
2、删除联系人(按名字);
3、查找(按名字);
4、修改(所有属性);
5、浏览所有联系人;
6、清空联系人列表;
7、排序(按名字);
8、其容量为动态增长的,即:当通讯录已满的情况下,在你进行添加时,它会动态增长。
注意:上述某些功能还可以更为完善,比如可以按其它属性进行删查排序。
除此之外:我们知道通讯录最重要也是最主要的功能就是对信息的保存,所以这就要求我们使用文件操作,即:在每次关闭的时候将本次的所有输入保存到文件,而在每次打开时将上次关闭前保存的内容读取到通讯录。
我们先给出通讯录的完整代码,然后对其部分逻辑进行简要分析。
注意:c语言中,写大的工程时,一般将头文件、函数实现、和main函数写到不同的源文件中,这样能使结构更加清晰,也方便其它操作。
头文件部分
contact.h
//条件编译
#ifndef __CONTACT_H__
#define __CONTACT_H__
//头文件列表
#include <stdio.h>
#include <windows.h>
#include <assert.h>
#include <string.h>
//忽略警告
#pragma warning(disable:4996)
//宏
#define INITCAP 128//初始化长度
#define INCREMENT 32//自增长度
#define FILE_NAME "contact_back"//打开文件名
//声明:
//联系人结构体
typedef struct person{
char name[32];//姓名 性别 年龄 电话 地址
char sex[8];
unsigned char age;
char phone[16];
char adds[64];
}person_t, *person_p, **person_pp;
//通讯录结构体
typedef struct contact{
int cap;//最大长度
int size;//当前长度
person_p contactList;//联系人列表
}contact_t, *contact_p, **contact_pp;
//函数声明
void initContact(contact_pp c);//初始化通讯录
void addContact(contact_p c, person_p p);//添加联系人
void showContact(contact_p c);//打印联系人列表
void delContact(contact_p c, char *del_name);//删除
void emptyContact(contact_p c);//清空
void destroyContact(contact_p c);//摧毁通讯录
int searchContact(contact_p c, char *search_name);//查找
void sortContact(contact_p c);//排序
void modContact(contact_p c);//修改
void helpContact();//帮助
void exitContact(contact_p c);//退出
int isContactEmpty(contact_p c);//判空
int fileLoad(contact_p c);//下载到项目
int fileStore(contact_p c);//储存到文件
#endif __CONTACT_H__
主函数
main.c
#include "contact.h"
//菜单
static void meun(){
printf("\n");
printf("Welcome...\n");
printf("----------------------------------- CONTACTS --------------------------------\n");
printf("-- 1.Add 2.Delect --\n");
printf("-- 3.Search 4.Edit --\n");
printf("-- 5.Show 6.Empty --\n");
printf("-- 7.Sort 8.Help --\n");
printf("-- 0.Exit --\n");
printf("-- 作者qq:248620932,ID:果冻,欢迎交流... =_= --\n");
printf("-------------------------------------------------------------------------------\n");
printf("\n");
}
//添加
static void myAdd(contact_p c){
person_t p;
assert(c);
printf("Please input information<name,sex,age,phone,addr>:\n");
scanf("%s %s %d %s %s", p.name, p.sex, &p.age, p.phone, p.adds);
addContact(c, &p);
}
//删除
static void myDel(contact_p c){
char del_name[32];
int n = 0;
assert(c);
if(isContactEmpty(c)){
printf("Contact is empty!\n");
return ;
}
printf("Please input the name whicth you want delect:");
scanf("%s", del_name);
printf("\nAre you sure delect: %s ?\n", del_name);
while(1)
{
printf("----------------\n");
printf("| 1.YES | 2.NO |\n");
printf("----------------\n");
scanf("%d", &n);
if( 1 == n)
{
delContact(c, del_name);
return ;
}
else if( 2 == n )
{
return;
}
else
{
printf("Error ! \n");
}
}
}
//查找
static void mySearch(contact_p c)
{
char search_name[32];
int pos = 0;
int i = 0;
assert(c);
if(isContactEmpty(c)){
printf("Contact is empty!\n");
return ;
}
printf("Please input rhe name whicth you want to search:");
scanf("%s", search_name);
pos = searchContact(c, search_name);
if(-1 == pos){
printf("Not find!\n");
}
else{
printf("------------------------------------------------------------------------------\n");
printf("| name | sex | age | phone | adds |\n");
printf("| %-10s| %-5s| %-4d| %-16s| %-32s|\n",c->contactList[i].name, \
c->contactList[i].sex,c->contactList[i].age, \
c->contactList[i].phone,c->contactList[i].adds);
printf("------------------------------------------------------------------------------\n");
}
}
int main()
{
int s = -1;//选择控制变量
contact_p myContact = NULL;//声明通讯录
system("color 2");
initContact(&myContact);//初始化
while(1){
meun();
printf("Please select<0~7>:");
fflush(stdin);
scanf("%d", &s);
switch(s){
case 1:system("cls");
myAdd(myContact);//添加联系人
system("pause");
break;
case 2:system("cls");
myDel(myContact);//删除联系人
system("pause");
break;
case 3:system("cls");
mySearch(myContact);//查找并打印联系人
system("pause");
break;
case 4:system("cls");
modContact(myContact);//修改联系人
system("pause");
break;
case 5:system("cls");
showContact(myContact);//显示联系人列表
system("pause");
break;
case 6:system("cls");
emptyContact(myContact);//清空通讯录
system("pause");
break;
case 7:system("cls");
sortContact(myContact);//排序通讯录
system("pause");
break;
case 8:system("cls");
helpContact();//帮助
system("pause");
break;
case 0:system("cls");
exitContact(myContact);//退出
break;
default:printf("ERROR SELECTION !!!\n");//错误选择
system("pause");
break;
}
system("cls");//清屏
}
return 0;
}
函数实现部分
contact.c
#include "contact.h"
//判空
//空:1
//不空:0
int isContactEmpty(contact_p c)
{
assert(c);
return c->size == 0 ? 1 : 0;
}
//初始化
void initContact(contact_pp c)
{
assert(c);
//申请通讯录空间
*c = (contact_p)malloc(sizeof(contact_t));
if(NULL == *c){
perror("malloc");
exit(1);
}
//申请成员空间
(*c)->contactList = (person_p)malloc(sizeof(person_t)*INITCAP);
if(NULL == (*c)->contactList){
perror("malloc");
exit(2);
}
//初始化长度和容量
(*c)->cap = INITCAP;
(*c)->size = 0;
fileLoad(*c);
}
//从文件读取通讯录信息
int fileLoad(contact_p c)
{
FILE *fp;
person_t p;
int i = 0;
assert(c);
//打开文件
fp = fopen(FILE_NAME,"rb");
if(NULL == fp){
perror("fopen");
return -2;
}
while(1){
//读取到p
fread(&p, sizeof(person_t), 1, fp);
if(0 != feof(fp)){
break;
}
//将读取的添加到通讯录
addContact(c, &p);
}
fclose(fp);
return 0;
}
//判满
//满:1
//未满:0
static int isContactFull(contact_p c)
{
assert(c);
return c->size >= c-> cap ? 1 : 0;
}
//自增
static int incContact(contact_p c)
{
person_p new_c = NULL;
assert(c);
//申请新空间
new_c = (person_p)realloc(c->contactList, (c->cap+INCREMENT)*sizeof(person_t));
if(NULL == new_c){
perror("realloc");
return 0;
}
//将新空间分配给旧空间
c->contactList = new_c;
c->cap += INCREMENT;
printf("Is full, increse success!\n");
return 1;
}
//添加联系人
void addContact(contact_p c, person_p p)
{
assert(c);
assert(p);
//如果不空直接添加,如果空就先自增再添加
if(!isContactFull(c) || incContact(c)){
c->contactList[c->size] = *p;
c->size++;
}
}
//查找
//是空的:打印空
//没找到:返回 -1
//找到:返回下标
int searchContact(contact_p c, char *search_name)
{
int i = 0;
assert(c);
assert(search_name);
//通讯录是空的
if(isContactEmpty(c)){
printf("Contact is empty!\n");
}
for(i = 0; i < c->size; i++){
if( 0 == strcmp(c->contactList[i].name, search_name) ){
break;
}
}
//没找到
if(i == c->size)
{
return -1;
}
//找到返回下标
return i;
}
//按名字排序
void sortContact(contact_p c)
{
int i = 0;
int j = 0;
int pos = 0;
person_t temp;
assert(c);
//是空的就不用排
if(isContactEmpty(c)){
printf("Contact is empty!\n");
return ;
}
//不空用冒泡法按名字排序
for(i = c->size-1; i>0; i--){
for(j = 0; j<i; j++){
if(1 == strcmp(c->contactList[j].name, c->contactList[j+1].name)){
temp = c->contactList[j];
c->contactList[j] = c->contactList[j+1];
c->contactList[j+1] = temp;
pos = 1;
}
}
if(0 == pos)
{
break;
}
}
printf("Done...\n");
}
//修改联系人
void modContact(contact_p c)
{
char name[32];
int i = 0;
char key_mod[8];
assert(c);
if(isContactEmpty(c)){
printf("Contact is empty!\n");
return ;
}
//输入要修改的人的名字
printf("Please input the name whicth you want to modify:");
scanf("%s", name);
//查找要修改人的下标
i = searchContact(c, name);
if(-1 == i)
{
printf("Not find!\n");
return ;
}
//打印信息
printf("------------------------------------------------------------------------------\n");
printf("| name | sex | age | phone | adds |\n");
printf("| %-10s| %-5s| %-4d| %-16s| %-32s|\n",c->contactList[i].name, \
c->contactList[i].sex,c->contactList[i].age, \
c->contactList[i].phone,c->contactList[i].adds);
printf("------------------------------------------------------------------------------\n");
//输入要修改的关键字
printf("Please input the infor whicth you want to modify:");
fflush(stdin);
scanf("%s", key_mod);
//寻找要修改的关键字
//如果要修改名字
if(0 == strcmp("name", key_mod)){
printf("Please input new name:");
fflush(stdin);//注意要清空输入缓冲区
scanf("%s", c->contactList[i].name);
printf("Done...\n");
return ;
}
//如果要修改性别
if(0 == strcmp("sex", key_mod)){
printf("Please input new sex:");
fflush(stdin);
scanf("%s", c->contactList[i].sex);
printf("Done...\n");
return ;
}
//如果要修改年龄
if(0 == strcmp("age", key_mod)){
printf("Please input new age:");
fflush(stdin);
scanf("%d", &c->contactList[i].age);
printf("Done...\n");
return ;
}
//如果要修改电话号码
if(0 == strcmp("phone", key_mod)){
printf("Please input new phone:");
fflush(stdin);
scanf("%s", c->contactList[i].phone);
printf("Done...\n");
return ;
}
//如果要修改地址
if(0 == strcmp("adds", key_mod)){
printf("Please input new adds:");
fflush(stdin);
scanf("%s", c->contactList[i].adds);
printf("Done...\n");
return ;
}
//没有找到要修改的关键字
printf("ERROR!!\n");
}
//删除
void delContact(contact_p c, char *del_name)
{
int i = 0;
int j = 0;
assert(c);
i = searchContact(c, del_name);
if(-1 == i)
{
printf("Not find!\n");
return ;
}
//将后面的成员前移
for(j = i;j<c->size; j++){
c->contactList[j] = c->contactList[j+1];
}
c->size--;
printf("Done...\n");
}
//清空通讯录
void emptyContact(contact_p c)
{
assert(c);
//直接将当前大小置0
c->size = 0;
printf("Done...\n");
}
//打印信息
void showContact(contact_p c)
{
int i = 0;
assert(c);
if(isContactEmpty(c)){
printf("Contact is empty!\n");
return ;
}
printf("\ntotal:%d\n", c->size);//打印总人数
//打印详细信息
printf("------------------------------- contacts -------------------------------------\n");
printf("| name | sex | age | phone | adds |\n");
printf("------------------------------------------------------------------------------\n");
for(; i < c->size; i++){
printf("| %-10s| %-5s| %-4d| %-16s| %-32s|\n",c->contactList[i].name, \
c->contactList[i].sex,c->contactList[i].age, \
c->contactList[i].phone,c->contactList[i].adds);
}
printf("------------------------------------------------------------------------------\n\n");
}
//帮助(使用手册)
void helpContact()
{
printf("\n");
printf("----------------------------------- HELP -----------------------------------\n");
printf("| You could use this app store up some information about your friends. |\n");
printf("| 1、you can add information by choose ( 1 ). |\n");
printf("| 2、you can delect someone by choose ( 2 ). |\n");
printf("| 3、you can search someone by choose ( 3 ). |\n");
printf("| 4、you can change some's information by choose ( 4 ). |\n");
printf("| 5、you can show information list by choose ( 5 ). |\n");
printf("| 6、you can empty all information by choose ( 6 ). |\n");
printf("| 7、you can sort people by choose ( 7 ). |\n");
printf("------------------------------------------------------------------------------\n\n");
}
//储存到文件
int fileStore(contact_p c)
{
FILE *fp;
int i = 0;
assert(c);
//打开文件
fp = fopen(FILE_NAME,"wb");
if(NULL == fp){
perror("fopen");
return -1;
}
//一次储存一个人大小的内容
for(; i<c->size; i++){
fwrite(c->contactList+i, sizeof(person_t), 1, fp);
}
fclose(fp);
return 0;
}
//摧毁通讯录
void destroyContact(contact_p c)
{
assert(c);
fileStore(c);//写入到文件
free(c->contactList);//释放联系人列表
c->contactList = NULL;
free(c);//释放整体
c = NULL;
}
//退出
void exitContact(contact_p c)
{
int n = 0;
printf("\nAre you sure quit ?\n");
while(1)
{
printf("----------------\n");
printf("| 1.YES | 2.NO |\n");
printf("----------------\n");
scanf("%d", &n);
if( 1 == n)
{
destroyContact(c);
exit(0);
}
else if( 2 == n )
{
return;
}
else
{
printf("Error ! \n");
}
}
}
以下对部分代码做简要分析:
在头文件中我们应该有一个表示联系人的结构体,如下所示:
//联系人结构体
typedef struct person{
char name[32];//姓名 性别 年龄 电话 地址
char sex[8];
unsigned char age;
char phone[16];
char adds[64];
}person_t, *person_p, **person_pp;
注意:我们给他typedef了三个名字,分别是结构体类型、结构体一级指针、结构体二级指针,定义指针的目的是在后面声明时避免写更多的 *
其次我们应该有一个通讯录的结构体,它里面应该保存联系人列表,当前长度以及容量,如下所示:
//通讯录结构体
typedef struct contact{
int cap;//容量
int size;//当前长度
person_p contactList;//联系人列表
}contact_t, *contact_p, **contact_pp;
在初始化传参时需要注意的问题:
void initContact(contact_pp c)
{
assert(c);
//申请通讯录空间
*c = (contact_p)malloc(sizeof(contact_t));
if(NULL == *c){
perror("malloc");
exit(1);
}
//申请成员空间
(*c)->contactList = (person_p)malloc(sizeof(person_t)*INITCAP);
if(NULL == (*c)->contactList){
perror("malloc");
exit(2);
}
//初始化长度和容量
(*c)->cap = INITCAP;
(*c)->size = 0;
fileLoad(*c);
}
注意:初始化传参时一定要使用二级指针,原因是:malloc返回一个指向所申请到的空间的指针,若使用一级指针传参,则申请到的空间将给形参,该形参在该函数结束时会释放,所以申请到的空间也将丢失,更重要的是,malloc申请到的空间需用free释放,然而你所申请到的空间已经丢失,也就没法释放了,这会造成严重的内存泄漏问题,在一个较大的工程中出现这样的问题是极其严重的,在你不知情的情况下,该程序一直吃你的内存,造成不可预知的后果。使用二级指针可以避免这样的问题,原因是:二级指针保存的是你一级指针的地址,通过二级指针我们可以访问到一级指针所指向的那片空间,这就类似于我们之前在交换两个数的内容时,使用一级指针(要交换的两个数的指针)传参一样。
文件操作——从文件读取信息
//从文件读取通讯录信息
int fileLoad(contact_p c)
{
FILE *fp;
person_t p;
int i = 0;
assert(c);
//打开文件
fp = fopen(FILE_NAME,"rb");
if(NULL == fp){
perror("fopen");
return -2;
}
while(1){
//读取到p
fread(&p, sizeof(person_t), 1, fp);
if(0 != feof(fp)){
break;
}
//将读取的添加到通讯录
addContact(c, &p);
}
fclose(fp);
return 0;
}
文件操作——将信息写入文件
//写入到文件
int fileStore(contact_p c)
{
FILE *fp;
int i = 0;
assert(c);
//打开文件
fp = fopen(FILE_NAME,"wb");
if(NULL == fp){
perror("fopen");
return -1;
}
//一次储存一个人大小的内容
for(; i<c->size; i++){
fwrite(c->contactList+i, sizeof(person_t), 1, fp);
}
fclose(fp);
return 0;
}
注意:几个文件操作函数,下面给出它的原型:
FILE *fopen( const char *filename, const char *mode );
filename为将要打开的文件的名字,mode为打开方式,“rb”:以二进制只读方式打开, “rw”:以二进制只写方式打开,它返回打开文件的地址。
size_t fwrite( const void *buffer, size_t size, size_tcount, FILE *stream );
buffer为被写入的内容,size为被写入信息的大小,count为写入信息的个数,stream为写入的文件,即该函数将buffer中的内容以size大小为单位,每次写入count个,写到stream中;
size_t fread( void *buffer, size_t size, size_t count, FILE *stream );
该函数与fwrite函数类似;
int feof( FILE *stream );
该函数从stream中读取内容,若读取到文件结尾,则返回一个非零值,否则返回0;
int fclose( FILE *stream );
通讯录在每次初始化完成后读取文件中的信息,每次释放通讯录前,将通讯录中的信息写到文件中,这样就完成了对联系人的保存。
总结:该通讯录使用c语言中基础的循环结构、选择结构,数组等知识,如:if()else; for(;;)switch()case :
还有结构体、内存管理、指针、文件操作等知识。
该通讯录是实现中肯定存在错误或者不完美的地方,欢迎大家讨论交流。 >_<
成于坚持,败于止步!
【作者:果冻 http://blog.csdn.net/jelly_9】