C语言课程设计之好友通讯录系统项目实现

好友通讯录系统项目实现

程序使用软件visual Studio 2022;

文章目录

  • 好友通讯录系统项目实现
  • 题目描述
  • 分析与设计
  • 代码实现


题目描述

建立一个通讯录,可以对通讯录中的好友信息进行增加、删除、修改、查找以及对通讯录中的好友信息进行显示打印,提高对好友通讯录的管理效率。

🍉知识目标:
(1)掌握模块化程序设计的方法;
(2)进一步掌握利用C语言进行程序设计的能力;
(3)进一步理解和运用结构化程序的设计的思想和方法
(4)学习和掌握C语言中的库函数及其应用。

🍉能力培养目标:
(1)能正确分析现实生活中的问题,进行模块分析和编程;
(2)在程序调试过程中,能根据运行环境给出的错误提示,正确解决程序中的语法错误;
(3)在程序调试过程中,能根据运行结果,运用相应的手段,正确地找出并解决程序中的逻辑错误;
(4)在课程设计过程中,适当进行小组分工,培养团队谐调和团队合作的能力;
(5)提交课程设计成果报告,培养专业文档书写的能力。

分析与设计

🍉Contact项目源文件说明:

  1. test.c 测试代码以及完成通讯录菜单界面的设计及调用
  2. contact.c 实现函数功能
  3. contact.h 声明函数

🍉Contact各个功能模块简要说明:
存放1000个好友的信息
名字、电话、性别、住址、年龄
1.增加好友信息
2.删除指定名字的好友信息
3.查找好友信息
4.修改好友信息
5.显示好友信息
6.对好友信息进行年龄排序
0.退出系统

🍉题目需求分析
程序的用途:该项目程序主要面向需要记录好友联系方式进行管理通讯录的人群。

通过该程序用户可以非常方便快捷的对自己通讯录里的好友信息进行管理,可以对通讯录里的好友信息进行增加、删除、修改、查找等操作以及对通讯录中的好友信息进行显示打印。程序主要处理的数据为好友的名字、电话、性别、住址、年龄。每种数据按照程序设计类型进行输入。

🍉总体设计
根据需求分析的结果,大题系统共设计六个功能模块:增加好友联系信息功能模块、删除好友联系信息功能模块、修改好友联系信息功能模块、查找好友联系信息功能模块、退出功能模块、显示好友联系信息模块。
系统模块图如下:

代码实现

contact.h

//#define是一个预处理器指令,用于创建宏定义。它允许程序员为常量值、表达式、函数等创建符号名称,使代码更易于阅读、理解和维护.
#pragma once
#define _CRT_SECURE_NO_WARNINGS 1
#define MAX 1000
#define MAX_NAME 20
#define MAX_SEX 5
#define MAX_TELE 12
#define MAX_ADDR 30
#include <stdio.h>
#include <string.h>
enum Option
{EXIT,ADD,DEL,SEARCH,MODIFY,SHOW,QSORT
};
struct PeoInfor
{char name[MAX_NAME];//名字int age;//年龄char sex[MAX_SEX];//性别 char tele[MAX_TELE];//电话char addr[MAX_ADDR];//地址
};
struct Contact
{struct  PeoInfor data[MAX];//存放一个信息int size;//记录当前已有的元素个数
};
//声明函数
//初始化通讯录
void InitContact(struct Contact* ps);
//添加一个好友信息到通讯录
void AddContact(struct Contact* ps);
//打印通讯录中的信息
//在结构体前使用 const 关键字可以创建一个只读(const-qualified)结构体。这表示结构体内的成员变量不能被修改。
void ShowContact(const struct Contact* ps);
//删除指定联系人
void DelContact(struct Contact* ps);
//查找指定的好友联系人信息
void SearchContact(const struct Contact* ps);
//修改联系人信息
void ModifyContact(struct Contact* ps);
//对好友联系人进行按年龄排序
void Qsort_Contact_age(struct Contact* ps);

contact.c

#define _CRT_SECURE_NO_WARNINGS 1
#include "contact.h"
//清空联系人结构体对象中的数据数组,并将联系人列表的元素个数初始化为 0。
// 这样做可以确保在创建联系人结构体对象时,它的数据成员得到适当的初始化,从而避免在使用时出现未初始化的值或者数据残留问题。
void InitContact(struct Contact* ps)
{memset(ps->data, 0, sizeof(ps->data));ps->size = 0;
};
//添加一个好友信息到通讯录
void AddContact(struct Contact* ps) {int age;FILE* file;if (ps->size == MAX) {printf("通讯录已满,无法增加");}else {file = fopen("D:\contacts.txt", "a");if (file == NULL) {file = fopen("D:\contacts.txt", "w");printf("无法打开文件");return;}printf("请输入名字:>");fscanf(stdin, "%s", ps->data[ps->size].name);printf("请输入年龄:>");fscanf(stdin, "%d", &(ps->data[ps->size].age));printf("请输入性别:>");fscanf(stdin, "%s", ps->data[ps->size].sex);printf("请输入电话:>");fscanf(stdin, "%s", ps->data[ps->size].tele);printf("请输入地址:>");fscanf(stdin, "%s", ps->data[ps->size].addr);fprintf(file, "%s %d %s %s %s\n", ps->data[ps->size].name, ps->data[ps->size].age, ps->data[ps->size].sex, ps->data[ps->size].tele, ps->data[ps->size].addr);ps->size++;printf("成功添加好友信息");fclose(file);}
}
//显示打印好友通讯录中的信息
void ShowContact(const struct Contact* ps)
{if (ps->size == 0)//判断通讯录中的好友数量信息是否为0{printf("该通讯录为空\n");}else{int i = 0;printf("%-20s\t%-4s\t%-5s\t%-12s\t%-20s\n", "名字", "年龄", "性别", "电话", "地址");for (i = 0; i < ps->size; i++){printf("%-20s\t%-4d\t%-5s\t%-12s\t%-20s\n", ps->data[i].name, ps->data[i].age, ps->data[i].sex, ps->data[i].tele, ps->data[i].addr);}}
}
//按名字进行查找,找到返回相应下标,找不到返回-1;
static int FindByName(const struct Contact* ps, char name[MAX_NAME])
{int i = 0;for (i = 0; i < ps->size; i++) {//strcmp 是一个字符串比较函数,用于比较两个字符串的大小关系 大于返回正数 小于返回负数 等于返回0if (0 == strcmp(ps->data[i].name, name)){return i;}}return -1;}
//删除指定联系人
void DelContact(struct Contact* ps)
{if (ps->size == 0){printf("该通讯录为空,不能进行删除操作\n");return 0;}char name[MAX_NAME];printf("请输入要删除人的名字:>");scanf("%s", name);//1.查找要删除的人在什么位置//找到了返回名字所在的下标,//找不到返回-1int pos = FindByName(ps, name);//2.删除if (pos == -1)printf("要删除的人不存在!\n");else{int j = 0;for (j = pos; j < ps->size - 1; j++){ps->data[j] = ps->data[j + 1];}int u=ps->size--;FILE* file = fopen("D:\contacts.txt", "w");if (file != NULL) {for (int i = 0; i < u-1; i++) {fprintf(file, "%s %d %s %s %s\n", ps->data[i].name, ps->data[i].age, ps->data[i].sex, ps->data[i].tele, ps->data[i].addr);	}fclose(file);}else {printf("无法打开文件");}printf("删除成功\n");}
}
//查找指定的好友联系人信息
void SearchContact(const struct Contact* ps)
{if (ps->size == 0){printf("该表为空,无法进行搜索\n");return 0;}char name[MAX_NAME];printf("请输入要查找人的名字:>");scanf("%s", name);int pos = FindByName(ps, name);if (pos == -1) {printf("要查找的人不存在!\n");}else{printf("%-20s\t%-4s\t%-5s\t%-12s\t%-20s\n", "名字", "年龄", "性别", "电话", "地址");printf("%-20s\t%-4d\t%-5s\t%-12s\t%-20s\n", ps->data[pos].name, ps->data[pos].age, ps->data[pos].sex, ps->data[pos].tele, ps->data[pos].addr);}}
//修改指定的好友联系人信息
void ModifyContact(struct Contact* ps)
{if (ps->size == 0){printf("该通讯录为空,不能进行修改操作\n");return 0;}char name[MAX_NAME];printf("请输入要修改人的名字:>");scanf("%s", name);int pos = FindByName(ps, name);if (pos == -1){printf("要修改人的信息不存在!\n");}else {printf("请输入名字:>");scanf("%s", ps->data[pos].name);printf("请输入年龄:>");scanf("%d", &(ps->data[pos].age));printf("请输入性别:>");scanf("%s", ps->data[pos].sex);printf("请输入电话:>");scanf("%s", ps->data[pos].tele);printf("请输入地址:>");scanf("%s", ps->data[pos].addr);printf("修改成功\n");}int u = ps->size;FILE* file = fopen("D:\contacts.txt", "w");if (file != NULL) {for (int i = 0; i < u ; i++) {fprintf(file, "%s %d %s %s %s\n", ps->data[i].name, ps->data[i].age, ps->data[i].sex, ps->data[i].tele, ps->data[i].addr);}fclose(file);}else {printf("无法打开文件");}}
//qsort 是C语言标准库 <stdlib.h> 中的一个函数,用于对数组进行快速排序。它可以对数组中的元素按照指定的比较函数进行排序。
//void* 是 C 语言中的一种特殊类型,代表指向未知类型的指针。void* 类型的指针可以指向任何类型的数据,因为它是一个通用类型指针,不关心它指向的数据的具体类型。
// const void* 表示指向常量数据的 void* 类型指针。函数在使用这些指针时不能修改它们所指向的数据。
//利用Qsort函数实现对结构体数据按照年龄排序
static int cmp_stc_by_age(const void* e1, const void* e2)
{return ((struct Contact*)e1)->data->age - ((struct Contact*)e2)->data->age;
}
void Qsort_Contact_age(struct Contact* ps)
{if (ps->size == 0)//判断通讯录中的好友数量信息是否为0{printf("该通讯录为空,无法进行排序\n");}else {//qsort四个参数含义:ps为待排序数组的起始地址    ps->size数组中元素的个数  sizeof(ps->data[0])为数组中每个元素的大小(以字节为单位)//cmp_stc_by_age用于返回确认元素顺序的比较函数的指针//比较函数cmp_stc_by_age应当接受两个 const void * 类型的参数,指向待比较的元素。该函数应当返回一个整数值来表示两个元素的大小关系://若返回值小于 0,表示第一个参数小于第二个参数;//若返回值等于 0,表示两个参数相等;//若返回值大于 0,表示第一个参数大于第二个参数。qsort(ps, ps->size, sizeof(ps->data[0]), cmp_stc_by_age);int i = 0;printf("%-20s\t%-4s\t%-5s\t%-12s\t%-20s\n", "名字", "年龄", "性别", "电话", "地址");for (i = 0; i < ps->size; i++){printf("%-20s\t%-4d\t%-5s\t%-12s\t%-20s\n", ps->data[i].name, ps->data[i].age, ps->data[i].sex, ps->data[i].tele, ps->data[i].addr);}}
}

test.c

//#define _CRT_SECURE_NO_WARNINGS 1
#include "contact.h"void menu() {printf("********************************************\n");printf("*********1.add                2.del**********\n");printf("*********3.search           4.modify************\n");printf("*********5.show             6.qsort**************\n");printf("********************0.exit********************\n");printf("********************************************\n");
}
int main()
{int input = 0;int size = 0;//创建通讯录struct Contact con;//con就是通讯录,里面包含:1000的元素的通讯录信息和size;InitContact(&con);do{menu();printf("请选择:>");scanf("%d", &input);switch (input){case ADD:AddContact(&con);break;case DEL:DelContact(&con);break;case SEARCH:SearchContact(&con);break;case MODIFY:ModifyContact(&con);break;case SHOW:ShowContact(&con);break;case QSORT:Qsort_Contact_age(&con);break;case EXIT:printf("退出通讯录\n");break;default:printf("选择错误\n");break;}} while (input);return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/614482.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

软件测试|解析selenium.common.exceptions.ElementClickInterceptedException错误及解决方法

导言 在自动化测试中&#xff0c;Selenium是一个广泛使用的工具&#xff0c;用于模拟用户在网页上的操作。然而&#xff0c;有时候在执行点击操作时&#xff0c;可能会遇到ElementClickInterceptedException异常&#xff0c;这可能是由于多种原因导致的。本文将深入探讨这个错…

【算法练习】leetcode算法题合集之数组和哈希表篇

重建数组&#xff08;高频&#xff09; LeetCode283.移动零 LeetCode283.移动零 双指针&#xff0c;记录已经处理好的序列的尾部 class Solution {public void moveZeroes(int[] nums) {int k 0;for (int i 0; i < nums.length; i) {if (nums[i] ! 0) {swap(nums, i, k)…

JavaScript 异步编程解决方案-上篇

1、JavaScript 异步编程 1、传统的方案 :JavaScript 中的异步操作函数往往通过回调函数来实现异步任务的结果处理 场景:fs 文件操作 数据库操作 AJAX 定时器 eg: 1、setTimeout 函数 //异步回掉,通过函数回调解决function printInfo() {document.getElementsByTagName(d…

Kafka的简介及架构

目录 消息队列 产生背景 消息队列介绍 常见的消息队列产品 应用场景 消息队列的消息模型 Kafka的基本介绍 简介 Kafka的架构 Kafka的使用 Kafka的shell命令 Kafka的Python API的操作 完成生产者代码 完成消费者代码 消息队列 产生背景 消息队列:指数据在一个容器…

Linux学习记录——삼십팔 网络层IP协议

文章目录 1、了解IP协议2、IP协议报文1、8位服务类型2、16位总长度&#xff08;字节数&#xff09;3、8位生存时间&#xff08;TTL&#xff09; 3、网段划分1、网段划分和CIDR方案2、子网划分简单方法3、IP地址问题的解决方案 4、公网内网1、内网分配2、运营商管理方法 5、路由…

【Python基础】一文搞懂:Python 中 Excel 文件的写入与读取

文章目录 1 引言2 使用 openpyxl2.1 安装 openpyxl2.2 写入 Excel 文件2.3 读取 Excel 文件 3 使用 pandas3.1 安装 pandas 和 openpyxl3.2 写入 Excel 文件3.3 读取 Excel 文件 4 实例演示4.1 安装所需库4.2 封装为excel_example.py脚本文件 5 注意事项6 总结 1 引言 在现代办…

spring-boot项目启动类错误: 找不到或无法加载主类 com.**Application

问题&#xff1a;Springboot项目启动报错&#xff1a;错误: 找不到或无法加载主类 com.**Application 解决步骤&#xff1a; 1.File–>Project Structure 2.Modules–>选中你的项目–点击“-”移除 3.重新导入&#xff1a;点击“”号&#xff0c;选择Import Module&…

【漏洞复现】优卡特脸爱云一脸通智慧管理平台文件上传漏洞

Nx01 产品简介 脸爱云一脸通智慧管理平台是一套功能强大&#xff0c;运行稳定&#xff0c;操作简单方便&#xff0c;用户界面美观&#xff0c;轻松统计数据的一脸通系统。无需安装&#xff0c;只需在后台配置即可在浏览器登录。 功能包括&#xff1a;系统管理中心、人员信息管…

【react-quill】富文本编辑器空格回显无效

<ReactQuilltheme"snow"id{id}ref{(el:any) > {if (el) {reactQuillRef.current el;}}}modules{modules}formats{formats}value{value}onChange{onChange}onBlur{onBlur}className"ql-editor"/> 关键&#xff1a; className"ql-editor&quo…

GPT 商店强势来袭,人人都要有自己的 GPTs

作者&#xff1a;苍何&#xff0c;前大厂高级 Java 工程师&#xff0c;阿里云专家博主&#xff0c;CSDN 2023 年 实力新星&#xff0c;土木转码&#xff0c;现任部门技术 leader&#xff0c;专注于互联网技术分享&#xff0c;职场经验分享。 &#x1f525;热门文章推荐&#xf…

网络基础学习(3):交换机

1.交换机结构 &#xff08;1&#xff09;网线接口和后面的电路部分加在一起称为一个端口&#xff0c;也就是说交换机的一个端口就相当于计算机上的一块网卡。 如果在计算机上安装多个网卡&#xff0c;并让网卡接收所有网络包&#xff0c;再安装具备交换机功能的软件&#xff0…

ORB SLAM2 编译

文章目录 软件版本编译编译自动编译手动编译 软件版本 Pangolin0.6opencv3.4.0 ORB SLAM2 编译 # 更改Opencv依赖版本与添加Pangolin依赖 # CMakelist.txt更改 LIST(APPEND CMAKE_PREFIX_PATH /usr/local/opencv-3.4) # 添加 LIST(APPEND CMAKE_PREFIX_PATH /usr/local/Pang…

数据加工:从原始数据到有价值的信息

在当今数字化的时代&#xff0c;数据已经成为了企业和组织最宝贵的资产之一。然而&#xff0c;原始数据往往需要经过加工和处理&#xff0c;才能转化为有价值的信息和知识。数据加工是指将原始数据进行处理和分析&#xff0c;以提取有用的信息和知识的过程。数据加工的重要性不…

springboot 集成kafka

1. SpringBoot快速集成Kafak_springboot集成kafaka-CSDN博客 2. kafka 启动&#xff1a;Windows系统下快速启动Kafka_windows启动kafka-CSDN博客 3.

idea 设置文件头

idea 设置创建文件时自动添加文档注释信息 /** * Description * Author jimaomao * DATE ${DATE} ${TIME} */

c# ==操作符和equals方法的区别

在C#中&#xff0c;""操作符和Equals()方法有着不同的用途和行为。 ""操作符&#xff1a; "“操作符用于比较两个对象的值是否相等。当使用”"操作符比较两个引用类型的对象时&#xff0c;它会比较它们的引用是否指向相同的内存地址。对于值类…

【Kafka-3.x-教程】-【五】Kafka-监控-Eagle

【Kafka-3.x-教程】专栏&#xff1a; 【Kafka-3.x-教程】-【一】Kafka 概述、Kafka 快速入门 【Kafka-3.x-教程】-【二】Kafka-生产者-Producer 【Kafka-3.x-教程】-【三】Kafka-Broker、Kafka-Kraft 【Kafka-3.x-教程】-【四】Kafka-消费者-Consumer 【Kafka-3.x-教程】-【五…

React之自定义路由组件

开篇 react router功能很强大&#xff0c;可以根据路径配置对应容器组件。做到组件的局部刷新&#xff0c;接下来我会基于react实现一个简单的路由组件。 代码 自定义路由组件 import {useEffect, useState} from "react"; import React from react // 路由配置 e…

机器人领域顶刊TRO,TASE及RAL的区别与关系

一、背景 机器人领域越来越火&#xff0c;特别是具身智能的加持&#xff0c;让机器人在不久的未来可以完成更多复杂的任务&#xff0c;进入到我们的生活&#xff08;不过应该还需要很长时间&#xff09;。作为机器人方向的研究僧&#xff0c;我们会看到许多机器人期刊&#xf…

Semaphore信号量详解

在Java并发编程中&#xff0c;Semaphore是一个非常重要的工具类。它位于java.util.concurrent包中&#xff0c;为我们提供了一种限制对临界资源的访问的机制。你可以将其视为一个同步控制的瑞士军刀&#xff0c;因为它既能够控制对资源的并发访问数量&#xff0c;也能够保证资源…