c语言:通讯录管理系统(增删查改)

news2024/11/27 3:48:21

        前言:在大多数高校内,都是通过设计一个通讯录管理系统来作为c语言课程设计,通过一个具体的系统设计将我们学习过的结构体和函数等知识糅合起来,可以很好的锻炼学生的编程思维,本文旨在为通讯录管理系统的设计提供思路和示例讲解,并且将如何用代码实现进行了完整的展示

目录

一.大体的框架

主函数初步设计

联系人的数据结构设计

菜单目录

二.初始化通讯录内容

三.增加联系人

四.删除联系人信息

五.查询联系人信息

六.修改联系人的信息

完整代码 

Contct.h

Contact.cpp

test.cpp


一.大体的框架

我们分为 3 个文件来设计:

  • Contact.h: 包含头文件的声明,对函数的声明,以及宏的申明
  • Contact.cpp: 通讯录管理系统中具体每一个函数的实现
  • test.cpp: 主函数,根据用户的选择进行调用相应的函数

主函数初步设计

        主函数中,我们用 do...while... 来完成用户持续使用通讯录管理系统的需求,当用户不想再使用通讯录后只要输入 0 就可以结束 do...while... 循环从而结束整个程序

        后续编程中,我们只需要对各个输入的函数进行补充就可以了,同时在枚举类型 options 中从上往下是从 0 开始的赋值,这样更方便我们理解阅读,增强了程序的可读性

//枚举,增加程序的可读性
enum options
{
	EXIT,
	ADD,
	DEL,
	SEACH,
	MODIFY,
	SHOW
};

int main()
{
	int input = 0;
	//创建通讯录
	Contact con;
	//初始化通讯录
	InitContact(&con);

	do
	{
		menu();
		printf("请输入你的选择: ");
		scanf("%d", &input);

		switch (input)
		{
		//增加联系人信息
		case ADD:
			break;
		//删除联系人信息
		case DEL:
			break;
		//查找某个联系人的信息
		case SEACH:
			break;
		//修改某个联系人的信息
		case MODIFY:
			break;
		//展示通讯录内的每一个联系人的信息
		case SHOW:
			break;
		//退出通讯录管理系统
		case EXIT:
			printf("通讯录已退出\n");
			break;
		//预防非法输入
		default:
			printf("输入错误,请重新输入\n");
			break;
		}
	}while(input);

	return 0;
}

联系人的数据结构设计

        使用俩个结构体来完成我们设计的需求,一个结构体 PeopleInformation 用来保存每一个用户的各种信息,另一个结构体 Contact 用来保存整个通讯录的信息,而在通讯录的信息中就得包含每一个用户的信息,因此我们将 PeopleInformation结构体 嵌套在 结构体Contact

        使用宏定义来方便我们后续修改调整数据大小,同时也可以增加程序的可读性

#define Name_Max 20
#define Tel_Number 12
#define Sex_Max 5
#define Address_Max 30
#define Contact_Max 100

//联系人结构体
typedef struct PeopleInformation
{
	char name[Name_Max];
	char telnumber[Tel_Number];
	int age;
	char sex[Sex_Max];
	char address[Address_Max];
}PeoInfor;

//通讯录结构体
typedef struct Contact
{
	PeoInfor data[Contact_Max];//存放联系人结构体
	int size;//记录当前通讯录中有多少个联系人
}Contact;

菜单目录

剩下的就只有根据我们的菜单目录来设计每一个函数的具体实现了

void menu()
{
	printf("-----------------------------\n");
	printf("---   1.添加联系人      -----\n");
	printf("---   2.删除联系人      -----\n");
	printf("---   3.查找联系人      -----\n");
	printf("---   4.修改联系人信息  -----\n");
	printf("---   5.显示全部信息    -----\n");
	printf("---   0.退出通讯录      -----\n");
	printf("-----------------------------\n");
}

二.初始化通讯录内容

为了方便,我们将通讯录中每一个人的全部信息置 0

void InitContact(Contact* cp)
{
	//判断非空
	assert(cp);

	cp->size = 0;
	memset(cp->date, 0, sizeof(cp->date));
}

三.增加联系人

        在增加之前先进行判断,首先要判断传入的指针非空,其次要判断当前情况下通讯录是否已经满了,如果满了就告诉用户通讯录已满,如果没有满再进行添加新的联系人

接下来分别使用指针进行访问输入就可以了,这里我们通过添加联系人姓名进行举例讲解:

        首先,我们添加联系人的函数拿到的参数是一个指针,指向通讯录结构体,这个结构体中有俩个成员,一是我们要存放的数据,二是当前结构体有多少个联系人,那我们就需要利用这个指针在访问我们要存放是数据,所以是 cp->data 这样的操作使我们访问到了通讯录结构体的数据数组,然后我再根据数组的下标来访问每一个单独的联系人的数据

        在这里利用通讯录结构体中的第二个成员 cp->size 来帮助我们访问到数据数组中单个联系人的内容,在用 “ . ” 访问单个联系人的每一条成员变量,从而进行赋值操作

void AddContact(Contact* cp)
{
	//判断非空
	assert(cp);

	//判断未满
	if (cp->size == Contact_Max)
	{
		printf("通讯录已满,无法再添加新的联系人\n");
		return;
	}

	printf("请输入要添加的联系人的姓名:\n");
	scanf("%s", cp->data[cp->size].name);

	printf("请输入要添加的联系人的电话号:\n");
	scanf("%s", cp->data[cp->size].telnumber);

	printf("请输入要添加的联系人的年龄:\n");
	scanf("%d", &(cp->data[cp->size].age));

	printf("请输入要添加的联系人的性别:\n");
	scanf("%s", cp->data[cp->size].sex);

	printf("请输入要添加的联系人的住址:\n");
	scanf("%s", cp->data[cp->size].address);

	cp++;
	printf("添加成功\n");
}

四.删除联系人信息

        删除联系人之前我们首先需要做的就是查询到联系人,只有找到联系人后,才能完成删除的工作,因此,我们先封装一个函数通过联系人的姓名进行查找,对整个结构体数组遍历,然后使用 strcmp 函数来比较用户输入的名字和我们要查找的名字,这样就可以找出联系人,并且返回数组的下标,如果没有找到就返回 -1 

int FindPeople(Contact* cp, char name[])
{
	assert(cp);
	for (int i = 0; i < cp->size; i++)
	{
		if (strcmp(cp->data[i].name, name) == 0)
		{
			return i;
		}
	}
	return -1;
}

        找到要删除的元素的位置后,我们就将整个数组从后往前覆盖,这样就达到了删除联系人的信息的目的

void DelContact(Contact* cp)
{
	assert(cp);
	char name[Name_Max];
	if (cp->size == 0)
	{
		printf("通讯录为空,无需删除\n");
		return;
	}
	printf("请输入选择删除的联系人的姓名:\n");
	scanf("%s", name);
	int ret = FindPeople(cp, name);
	if (ret == -1)
	{
		printf("要删除的联系人不存在\n");
		return;
	}
	for (int i = ret; i < cp->size; i++)
	{
		cp->data[i] = cp->data[i + 1];
	}
	cp->size--;
	printf("删除成功\n");
}

五.查询联系人信息

查询在刚才查找到的基础上进行打印输出就可以了

void SeachPeople(Contact* cp)
{
	assert(cp);
	char name[Name_Max];
	if (cp->size == 0)
	{
		printf("通讯录为空\n");
		return;
	}
	printf("请输入选择查找的联系人的姓名:\n");
	scanf("%s", name);
	int ret = FindPeople(cp, name);
	if (ret == -1)
	{
		printf("要查找的联系人不存在\n");
		return;
	}

	//名字  年龄  性别    电话    地址
	//xxx   xxx    xxx    xxx     xxx
	printf("%-10s%-5s%-5s%-12s%-30s\n", "名字", "年龄", "性别", "电话", "地址");
	//打印个人的信息
	printf("%-20s%-5d%-5s%-12s%-30s\n", cp->data[ret].name, cp->data[ret].age, cp->data[ret].sex, cp->data[ret].telnumber, cp->data[ret].address);
}

六.修改联系人的信息

大体思路也和上面一样,先找到联系人的在数组中的位置,然后再进行修改

void ModifyContact(Contact* cp)
{
	assert(cp);
	char name[Name_Max];
	if (cp->size == 0)
	{
		printf("通讯录为空\n");
		return;
	}
	printf("请输入选择修改的联系人的姓名:\n");
	scanf("%s", name);
	int ret = FindPeople(cp, name);
	if (ret == -1)
	{
		printf("要修改的联系人信息不存在\n");
		return;
	}

	printf("请输入要修改的联系人的姓名:\n");
	scanf("%s", cp->data[ret].name);

	printf("请输入要修改的联系人的电话号:\n");
	scanf("%s", cp->data[ret].telnumber);

	printf("请输入要修改的联系人的年龄:\n");
	scanf("%d", &(cp->data[ret].age));

	printf("请输入要修改的联系人的性别:\n");
	scanf("%s", cp->data[ret].sex);

	printf("请输入要修改的联系人的住址:\n");
	scanf("%s", cp->data[ret].address);

	printf("修改成功\n");
}

完整代码 

Contct.h

#pragma once
#include<stdio.h>
#include<assert.h>
#include<string.h>

#define Name_Max 20
#define Tel_Number 12
#define Sex_Max 5
#define Address_Max 30
#define Contact_Max 100

//联系人结构体
typedef struct PeopleInformation
{
	char name[Name_Max];
	char telnumber[Tel_Number];
	int age;
	char sex[Sex_Max];
	char address[Address_Max];
}PeoInfor;

//通讯录结构体
typedef struct Contact
{
	PeoInfor data[Contact_Max];//结构体数组存放联系人结构体
	int size;//记录当前通讯录中有多少个联系人
}Contact;


//目录
void menu();

//初始化通讯录
void InitContact(Contact* cp);

//增加联系人
void AddContact(Contact* cp);

//删除联系人
void DelContact(Contact* cp);

//通过姓名进行查找联系人
int FindPeople(Contact* cp, char name[]);

//展示全部通讯录信息
void ShowContact(const Contact* cp);

//查询联系人
void SeachPeople(Contact* cp);

//修改联系人信息
void ModifyContact(Contact* cp);

Contact.cpp

#define _CRT_SECURE_NO_WARNINGS 1
#include "Contact.h"

void menu()
{
	printf("\n");
	printf("-----------------------------\n");
	printf("---   1.添加联系人      -----\n");
	printf("---   2.删除联系人      -----\n");
	printf("---   3.查找联系人      -----\n");
	printf("---   4.修改联系人信息  -----\n");
	printf("---   5.显示全部信息    -----\n");
	printf("---   0.退出通讯录      -----\n");
	printf("-----------------------------\n");
}

//初始化通讯录
void InitContact(Contact* cp)
{
	//判断非空
	assert(cp);

	cp->size = 0;
	memset(cp->data, 0, sizeof(cp->data));
}

//增加联系人
void AddContact(Contact* cp)
{
	//判断非空
	assert(cp);

	//判断未满
	if (cp->size == Contact_Max)
	{
		printf("通讯录已满,无法再添加新的联系人\n");
		return;
	}

	printf("请输入要添加的联系人的姓名:\n");
	scanf("%s", cp->data[cp->size].name);

	printf("请输入要添加的联系人的电话号:\n");
	scanf("%s", cp->data[cp->size].telnumber);

	printf("请输入要添加的联系人的年龄:\n");
	scanf("%d", &(cp->data[cp->size].age));

	printf("请输入要添加的联系人的性别:\n");
	scanf("%s", cp->data[cp->size].sex);

	printf("请输入要添加的联系人的住址:\n");
	scanf("%s", cp->data[cp->size].address);

	cp->size++;
	printf("添加成功\n");
}

//通过姓名进行查找联系人
int FindPeople(Contact* cp, char name[])
{
	assert(cp);
	for (int i = 0; i < cp->size; i++)
	{
		if (strcmp(cp->data[i].name, name) == 0)
		{
			return i;
		}
	}
	return -1;
}

//删除联系人
void DelContact(Contact* cp)
{
	assert(cp);
	char name[Name_Max];
	if (cp->size == 0)
	{
		printf("通讯录为空,无需删除\n");
		return;
	}
	printf("请输入选择删除的联系人的姓名:\n");
	scanf("%s", name);
	int ret = FindPeople(cp, name);
	if (ret == -1)
	{
		printf("要删除的联系人不存在\n");
		return;
	}
	for (int i = ret; i < cp->size-1 ; i++)
	{
		cp->data[i] = cp->data[i + 1];
	}
	cp->size--;
	printf("删除成功\n");
}

//查询联系人
void SeachPeople(Contact* cp)
{
	assert(cp);
	char name[Name_Max];
	if (cp->size == 0)
	{
		printf("通讯录为空\n");
		return;
	}
	printf("请输入选择查找的联系人的姓名:\n");
	scanf("%s", name);
	int ret = FindPeople(cp, name);
	if (ret == -1)
	{
		printf("要查找的联系人不存在\n");
		return;
	}

	//名字  年龄  性别    电话    地址
	//xxx   xxx    xxx    xxx     xxx
	printf("%-10s%-5s%-5s%-12s%-30s\n", "名字", "年龄", "性别", "电话", "地址");
	//打印个人的信息
	printf("%-10s%-5d%-5s%-12s%-30s\n", cp->data[ret].name, cp->data[ret].age, cp->data[ret].sex, cp->data[ret].telnumber, cp->data[ret].address);
}

//展示全部通讯录信息
void ShowContact(const Contact* cp)
{
	assert(cp);
	if (cp->size == 0)
	{
		printf("通讯录为空\n");
		return;
	}
	//名字  年龄  性别    电话    地址
	//xxx   xxx    xxx    xxx     xxx
	printf("%-10s%-5s%-5s%-12s%-30s\n", "名字", "年龄", "性别", "电话", "地址");
	for (int i = 0; i < cp->size; i++)
	{
		//打印每个人的信息
		printf("%-10s%-5d%-5s%-12s%-30s\n",cp->data[i].name, cp->data[i].age, cp->data[i].sex, cp->data[i].telnumber, cp->data[i].address);
	}
}

//修改联系人信息
void ModifyContact(Contact* cp)
{
	assert(cp);
	char name[Name_Max];
	if (cp->size == 0)
	{
		printf("通讯录为空\n");
		return;
	}
	printf("请输入选择修改的联系人的姓名:\n");
	scanf("%s", name);
	int ret = FindPeople(cp, name);
	if (ret == -1)
	{
		printf("要修改的联系人信息不存在\n");
		return;
	}

	printf("请输入要修改的联系人的姓名:\n");
	scanf("%s", cp->data[ret].name);

	printf("请输入要修改的联系人的电话号:\n");
	scanf("%s", cp->data[ret].telnumber);

	printf("请输入要修改的联系人的年龄:\n");
	scanf("%d", &(cp->data[ret].age));

	printf("请输入要修改的联系人的性别:\n");
	scanf("%s", cp->data[ret].sex);

	printf("请输入要修改的联系人的住址:\n");
	scanf("%s", cp->data[ret].address);

	printf("修改成功\n");
}

test.cpp

#define _CRT_SECURE_NO_WARNINGS 1
#include "Contact.h"

//枚举,增加程序的可读性
enum options
{
	EXIT,
	ADD,
	DEL,
	SEACH,
	MODIFY,
	SHOW
};

int main()
{
	int input = 0;
	//创建通讯录
	Contact con;
	//初始化通讯录
	InitContact(&con);

	do
	{
		menu();
		printf("请输入你的选择: ");
		scanf("%d", &input);

		switch (input)
		{
		//增加联系人信息
		case ADD:
			AddContact(&con);
			break;
		//删除联系人信息
		case DEL:
			DelContact(&con);
			break;
		//查找某个联系人的信息
		case SEACH:
			SeachPeople(&con);
			break;
		//修改某个联系人的信息
		case MODIFY:
			ModifyContact(&con);
			break;
		//展示通讯录内的每一个联系人的信息
		case SHOW:
			ShowContact(&con);
			break;
		//退出通讯录管理系统
		case EXIT:
			printf("通讯录已退出\n");
			break;
		//预防非法输入
		default:
			printf("输入错误,请重新输入\n");
			break;
		}
	}while(input);

	return 0;
}

        

        本次的分享就到此为止了,本文不涉及到文件操作,下篇文章,笔者将为大家带来如何通过文件操作,将我们的通讯录防止在文件中,以便我们多次重复打开和操作,如有错误,欢迎积极指出,感谢您的支持

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

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

相关文章

【STM32基础 CubeMX】PWM输出

文章目录 前言一、PWM是什么&#xff1f;二、CubeMX配置PWM三、代码分析3.1 CubeMX生成代码3.2 PWM的几个库函数HAL_TIM_PWM_Start 3.3 PWM回调函数3.4 占空比占空比是什么__HAL_TIM_SET_COMPARE设置占空比 四、呼吸灯示例总结 前言 STM32微控制器是一系列功能强大的微控制器&…

unordered_map/unordered_set的学习[unordered系列]

文章目录 1.老生常谈_遍历2.性能测试3.OJ训练3.1存在重复元素3.2两个数组的交集Ⅱ3.3两句话中的不常见单词3.4两个数组的交集3.5在长度2N的数组中找出重复N次的元素 1.老生常谈_遍历 #pragma once #define _CRT_SECURE_NO_WARNINGS #include <iostream> #include <l…

红黑树(有图解)

目录 介绍 概念 性质 模拟实现 结点定义 插入 保证平衡的原因 一般情况 特殊情况(uncle为黑) uncle不存在 旋转方式 右旋 迭代器 -- 代码 介绍 概念 红黑树是一种自平衡的二叉搜索树 它是在每个节点上引入额外的颜色信息,通过对任何一条从根到叶子的路径…

项目管理之高效合作

序 一件事能不能做成&#xff0c;和你有什么关系&#xff1f;靠的是你的努力吗&#xff1f;还是说靠的只是一个运气&#xff1f; 就像买彩票一样&#xff0c;你觉得中奖和个人努力有没有关系&#xff1b;就像和高考一样&#xff0c;你觉得考上北大清华和个人努力有没有关系&…

IDEA git操作技巧大全,持续更新中

作者简介 目录 1.创建新项目 2.推拉代码 3.状态标识 5.cherry pick 6.revert 7.squash 8.版本回退 9.合并冲突 1.创建新项目 首先我们在GitHub上创建一个新的项目&#xff0c;然后将这个空项目拉到本地&#xff0c;在本地搭建起一个maven项目的骨架再推上去&#xff0…

两条链表相同位数相加[中等]

优质博文IT-BLOG-CN 一、题目 给你两个非空的链表&#xff0c;表示两个非负的整数。它们每位数字都是按照逆序的方式存储的&#xff0c;并且每个节点只能存储一位数字。请你将两个数相加&#xff0c;并以相同形式返回一个表示和的链表。你可以假设除了数字0之外&#xff0c;这…

一文带你掌握 优先级队列

&#x1f388;个人主页:&#x1f388; :✨✨✨初阶牛✨✨✨ &#x1f43b;强烈推荐优质专栏: &#x1f354;&#x1f35f;&#x1f32f;C的世界(持续更新中) &#x1f43b;推荐专栏1: &#x1f354;&#x1f35f;&#x1f32f;C语言初阶 &#x1f43b;推荐专栏2: &#x1f354;…

Leetcode.965 单值二叉树

本专栏内容为&#xff1a;leetcode刷题专栏&#xff0c;记录了leetcode热门题目以及重难点题目的详细记录 &#x1f493;博主csdn个人主页&#xff1a;小小unicorn ⏩专栏分类&#xff1a;八大排序汇总 &#x1f69a;代码仓库&#xff1a;小小unicorn的代码仓库&#x1f69a; &…

【算法练习Day9】用栈实现队列用队列实现栈

、​ ​&#x1f4dd;个人主页&#xff1a;Sherry的成长之路 &#x1f3e0;学习社区&#xff1a;Sherry的成长之路&#xff08;个人社区&#xff09; &#x1f4d6;专栏链接&#xff1a;练题 &#x1f3af;长路漫漫浩浩&#xff0c;万事皆有期待 文章目录 用栈实现队列用队列实…

代码随想录算法训练营第五十一天 |309.最佳买卖股票时机含冷冻期、714.买卖股票的最佳时机含手续费、总结

一、309.最佳买卖股票时机含冷冻期 题目链接/文章讲解&#xff1a;代码随想录 视频讲解&#xff1a;动态规划来决定最佳时机&#xff0c;这次有冷冻期&#xff01;| LeetCode&#xff1a;309.买卖股票的最佳时机含冷冻期_哔哩哔哩_bilibili 思考&#xff1a; 1.确定dp数组&…

创建型设计模式 原型模式 建造者模式 创建者模式对比

创建型设计模式 单例 工厂模式 看这一篇就够了_软工菜鸡的博客-CSDN博客 4.3 原型模式 4.3.1 概述 用一个已经创建的实例作为原型&#xff0c;通过复制该原型对象来创建一个和原型对象相同的新对象。 4.3.2 结构 原型模式包含如下角色&#xff1a; 抽象原型类&#xff1a;规定了…

FFmpeg 命令:从入门到精通 | ffmpeg 命令视频录制

FFmpeg 命令&#xff1a;从入门到精通 | ffmpeg 命令视频录制 FFmpeg 命令&#xff1a;从入门到精通 | ffmpeg 命令视频录制安装软件&#xff1a;Screen Capturer Recorder查看可用设备名字音视频录制录制视频&#xff08;默认参数&#xff09;录制声音&#xff08;默认参数&am…

计算机竞赛 深度学习疲劳检测 驾驶行为检测 - python opencv cnn

文章目录 0 前言1 课题背景2 相关技术2.1 Dlib人脸识别库2.2 疲劳检测算法2.3 YOLOV5算法 3 效果展示3.1 眨眼3.2 打哈欠3.3 使用手机检测3.4 抽烟检测3.5 喝水检测 4 最后 0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; **基于深度学习加…

AJAX--Express速成

一、基本概念 1、AJAX(Asynchronous JavaScript And XML)&#xff0c;即为异步的JavaScript 和 XML。 2、异步的JavaScript 它可以异步地向服务器发送请求&#xff0c;在等待响应的过程中&#xff0c;不会阻塞当前页面。浏览器可以做自己的事情。直到成功获取响应后&#xf…

1558. 得到目标数组的最少函数调用次数

1558. 得到目标数组的最少函数调用次数 原题链接&#xff1a;完成情况&#xff1a;解题思路&#xff1a;参考代码&#xff1a; 原题链接&#xff1a; 1558. 得到目标数组的最少函数调用次数 https://leetcode.cn/problems/minimum-numbers-of-function-calls-to-make-target…

毛玻璃用户卡交互

效果展示 页面结构组成 从效果展示可以看到&#xff0c;此效果都是比较常规的。主要的核心就是卡片的悬停效果。 CSS 知识点 backdrop-filter 回顾transitiontransform 页面基础布局实现 <section><div class"container"><div class"card&q…

Academic accumulation|社会创业研究:过去的成就和未来的承诺

文献来源&#xff1a;Saebi T, Foss N J, Linder S. Social entrepreneurship research: Past achievements and future promises[J]. Journal of management, 2019, 45(1): 70-95. 一、文章介绍 &#xff08;一&#xff09;文章主要包含什么&#xff1f; SE越来越受到学术界的…

凉鞋的 Unity 笔记 104. 测试所涉及的窗口

104. 测试所涉及的窗口 在上一篇&#xff0c;笔者简单介绍了检视器窗口&#xff0c;如图所示&#xff1a; 我们接着介绍上图中的最后一个部分内容&#xff0c;测试部分。 测试部分我们只做了一件非常简单的操作&#xff0c;就是点击了一下运行按钮&#xff0c;查看结果&#…

【浅记】分而治之

归并排序 算法流程&#xff1a; 将数组A[1,n]排序问题分解为A[1,n/2]和A[n/21,n]排序问题递归解决子问题得到两个有序的子数组将两个子数组合并为一个有序数组 符合分而治之的思想&#xff1a; 分解原问题解决子问题合并问题解 递归式求解 递归树法 用树的形式表示抽象递…

JAVA面经整理(4)

一)Volitaile关键字的作用: volatile的使用:常常用于一写多读的情况下&#xff0c;解决内存可见性和指令重排序 JAVA内存的JMM模型:主要是用来屏蔽不同硬件和操作系统的内存访问差异的&#xff0c;在不同的硬件和不同的操作系统内存的访问是有差异的&#xff0c;这种差异会导致…