C语言实现一个简易通讯录

所属分类: 软件编程 / C 语言 阅读数: 146
收藏 0 赞 0 分享

本文实现一个通讯录,是基于C语言的IO文件操作、数据结构里面的顺序表实现。

具体功能

实现了

1、信息的添加
2、信息的显示
3、信息的修改(修改单一属性)
4、将内存中的信息保存到文件中去
5、将文件中的信息加载到内存中(每次程序运行数据就会丢失)
6、信息的删除
7、信息的查找(按照各自的属性查找)
8、给每一条信息设置了唯一的标识id
9、通讯录的销毁

头文件中的声明

在c语言中我们采用结构体来记录每一个人的具体信息
用顺序表的数据结构来来对数据的操作

#ifndef __ADDRESSBOOK_H__
#define __ADDRESSBOOK_H__

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

#define NAME_MAX 200 //名字
#define GENDER_MAX 100 // 性别
#define ADDRESS_MAX 200 // 地址
#define NUMBER_MAX 200 // 电话
#define SEQLIST_MAX 1000 // 存储的最大信息数量
#define FILE_PATH "address_book.txt" // 写入文件的位置

typedef struct person_inf
{ 
 char name[NAME_MAX];
 char gender[GENDER_MAX];
 char number[NUMBER_MAX];
 char address[ADDRESS_MAX];
}person_inf;

typedef struct address_book
{
 size_t size;
 person_inf data[SEQLIST_MAX];
}address_book;

//初始化通讯录
void address_book_init(address_book *book);

//添加信息
void address_book_add(address_book *book);

//显示信息
void address_book_display(address_book *book);

//删除所有信息
void address_book_delete_all(address_book *book);

//保存信息
void address_book_save(address_book *book);

//加载信息
void address_book_load(address_book *book);

//修改信息
void address_book_update(address_book *book);

//删除信息
void address_book_delete(address_book *book);

//查找信息
void address_book_find(address_book *book);

//销毁通讯录
void adderss_book_destory(address_book *book);

#endif

函数的定义

在这里我们实现了,基本的增删查改,保存信息加载信息。

#define _CRT_SECURE_NO_WARNINGS

#include "AddressBook.h"

//初始化通讯录
void address_book_init(address_book *book)
{
 if(book == NULL)
 {
  return ;
 }
 book->size = 0;
}

//添加信息
void address_book_add(address_book *book)
{
 size_t cur = 0;
 if(book == NULL)
 {
  printf("book is NULL\n");
  return ;
 }
 cur = book->size;
 ++book->size;
 printf("添加信息\n");
 printf("请输入要添加的姓名\n");
 scanf("%s",book->data[cur].name);
 printf("请输入要添加的性别\n");
 scanf("%s",book->data[cur].gender);
 printf("请输入要添加的电话\n");
 scanf("%s",book->data[cur].number);
 printf("请输入要添加的地址\n");
 scanf("%s",book->data[cur].address);
 printf("添加成功\n");
 return;
}

//显示信息
void address_book_display(address_book *book)
{
 size_t j = 0;
 if(book == NULL)
 {
  return ;
 }
 printf("序号\t\t姓名\t\t性别\t\t电话\t\t地址\n");
 for(j=0; j< book->size; j++)
 {
  printf("%u\t\t%s\t\t%s\t\t%s\t\t%s\n",j,book->data[j].name,
  book->data[j].gender,book->data[j].number,
  book->data[j].address);
 }
}

//保存信息
void address_book_save(address_book *book)
{
 size_t i = 0;
 FILE *fp = fopen(FILE_PATH,"w");
 if(book == NULL)
 {
  return ;
 }
 if(fp == NULL)
 {
  printf("打开文件失败\n");
  return ;
 }
 //fprintf(fp,"序号\t\t姓名\t\t性别\t\t电话\t\t地址\n");
 for(i=0; i< book->size; i++)
 {
  fprintf(fp,"%u\t\t%s\t\t%s\t\t%s\t\t%s\n",i,book->data[i].name,
  book->data[i].gender,book->data[i].number,
  book->data[i].address);
 }
 fclose(fp);
}

//加载信息
void address_book_load(address_book *book)
{
 size_t len = 0;
 size_t i = 0;
 FILE *fp = fopen(FILE_PATH,"r");

 if(book == NULL)
 {
  return ;
 }
 if(fp == NULL)
 {
  printf("打开文件失败\n");
  return ;
 }
 // 把光标移动到文件末尾
 fseek(fp,0,SEEK_END);
 // 从光标到文件首偏移的字节数
 len = ftell(fp);
 if(len == 0)
 {
  printf("通讯录为空\n\n");
  return ;
 }
 // rewind函数是将fp指针指向文件的开始
 rewind(fp);
 while(!feof(fp))
 {
  fscanf(fp,"%u\t\t%s\t\t%s\t\t%s\t\t%s\n",&i,book->data[book->size].name,//name是数组,在调用数组名时候降级为指针
   book->data[i].gender,book->data[book->size].number,
   book->data[book->size].address);
  i++;
  ++book->size;
 }
 fclose(fp);
}


//修改信息
void address_book_update(address_book *book)
{
 size_t i = 0;
 if(book == NULL)
 {
  return ;
 }
 printf("请输入要修改的编号\n");
 scanf("%u",&i);
 if(i > book->size || i < 0)
 {
  printf("输入为非法值\n");
  return ;
 }
 printf("修改信息\n");
 printf("姓名修改为\n");
 scanf("%s",book->data[i].name);
 printf("性别修改为\n");
 scanf("%s",book->data[i].gender);
 printf("修改电话为\n");
 scanf("%s",book->data[i].number);
 printf("地址修改为\n");
 scanf("%s",book->data[i].address);
 printf("修改成功\n");
 return ;
}


//删除信息
void address_book_delete(address_book *book)
{
 size_t i = 0;
 if(book == NULL)
 {
  return ;
 }
 printf("请输入要删除的编号\n");
 scanf("%u",&i);
 if(i > book->size)
 {
  printf("输入为非法值\n");
  return ;
 }
 while(i < book->size)
 {
  book->data[i] = book->data[i+1];
  i++;
 }
 book->size--;
 printf("删除成功\n");
 return;
}

//删除所有信息
void address_book_delete_all(address_book *book)
{
 if(book == NULL)
 {
  return ;
 }
 book->size = 0;
}

//查找信息
void address_book_find(address_book *book)
{
 int flag = 0;
 size_t i = 0;
 int choice = 0;
 char f_name[50];
 char f_number[50];
 if(book == NULL)
 {
  //book为空指针;
  return ;
 }
 printf("请输入要查找的方式\n");
 printf("************************\n");
 printf("*1.姓名查找 2.电话号查找\n");
 printf("************************\n");
 scanf("%d",&choice);
 if (choice == 1)
 {
  //姓名查找
  printf("请输入查找的姓名或者关键字\n");
  scanf("%s",f_name);
  printf("序号\t\t姓名\t\t性别\t\t电话\t\t地址\n");
  while(i < book->size)
  {
   if(strstr(book->data[i].name,f_name)) //用strstr函数来查关键字
   {
    flag = 1;
    printf("%u\t\t%s\t\t%s\t\t%s\t\t%s\n",i,book->data[i].name,
    book->data[i].gender,book->data[i].number,
    book->data[i].address);
   }
   i++;
  }
  if(flag == 0)
  printf("未查找到\n");
 }
 else if (choice == 2)
 {
  //电话号码查找
  printf("请输入查找的电话号或者关键号码\n");
  scanf("%s",f_number);
  printf("序号\t\t姓名\t\t性别\t\t电话\t\t地址\n");
  while(i < book->size)
  {
   if(strstr(book->data[i].number,f_number))
   {
    flag = 1;
    printf("%u\t\t%s\t\t%s\t\t%s\t\t%s\n",i,book->data[i].name,
    book->data[i].gender,book->data[i].number,
    book->data[i].address);
   }
   i++;
  }
  if(flag == 0)
  {
   printf("未查找到\n");
  }
 }
 else
 {
  printf("选择错误\n");
 }
}

/*fseek(fp,100L,0);把文件内部指针移动到离文件开头100字节处;
fseek(fp,100L,1);把文件内部指针移动到离文件当前位置100字节处;
fseek(fp,-100L,2);把文件内部指针退回到离文件结尾100字节处。

ftell(fp);利用函数 ftell() 也能方便地知道一个文件的长。
如以下语句序列: fseek(fp, 0L,SEEK_END); len =ftell(fp)+1; 
首先将文件的当前位置移到文件的末尾,然后调用函数ftell()获得当前
位置相对于文件首的位移,该位移值等于文件所含字节数。
*/

//销毁通讯录
void adderss_book_destory(address_book *book)
{
 FILE *fp = fopen(FILE_PATH,"w");
 if(book == NULL)
 {
  return ;
 }
 if(fp == NULL)
 {
  printf("打开文件失败\n");
  return ;
 }
 fseek(fp,0,SEEK_SET);
 rewind(fp);
 fclose(fp);
 printf("销毁成功\n");
}

主函数的实现(主要的框架)

实现是采用枚举来标识要使用哪种功能,其中要注意的是,我们在将程序运行起来时候就需要加载我们的以前文件中的信息。还有就是我们要在每次添加一条信息,或者删除,修改都需要保存,既内存中和IO文件中保存写入一次

enum
{
 EXIT,
 DISPLAY,
 ADD,
 UPDATE,
 Y_DELETE,
 FIND,
 DESTORY
};

//菜单
void menu()
{
 int choice = 0;
 address_book book;
 address_book_init(&book);
 address_book_load(&book);
 while(1)
 {
  printf("===============================\n");
  printf("1.显示通讯录\n");
  printf("2.添加\n");
  printf("3.修改\n");
  printf("4.删除\n");
  printf("5.查找\n");
  printf("6.销毁\n");
  printf("0.退出\n");
  printf("===============================\n");
  scanf("%d",&choice);
  system("cls");
  switch (choice)
  {
   case DISPLAY:
    address_book_display(&book);
    break;
   case ADD:
    address_book_add(&book);
    address_book_save(&book);
    break;
   case UPDATE:
    address_book_update(&book);
    address_book_save(&book);
    break;
   case Y_DELETE:
    address_book_delete(&book);
    address_book_save(&book);
    break;
   case FIND:
    address_book_find(&book);
    break;
   case DESTORY:
    adderss_book_destory(&book);
    address_book_delete_all(&book);
    break;
   case EXIT:
    return ;
    break;
   default:
    printf("输入值非法\n");
    break;
  }
 }

}

int main()
{
 menu();
 return 0;
}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

更多精彩内容其他人还在看

用标准c++实现string与各种类型之间的转换

这个类在头文件中定义, < sstream>库定义了三种类:istringstream、ostringstream和stringstream,分别用来进行流的输入、输出和输入输出操作。另外,每个类都有一个对应的宽字符集版本
收藏 0 赞 0 分享

C++如何通过ostringstream实现任意类型转string

再使用整型转string的时候感觉有点棘手,因为itoa不是标准C里面的,而且即便是有itoa,其他类型转string不是很方便。后来去网上找了一下,发现有一个好方法
收藏 0 赞 0 分享

C/C++指针小结

要搞清一个指针需要搞清指针的四方面的内容:指针的类型,指针所指向的类型,指针的值或者叫指针所指向的内存区,还有指针本身所占据的内存区
收藏 0 赞 0 分享

C++ 类的静态成员深入解析

在C++中类的静态成员变量和静态成员函数是个容易出错的地方,本文先通过几个例子来总结静态成员变量和成员函数使用规则,再给出一个实例来加深印象
收藏 0 赞 0 分享

C++类的静态成员初始化详细讲解

通常静态数据成员在类声明中声明,在包含类方法的文件中初始化.初始化时使用作用域操作符来指出静态成员所属的类.但如果静态成员是整型或是枚举型const,则可以在类声明中初始化
收藏 0 赞 0 分享

C++类静态成员与类静态成员函数详解

静态成员不可在类体内进行赋值,因为它是被所有该类的对象所共享的。你在一个对象里给它赋值,其他对象里的该成员也会发生变化。为了避免混乱,所以不可在类体内进行赋值
收藏 0 赞 0 分享

C++中的friend友元函数详细解析

友元可以是一个函数,该函数被称为友元函数;友元也可以是一个类,该类被称为友元类。友元函数的特点是能够访问类中的私有成员的非成员函数。友元函数从语法上看,它与普通函数一样,即在定义上和调用上与普通函数一样
收藏 0 赞 0 分享

static全局变量与普通的全局变量的区别详细解析

以下是对static全局变量与普通的全局变量的区别进行了详细的分析介绍,需要的朋友可以过来参考下,希望对大家有所帮助
收藏 0 赞 0 分享

C++ explicit关键字的应用方法详细讲解

C++ explicit关键字用来修饰类的构造函数,表明该构造函数是显式的,既然有"显式"那么必然就有"隐式",那么什么是显示而什么又是隐式的呢?下面就让我们一起来看看这方面的知识吧
收藏 0 赞 0 分享

教你5分钟轻松搞定内存字节对齐

随便google一下,人家就可以跟你解释的,一大堆的道理,我们没怎么多时间,讨论为何要对齐.直入主题,怎么判断内存对齐规则,sizeof的结果怎么来的,请牢记以下3条原则
收藏 0 赞 0 分享
查看更多