【C语言疯狂讲义】(十六)C语言简易通讯录(未优化版)

《通讯录》开发用到得知识点

常量、变量的使用

全局变量

分支语句

函数

循环语句

scanf和printf

数据

结构体

文件

指针*

《通讯录》中解决的经典问题

  1. 数组元素如何删除(不使用链表)

开发调试环境:Mac os x10.10 + xcode6.1

通讯录主界面:

添加联系人界面

删除联系人界面

修改联系人界面

搜索联系人

#include <stdio.h>
#include <string.h>
/****** 宏定义 *******/
#define NAME_LEN 21
#define TEL_LEN 12
#define N 1000

/****** 函数的声明 *******/
void doAdd();
void doDelete();
void doUpdate();
void doList();
void searchPersonByName();
void init();
void writeFile();

/****** 变量定义 *******/
typedef struct Linker{

    //联系人的姓名
    char name[NAME_LEN];
    //联系人电话
    char mobileNum[TEL_LEN];

}Person;

//定义联系人数组
Person contacts[N];
//定义一个变量,用于存放当前联系人的个数
int totalCount=0;
//文件路径的变量
char *filePath="telbook.data";

int main(int argc, const char * argv[]) {

    int flag = 1;
    int num =-1;

    //进行初始化
    init();
    printf("数据初始化成功!...\n");

    while (flag) {

        printf("**************************\n");
        printf("****** 欢迎使用通讯录 ******\n");
        printf("****** 1、添加联系人  ******\n");
        printf("****** 2、删除联系人  ******\n");
        printf("****** 3、修改联系人  ******\n");
        printf("****** 4、查看所有联系人 ****\n");
        printf("****** 5、搜索联系人  ******\n");
        printf("****** 6、退出系统    ******\n");
        printf("**************************\n\n");

        printf("请选择1-6之间的一个操作\n");
        scanf("%d",&num);
        if (num<=0 || num >6) {
            printf("非法输入\n");
        }else{

            //判断用户选择了哪个功能
            switch (num) {

                case 1:
                    doAdd();
                    break;
                case 2:
                    doDelete();
                    break;
                case 3:
                    doUpdate();
                    break;
                case 4:
                    doList();
                    break;
                case 5:
                    searchPersonByName();
                    break;
                case 6:
                    printf("正在退出系统...\n");
                    printf("退出完成!\n");
                    flag = 0;
                    break;

                default:
                    break;
            }

        }

    }

    return 0;
}

/**
 *  添加联系人
    思路:
    1)提示用户输入姓名和电话号码
    2)接收用户输入的内容
    3)保存到联系人数组
    4)写入到文件中
 */
void doAdd(){

    printf("您选择的是添加联系,请按提示操作\n");
    //1)提示用户输入姓名和电话号码
    printf("请输入联系人姓名:*联系人姓名不能有空格\n");
    //2)接收用户输入的内容
    // 0   0
    // 1   1 contacts[1]
    //3)保存到联系人数组
    scanf("%s",contacts[totalCount].name);
    printf("请输入联系人电话:*联系人电话不能有空格\n");
    scanf("%s",contacts[totalCount].mobileNum);

    //联系人的总数要+1
    totalCount++;

    //4)写入到文件中
    writeFile();

}
/**
 *  删除联系人的函数
    思路:
    1)让用户输入要删除的数据的编号
    2)判断编号是否合法
    3)让用户再次确认删除
    4)开始删除数组元素
    5)删除文件内容
 */
void doDelete(){

    printf("您选择的是删除联系,请按提示操作\n");
    doList();
    //1)让用户输入要删除的数据的编号
    int no;
    printf("请输入要删除的联系人的编号:\n");
    scanf("%d",&no);
    //2)判断编号是否合法
    if (no<=0 || no >totalCount) {
        printf("编号不存在!\n");
        return;
    }
    //3)让用户再次确认删除
    int no1;
    printf("请再次确认要删除的信息: 0.取消   1.确定\n");
    scanf("%d",&no1);

    if (no1) {
        //4)开始删除数组元素
        //   1)删除的元素是数组的最后一个元素
        if (no==totalCount) {
            totalCount --;
        }else{
        //   2) 删除的不是最后一个元素

            for (int i=no; i<totalCount; i++) {
                //后一个元素覆盖前一个元素
                contacts[no-1] = contacts[no];

            }

            totalCount--;
        //5)删除文件内容
            writeFile();
        }
    }

}
/**
 *  更新联系人信息
    思路:
    1)提示输入要修改的联系人编号
    2)判断编号是否合法
    3)让用户输入新的姓名、电话
    4)让用户再次确认修改
    5)开始修改用户信息
    6)更新到文件中

 */
void doUpdate(){

    printf("您选择的是修改联系人,请按提示操作\n");

    doList();
    //1)让用户输入要修改的数据的编号
    int no;
    printf("请输入要修改的联系人的编号:\n");
    scanf("%d",&no);
    //2)判断编号是否合法
    if (no<=0 || no >totalCount) {
        printf("编号不存在!\n");
        return;
    }
    //3)让用户输入新的姓名和电话号码
    char name[NAME_LEN];
    char tel[TEL_LEN];
    printf("请输入新的用户名:\n");
    scanf("%s",name);
    printf("请输入新的电话号码:\n");
    scanf("%s",tel);

    //4)让用户再次确认修改
    int no1;
    printf("请再次确认要修改的信息: 0.取消   1.确定\n");
    scanf("%d",&no1);

    if (no1) {
    //5)开始修改用户信息

        strcpy(contacts[no-1].name, name);
        strcpy(contacts[no-1].mobileNum, tel);

    //6)更新到文件中
        writeFile();

    }
}

/**
 *  查看所有的联系人
    思路:
    1)先判断联系人是否为空
    2)如果不为空,遍历数组,显示所有的联系人
 */
void doList(){

    if (totalCount==0) {

        printf("您的通讯录还空无一人!\n");

    }else{
        printf("所有的联系人信息如下:\n");
        printf("编号\t姓名\t\t电话\n");
        for (int i=0; i<totalCount; i++) {
            printf("%d\t%s\t\t%s\n",i+1,contacts[i].name,contacts[i].mobileNum);
        }

    }

    printf("\n");
}

/**
 *  根据联系人的姓名查找联系人
    思路:
    1)提示用户输入要查找的人的姓名
    2)遍历联系人数组,查找有没有这个人
    3)查找到了,把电话号码显示出来
    4)没有查找到,提示没有这个联系人
 */
void searchPersonByName(){

     printf("您选择的是搜索联系人,请按提示操作:\n");
     char name[NAME_LEN];
    //1)提示用户输入要查找的人的姓名

    printf("请输入要查找的用户名:\n");
    scanf("%s",name);
    int i;
    //2)遍历联系人数组,查找有没有这个人
    for (i=0; i<totalCount; i++) {

        //3)查找到了,把电话号码显示出来
        if (strcmp(contacts[i].name, name)==0) {
            printf("您查找的 %s 的电话号码是:%s\n",contacts[i].name,contacts[i].mobileNum);
            //停止循环
            break;
        }
    }

    //4)没有查找到,提示没有这个联系人
    if (i==totalCount) {
        printf("你的通讯录没有这个人!\n");
    }

    printf("\n");

}

/**
   初始化方法,用于初始化数据
   思路:
   1)尝试性的读取文件
   2)如果成功了,说明文件存在,则读取文件内容
   3)不成功,说明文件不存在,
       1)创建文件
       2)写入联系人数量

 */
void init(){

    //读取数据文件
    FILE *fp = fopen(filePath, "rb");

    if (fp!=NULL) {

        //读取到,fread读文件到数组中
        //printf("通讯录文件已经存在!\n");

        //先读取联系人的个数
        fread(&totalCount, sizeof(int), 1, fp);
//        printf("totalCount = %d",totalCount);
        for (int i=0; i<totalCount; i++) {
            //循环读取每一块数据
            fread(&contacts[i], sizeof(Person), 1, fp);
        }

    }else{

        //不存在,创建文件
        fp = fopen(filePath, "w");
        //当前联系人的数量保存到文件中
//        int count=1;
        //                4         1
        fwrite(&totalCount, sizeof(int), 1, fp);

        printf("通讯录文件创建成功!\n");
    }

    fclose(fp);
}
/**
 *  普通的写文件操作(把联系人写入到文件中)
    思路:
    1)先写联系人的长度,占用的时文件的头4个字节
    2)然后遍历数组,把数组的每一个元素都写入到文件中
 */
void writeFile(){

    FILE *fp = fopen(filePath, "wb");
    if (fp!=NULL) {
        // 1)先写联系人的长度,占用的时文件的头4个字节
        fwrite(&totalCount, sizeof(int), 1, fp);
        // 2)然后遍历数组,把数组的每一个元素都写入到文件中
        for (int i=0; i<totalCount; i++) {
            fwrite(&contacts[i], sizeof(Person), 1, fp);
        }

        printf("文件更新成功!\n");
    }

    fclose(fp);

}
时间: 2024-07-30 19:51:18

【C语言疯狂讲义】(十六)C语言简易通讯录(未优化版)的相关文章

苹果新的编程语言 Swift 语言进阶(十六)--泛化

泛化允许你定义一个宽松.可重用的函数或者类型,使用泛化能够避免代码的重复,也能以更清楚和抽象的方式来表达程序的意图. 泛化是Swift语言提供的强大功能之一,Swift提供的许多标准库都使用了泛化来创建,如Swift提供的数组和词典类型.通过使用泛化,你能使用一个数组和词典来包含和存储任何类型的元素. 1.1 泛化函数 使用Swift语言你能定义一个可以工作于任意类型的泛化函数,从而不必为每种类型都定义一个具有相同功能的函数,这样就可以大大减少代码的重复. 如对一个实现任意类型值交换(swap)

【C语言疯狂讲义】(七)C语言进制转换

1.计算机中的进制 2进制:逢二进1      0  1 8进制:逢八进1      0  1   2  3  4  5  6  7 10进制:逢十进1  默认的进制  0 - 9 16进制:逢十六进1   0 - 9  A B C D E F      (内存的地址格式) 2.进制的转换问题 三个要素: 数位(0-7). 基数(每一位能取值的个数). 位权(数码*基数^数位).    101 = 1*2^0+0*2^1+1*2^2 数码(每一位设置) 转换:有得时候转换为人能识别的数制,要操作

【C语言疯狂讲义】(十六)C语言文件操作

1.文件的基本概念 存储外部介质上得数据集,数据集有一个名称就是文件名 文件的分类: 1)用户角度:普通文件和设备文件 2)存储的内容: ascii文件(文本文件): 存储的流程:根据文本找到其对应的ascii码值---->转为二进制--> 写到文件中 读取流程: 二进制-->10进制-->找对应的字符-->显示出来 二进制文件: 二进制数据的存取 文件的操作流程: 1)导入头文件  stdio.h 2) 定义文件指针 3)打开文件 4)操作文件 5)关闭文件 文件操作原理

区块链技术语言(二十六)——Go语言异常处理

任何编程语言的学习都要考虑错误处理.早期的语言,比如C语言中的errno,不是语言规范的一部分,通常只作为一种编程范式存在.但C++语言从语言层面上增加错误处理的支持,比如异常的概念和try-catch关键字的引入.而Go语言最大的亮点之一就是拥有漂亮的错误处理规范. 一.error error是Go语言内建的接口类型,它是错误处理的标准模式,定义如下: 在Go语言中,生成err值的方法有三种方式:通过errors包的New函数获得error类型的值,采用fmt.Errof 将string信息转

苹果新的编程语言 Swift 语言进阶(十六)--泛型

? ? ? ? ??? ?泛型同意你定义一个宽松.可重用的函数或者类型.使用泛型能够避免代码的反复.也能以更清楚和抽象的方式来表达程序的意图. ? ? ? ? ? ?泛型是Swift语言提供的强大功能之中的一个,Swift提供的很多标准库都使用了泛型来创建,如Swift提供的数组和词典类型. 通过使用泛型,你能使用一个数组和词典来包括和存储不论什么类型的元素. ?? ? 1.1 泛型函数 ?? ? ? ? ? 使用Swift语言你能定义一个能够工作于随意类型的泛型函数.从而不必为每种类型都定义一

李刚OC语言疯狂讲义笔记

设计一个”学生“类1> 属性* 姓名* 生日用结构体作为类的实例变量(生日) #import <Foundation/Foundation.h> //定义生日的结构体 typedef struct{ int year; int month; int day; }MyDate; @interface Person : NSObject { @public NSString *_name;//定义姓名 MyDate _birthday;//定义生日 } @end @implementatio

【C语言疯狂讲义】(八)C语言一维数组

1.数组的基本概念: 相同类型    若干个     有序 由若干个相同类型的数据组成的有序的集合 有序:存储地址连续 下标连续 数组名:用来存放数组首地址的变量 数组元素:构成数组的每一个数据 数组的下标:给数组的每一个元素做一个编号 数组的长度:构成数组的数据的个数 2.一维数组的定义 数组的使用的流程:先定义   ---> 初始化   --->使用 数组定义完成后,如果不初始化里面存放的时垃圾值 格式:int arr[10]; 定义长度为10的整型数组,每个都是Int型的,数组的名称 a

【C语言疯狂讲义】(九)C语言指针(一)

1.什么是地址? 内存是由若干个1个字节的内存单元组成的存储器 计算机为了管理内存单元,给每个字节都进行编号 编号的就是地址 2.什么是指针? 地址就是指针 地址: 地址指向的内存单元值:编号对应的存储内容 变量访问的方法:直接访问    间接访问 1)直接访问:用变量名访问其代表的存储空间 2)间接访问:通过内存地址访问地址所对应的存储单元的内容 3.指针和变量之间的关系 指针可以间接的访问变量的值 1)指针变量:就是用来存放地址的变量 指针变量也遵守变量使用的规则 :先定义  --->初始化

【C语言疯狂讲义】(三)C语言运算符

1.运算符: 连接两个操作数(常量.变量)的符号 用运算符按照一定的规则连接的式子称为表达式 运算符的分类: 1)操作数的个数: 单目运算(++     sizeof    !) 双目运算符:.... 三目运算符:  ?: 2) 功能: 算术运算符.关系和逻辑运算.位运算 2.算术运算符 1)什么东西? 进行算术的运算,总计5个 +  -  *  /  % 双目运算符 a+b   a*3   b/5    10%3 2)优先级 * /   3 + -   4 乘除的优先级要高于加减的 3)结合性