C语言-《通讯录》
黑白的通讯录
--1-- 需求分析 1.1 需求 1.2 原型展示 1.3 功能分析 --2-- 代码实现 2.1 外部声明、变量、宏 2.2 模块实现 -----------------------------【写在开头:】
『UI界面习惯了,用一个命令行版的通讯录也蛮好的...』
--1-- 需求分析
1.1 需求
实现简单计算器的计算功能,用命令行的方式选择具体的操作
1.2 原型展示
欢迎界面:
1)添加联系人:
2)删除联系人:
3)修改联系人:
4)查看联系人:
5)搜索联系人:
数据库文件:
1.3 功能分析
按照原型编写相应的流程功能。
/**
分析:
0、初始化
初始化方法,用于初始化数据
思路:
1)尝试性的读取文件
2)如果成功了,说明文件存在,则读取文件内容
3)不成功,说明文件不存在
1)创建文件
2)写入联系人数量
1、添加联系人
思路:
1)提示用户输入姓名和电话号码
2)接收用户输入的内容
3)保存到联系人数组
4)写入到文件中
2、删除联系人
思路:
1)让用户输入要删除的数据的编号
2)判断编号是否合法
3)让用户再次确认删除
4)开始删除数组元素
5)删除文件的内容
3、修改联系人
更新联系人信息
思路:
1)提示用户输入要删除联系人的编号
2)判断编号是否合法
3)让用户再次确认修改
4)开始修改用户信息
5)更新到文件中
4、查看联系人
查看所有联系人
思路:
1)先判断联系人是否为空
2)如果不为空,则遍历数组,列出所有的联系人
5、搜索联系人
根据输入的姓名查找联系人
思路:
1)提示用户要输入查找的人的姓名
2)遍历联系人数组,查找是否有这个人
3)如果找到,就把电话号码显示出来
4)没有找到,则显示没有该联系人信息
6、退出系统
*/
用到的知识点:
常量、变量的使用;全局变量;数组;分支语句;函数;宏;循环语句;scanf和printf;数据;结构体;文件操作;指针*。
难点:
数组元素的删除(可变数组,如果使用链表会更优)。
--2-- 代码实现
2.1 外部声明、变量、宏
需定义的宏
//******宏定义
#define N 100 //联系人数组的长度
#define NAMELEN 13 //姓名长度
#define NUMLEN 12 //手机号长度
//**********
全局变量
//******定义变量
int inputNum; //接收键盘输入
int telCount; //联系人个数
int flag; //接收确认标记
char *telBook = "telNumBook.data"; //数据库文件
//****
函数声明
//*****函数声明
void doAdd();
void doDel();
void doEdit();
void doList();
void doSearch();
void startView();
int writeFile();
void init();
int validateInput(int num, int min, int max);
//********
联系人结构体
//******联系人结构体
typedef struct{
char telName[NAMELEN];
char telNum[NUMLEN];
}Person; Person contacts[N]; //联系人数组
//*********
2.2 模块实现
1)添加联系人模块
/**
* 添加联系人
*/
void doAdd(){
printf("您选择了添加联系人操作\n");
printf("请输入要添加的联系人的姓名:(*注意联系人姓名中间不能有空格)\n");
scanf("%s", contacts[telCount].telName); //存入数组 printf("请输入要添加的联系人的电话号码:(*注意联系人电话号码中间不能有空格)\n");
scanf("%s", contacts[telCount].telNum); //提示确认
printf("是否确认添加\"%s\"联系人? 1.确认 0.取消\n", contacts[telCount].telName);
scanf("%d", &flag);
if (flag) {
//联系人个数+1
telCount++;
//写入文件中
writeFile(); printf("\n");
} }
2)删除联系人模块
/**
* 删除联系人
*/
void doDel(){
printf("您当前选择的是删除联系人操作\n");
doList();
printf("请输入要删除的联系人编号:\n"); scanf("%d", &inputNum);
if (validateInput(inputNum, , telCount)){
//非法输入则返回
return;
} else{
printf("数据删除后将不可恢复,您是否确认要删除\"%s\"的信息? 1.确认 0.取消\n",
contacts[inputNum - ].telName);
scanf("%d", &flag);
if (flag) {
if (inputNum == telCount){ //要删除的是最后一个元素
telCount--;
} else{ //不是最后一个元素,则要移动数组元素的位置
for (int i = inputNum; i < telCount; i++){
contacts[inputNum - ] = contacts[inputNum];
telCount--; //联系人-1
}
}
//写入文件
writeFile();
}
} }
3)修改联系人模块
/**
* 编辑联系人
*/
void doEdit(){
printf("您选择了修改联系人操作\n"); doList();
printf("请输入要修改的联系人的编号:\n");
scanf("%d", &inputNum); //定义临时数组保存新联系人的姓名和电话,不直接修改数组
char tempName[NAMELEN];
char tempTelNum[NUMLEN];
if (validateInput(inputNum, , telCount)) {
return;
} else{
printf("您是否确认要修改联系人\"%s\"的信息? 1.确认 0.取消",
contacts[inputNum - ].telName);
scanf("%d", &flag); if (flag) {
printf("请输入新的联系人姓名:(*注意姓名中间不能有空格)\n");
scanf("%s", tempName);
printf("请输入新的联系人电话号码:(*注意电话号码中间不能有空格)\n");
scanf("%s", tempTelNum); //更新数组信息
strcpy(contacts[inputNum - ].telName, tempName);
strcpy(contacts[inputNum - ].telNum, tempTelNum); //保存入文件
writeFile(); }
} }
4)查看联系人模块
/**
* 显示联系人
*/
void doList(){
if (telCount == ) {
printf("您的当前的联系人为空,请先添加小伙伴哟~~\n");
return;
}
printf("当前联系人列表:\n");
for (int i = ; i < telCount; i++) {
printf("编号%d 姓名: %s, 电话号码: %s\n", i + , contacts[i].telName, contacts[i].telNum);
}
}
5)搜索联系人模块
/**
* 搜索联系人
*/
void doSearch(){
printf("您当前选择的是搜索联系人操作\n"); doList();
char tempName[NAMELEN]; //临时数组
printf("请输入要查找的联系人姓名:\n");
scanf("%s",tempName); int i;
for (i = ; i < telCount; i++) {
if (strcmp(tempName, contacts[i].telName) == ){
printf("您搜索的联系人\"%s\"的电话号码是%s\n", contacts[i].telName, contacts[i].telNum);
break; //找到则循环终止
}
}
//循环一遍还没有找到
if (i == telCount){
printf("抱歉!没有找到\"%s\"的记录信息\n", tempName);
}
}
6)自定义校验非法数值及写入文件函数
/**
* 将数组和联系人个数写入文件
*
* @return 1 异常 0 正常
*/
int writeFile(){
//打开文件
FILE *fp = fopen(telBook, "wb"); //以二进制写入
if (fp != NULL) {
//将联系人个数写入文件
fwrite(&telCount, sizeof(telCount), , fp);
//数组写入文件
for (int i = ; i < telCount; i++) {
fwrite(&contacts[i], sizeof(Person), , fp);
}
printf("数据更新成功!\n"); } else{
printf("数据写入失败!\n");
return ;
} //关闭指针
fclose(fp);
return ;
} /**
* 验证输入是否合法
*
* @param num 待验证的整数
* @param min 最小值
* @param max 最大值
*
* @return 0.合法 1.非法
*/
int validateInput(int num, int min, int max){
if (num >= min && num <= max) {
return ;
} else{
printf("非法输入!\n");
return ;
}
}
分析:
此处为什么一定要将联系人的个数telCount持久化?
因为如果联系人个数如果不持久化,那么每次程序重启后都读取不到联系人了,因为这里使用的是数组变量。所以注意此处一定要将联系人个数存入文件。
7)自定义初始化函数
/**
初始化
从文件读取联系人和数组
*/
void init(){ FILE *fp = fopen(telBook, "r"); //打开文件
if (fp != NULL) {
//从文件中读取联系人
fread(&telCount, sizeof(telCount), , fp);
//读取数组
for (int i = ; i < telCount; i++) {
fread(&contacts[i], sizeof(Person), , fp);
}
} else{ //如果没有文件,则创建
FILE *fp = fopen(telBook, "wr");
fwrite(telBook, sizeof(Person), , fp);
printf("通讯录创建成功~\n");
} //关闭指针
fclose(fp);
printf("通讯录初始化成功!~~\n"); }
分析:
为什么要有一个初始化的方法?
因为每次系统启动时都必须从文件中读取联系人数组和联系人个数。
8)主界面和主函数
/**
* 主界面
*/
void startView(){
printf("********************************\n");
printf("******** 欢迎使用C通讯录 ******\n");
printf("******** 1、添加联系人 ******\n");
printf("******** 2、删除联系人 ******\n");
printf("******** 3、修改联系人 ******\n");
printf("******** 4、查看所有联系人 ******\n");
printf("******** 5、搜索联系人 ******\n");
printf("******** 6、退出系统 ******\n");
printf("********************************\n");
printf("请选择1-6之间您要进行的操作\n");
} /**
* 主函数
*
* @param argc
* @param argv
*
* @return 0 程序正常退出
*/
int main(int argc, const char * argv[]) {
init();
while () {
startView();
scanf("%d", &inputNum);
switch (inputNum) {
case :
doAdd();
break;
case :
doDel();
break;
case :
doEdit();
break;
case :
doList();
break;
case :
doSearch();
break;
case :
printf("系统正在退出...\n");
printf("系统安全退出,感谢您再次使用\n");
return ;
default:
break;
}
}
return ;
}
【写在结尾:】
『有那么一个时候,真的好想说一声,对不起,谢谢』
C语言-《通讯录》的更多相关文章
- c语言:<tchar.h>
头文件“<tchar.h>”作用就是为了进行ASCII码和UNICODE(wide-character)码的头文件(该头文件由微软提供): 这样我们就可以使用TCHAR.H头文件中的定义的 ...
- 如何使用微软提供的TCHAR.H头文件?
转载:https://www.cnblogs.com/flyingspark/archive/2012/03/16/2399788.html 如何使用微软提供的TCHAR.H头文件? 如果你现在写的代 ...
- C语言math.h库函数中atan与atan2的区别
源: C语言math.h库函数中atan与atan2的区别 C语言中的atan和atan2
- c语言string.h和memory.h某些函数重复问题
在C语言中,为了使用memset()函数,你是选择#include <string.h>还是<memory.h>?两个都可以,如何选择? <string.h>,标准 ...
- C语言string.h中常用字符函数介绍
原文:http://www.cnblogs.com/xuwenmin888/archive/2013/05/03/3057883.html strcpy 函数名: strcpy 功 能: 拷贝一个字符 ...
- C语言ctype.h字符函数和字符串
ctype.h存的是与字符相关的函数: 这些函数虽然不能处理整个字符串,但是可以处理字符串中的字符: ToUpper()函数,利用toupper()函数处理字符串中的每个字符,转换成大写: Punct ...
- C语言函数--H
函数名: harderr 功 能: 建立一个硬件错误处理程序 用 法: void harderr(int (*fptr)()); 程序例: /*This program will trap disk ...
- C语言conio.h部分解释
#include <conio.h> int getch(void);// 从控制台得到下一个字符,以ASCII值返回,并不在屏幕显示该字符 int getche(void);// 从控制 ...
- C语言——stdio.h
int fgetc(FILE * stream); get character from stream 返回流中的一个字符,并以int的类型返回,如果碰到文件的结尾,或者一个错误发生,函数返回 ...
- C语言string.h常用函数总结
void *memcpy(void *dest, const void *src, size_t n); 从源src所指的内存地址的起始位置开始拷贝n个字节到目标dest所指的内存地址的起始位置中. ...
随机推荐
- Thinking in Java——笔记(18)
I/O The original byte-oriented library was supplemented with char-oriented, Unicode-based I/O classe ...
- .Net深复制、浅复制
在.Net,大家都知道引用类型的深复制.浅复制吧. ,一般int等值类型是值类型(复制时是直接传值),一般的类(List<T>,Class)是引用类型(复制时传地址),默认是浅复制.若ob ...
- JAVA中使用FTPClient上传下载
Java中使用FTPClient上传下载 在JAVA程序中,经常需要和FTP打交道,比如向FTP服务器上传文件.下载文件,本文简单介绍如何利用jakarta commons中的FTPClient(在c ...
- 使用clearInterval清除计时循环时,最后一次循环还是会执行解决办法
原代码: var interv=setInterval(function(){ alert("setInterval执行"); },2000) clearInterval(inte ...
- 启用CentOS6.5 64位安装时自带的MySQL
#service mysqld start#cd /usr/bin#mysqladmin -u root password '123456'#./mysql -u root -pEnter passw ...
- VS工程添加资源文件
1. 添加资源文件: 2. 资源文件内写相应代码: <ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006 ...
- 上下箭头选中 选项事件 JS
//上下键 选择事件 searchBackgroud 为样式,只做标记,无实质样式,因为和其他样式不兼容,只能添加CSS $(document).keydown(function (event) { ...
- iOS获取当前AppStore版本号与更新
- (void)checkUpdateWithAppID:(NSString *)appID success:(void (^)(NSDictionary *resultDic , BOOL isNe ...
- lua table integer index 特性
table.maxn (table) Returns the largest positive numerical index of the given table, or zero if the t ...
- UE4入门与精通
由于目前在使用UE4引擎,多少也有一些心得,比如在日常使用中会遇到一些问题.坑(潜规则)或者一些使用技巧等.本人决定开一个大坑,主要有两个目的:一是可以自己做个记录,二是可以给大家提供一些参考吧.主要 ...