【C语言】静态通讯录 -- 详解

news2024/11/25 0:23:31

一、实现目标

1、功能

  • 保存 1000 个联系人的信息
  • 添加联系人
  • 删除联系人
  • 修改联系人
  • 查找联系人
  • 排序

2、个人信息(结构体)

  • 名字
  • 年龄
  • 性别
  • 电话
  • 地址

二、创建文件

  1. test.c(专门测试通讯录的功能)
  2. contact.c(接口的实现)
  3. contact.h(接口的声明)

三、初始页面的实现

1、实现主菜单页面

// test.c

(1)menu()
void menu()
{
	printf("****************************************\n");
	printf("****** 1.add           2.del    ********\n");
	printf("****** 3.search        4.modify ********\n");
	printf("****** 5.show          6.sort   ********\n");
	printf("****** 0.exit                   ********\n");
	printf("****************************************\n");
}

效果图如下:


(2)main()
int main()
{
	int input = 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 SORT:
			SortContact(&con);
			break;
		case EXIT:
			printf("退出通讯录!\n");
			break;
		default:
			printf("选择错误!\n");
			break;
		}
	} while (input);
	return 0;
}

2、在contact.h 中引用所需要的文件和必要的定义

首先我们要声明一个结构体,其中包含了我们想要保存的信息(可以自己设置):

struct PeoInfo
{
	char name[MAX_NAME];
	int age;
	char sex[MAX_SEX];
	char tele[MAX_TELE];
	char addr[MAX_ADDR];
};

但是接下来我们可能会想到一个问题,如何表示该结构体中已经存入的有效数据有多少?所以我们还得定义一个变量 size,通过某些函数功能的实现(例如增加联系人),size 的值也必须要发生改变,我们可以通过传入 size 的地址来改变它自身。但是还有一个简单的办法:再声明一个结构体,并用该结构体创建一个 struct PeoInfo 的数组以及 size,这样就解决了这个问题且方便管理。

struct Contact
{
	struct PeoInfo data[MAX];// 可以存放1000个人的信息
	int size;// 记录通讯录中已经保存的信息个数
};

 整体逻辑:

// contact.h
#pragma once // 避免头文件被重复引用

#include <stdio.h>
#include <string.h> // memset strcmp
#include <stdlib.h> //qsort

// 宏定义
#define MAX 1000
#define MAX_NAME 20
#define MAX_SEX 5
#define MAX_TELE 12 // 电话号码11位,以%s打印输出,所以要留下足够的空间放结束标志'\0'
#define MAX_ADDR 30

enum Option
{
	EXIT,//0
	ADD,//1
	DEL,//2
	SEARCH,//3
	MODIFY,//4
	SHOW,//5
	SORT//6
};

struct PeoInfo
{
	char name[MAX_NAME]; //姓名
	int age;             //年龄
	char sex[MAX_SEX];   //性别
	char tele[MAX_TELE]; //电话
	char addr[MAX_ADDR]; //地址
};

//通讯录类型
struct Contact
{
	struct PeoInfo data[MAX];// 可以存放1000个人的信息
	int size;// 记录通讯录中已经保存的信息个数
};

// 函数的声明
// 初始化通讯录的函数
void InitContact(struct Contact* ps);
// 添加联系人信息
void AddContact(struct Contact* ps);
// 展示通讯录中的信息(只是打印信息,不会去修改,加上const更加安全)
void ShowContact(const struct Contact* ps);
// 删除指定的联系人
void DelContact(struct Contact* ps);
// 通过姓名查找指定联系人所在下标
int FindByName(const struct Contact* ps, char name[]);
// 查找指定的人的信息(只是查找信息,不会去修改,加上const更加安全)
void SearchContact(const struct Contact* ps);
// 修改指定联系人
void ModifyContact(struct Contact* ps);
// 排序通讯录内容
void SortContact(struct Contact* ps);

:给电话数组需要定义 12 个 char 大小,如果只定义了 11 个char大小,字符数组没有结束标志,会导致打印时出现问题 。

在整体逻辑的实现上,我们用了很多 #define 的标识符常量使修改一些数据变得更加容易。为了让代码的可读性更高,在 switch 语句中运用了枚举常量。为了减少时间以及空间上的开销,所有功能函数中传入的都是结构体的地址。 


三、在 contact.c 上实现各个接口函数

1、初始化通讯录

使用 memset 函数初始化存放联系人信息的结构体数组 data。

// 初始化通讯录
void InitContact(struct Contact* ps) // 结构体指针
{
    ps->size = 0; // 设置通讯录最初只有0个元素
	memset(ps->data, 0, sizeof(ps->data));
}

2、添加联系人信息

先判断通讯录人数是否已满,如果未满,则添加联系人信息。 

// 增加一个信息到通讯录
void AddContact(struct Contact* ps)
{
    // 判断通讯录人数是否已满
	if (ps->size == MAX)
	{
		printf("通讯录已满,无法增加!\n");
        return;
	}

    // 添加一个联系人的信息
    // 录入信息
	printf("请输入名字:>");
	scanf("%s", ps->data[ps->size].name);
	printf("请输入年龄:>");
	scanf("%d", &(ps->data[ps->size].age)); // 年龄是一个整型变量 需要取地址
	printf("请输入性别:>");
	scanf("%s", ps->data[ps->size].sex);
	printf("请输入电话:>");
	scanf("%s", ps->data[ps->size].tele);
	printf("请输入地址:>");
	scanf("%s", ps->data[ps->size].addr);

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

注意由于 age 在这里是一个整型变量,所以要加上 &。


3、展示通讯录中所有联系人的信息

// 展示通讯录中的信息
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);
		}
	}
}

注意:因为只是打印信息,不会修改内容,所以加上 const 更加安全。 

为了让结果更美观,采用了左对齐的方式。printf 中 %-20s 中的 20 是指输出字段的宽度负号表示左对齐,如省略表示右对齐,如果输出的数据位数小于 20,则在数据右端补齐空格。


4、通过姓名查找指定联系人所在的下标 

// 通过姓名查找指定联系人所在下标
static int FindByName(const struct Contact* ps, char name[MAX_NAME])
{
	int i = 0;
	for (i = 0; i < ps->size; i++)
	{
		if (0 == strcmp(ps->data[i].name, name))
		{
			return i; // 查找到返回联系人的下标
		}
	}

	return -1;// 找不到返回-1
}

为了解决代码的冗余,我们不妨分装一个函数来完成查找功能。该函数会在删除 / 修改 / 查找指定联系人信息的函数中被调用到,这些函数刚好又在同一源文件中,所以用 static 修饰函数,只能在所在此文件内使用。 


5、删除指定联系人

先判断通讯录是否为空,如果不为空,再通过 FindByName() 函数查找通讯录中是否有你要删除的联系人,如果有则删除。

原理:把要删除的联系人后面一个人的信息依次从前向后往前移动一位,覆盖掉其信息,然后再将人数 -1。

// 删除指定的联系人
void DelContact(struct Contact* ps)
{
	char name[MAX_NAME];
	printf("请输入要删除人的名字:>");
	scanf("%s", name);

	// 1、查找要删除的人在什么位置
	int 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];
		}
		ps->size--;
		printf("删除成功!\n");
	}
}

6、查找指定联系人的信息

通过 FindByName() 函数查找通讯录中是否有你要查找的联系人,如果查找到,则打印该联系人的信息。 

// 查找指定的人的信息
void SearchContact(const struct Contact* ps)
{
	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);
	}
}

注意:因为只是查找信息,不会修改内容,所以加上 const 更加安全 


7、修改指定联系人

通过 FindByName() 函数查找通讯录中是否有你要修改信息的联系人,如果有则修改。 

// 修改指定联系人
void ModifyContact(struct Contact* ps)
{
	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");
	}
}

8、排序通讯录内容

// 排序通讯录内容
// 比较结构体数组中两个元素的姓名成员
int compareStructType_name(const void* elem1, const void* elem2)
{
	// 姓名成员是字符串,用strcmp比较
	return strcmp(((struct PeoInfo*)elem1)->name, ((struct PeoInfo*)elem2)->name);
}

// 以名字排序所有联系人
void SortContact(struct Contact* ps)
{
	// 判断通讯录是否为空
	if (ps->size == 0)
	{
		printf("通讯录为空,无法排序!\n");
		return;
	}
	else
	{
		// 根据姓名成员对结构体数组升序排列
		qsort(ps->data, ps->size, sizeof(ps->data[0]), compareStructType_name);
		printf("以名字排序联系人成功!\n");
	}
}

该函数排序用的是姓名作为标准,也可以自己更换其他的排序方式。 


四、代码整合

1、test.c

// test.c
#include "contact.h"

void menu()
{
	printf("****************************************\n");
	printf("****** 1.add           2.del    ********\n");
	printf("****** 3.search        4.modify ********\n");
	printf("****** 5.show          6.sort   ********\n");
	printf("****** 0.exit                   ********\n");
	printf("****************************************\n");
}

int main()
{
	int input = 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 SORT:
			SortContact(&con);
			break;
		case EXIT:
			printf("退出通讯录!\n");
			break;
		default:
			printf("选择错误!\n");
			break;
		}
	} while (input);
	return 0;
}

2、contact.h

// contact.h
#pragma once // 避免头文件被重复引用

#include <stdio.h>
#include <string.h> // memset strcmp
#include <stdlib.h> //qsort

// 宏定义
#define MAX 1000
#define MAX_NAME 20
#define MAX_SEX 5
#define MAX_TELE 12 // 电话号码11位,以%s打印输出,所以要留下足够的空间放结束标志'\0'
#define MAX_ADDR 30

enum Option
{
	EXIT,//0
	ADD,//1
	DEL,//2
	SEARCH,//3
	MODIFY,//4
	SHOW,//5
	SORT//6
};

struct PeoInfo
{
	char name[MAX_NAME]; //姓名
	int age;             //年龄
	char sex[MAX_SEX];   //性别
	char tele[MAX_TELE]; //电话
	char addr[MAX_ADDR]; //地址
};

//通讯录类型
struct Contact
{
	struct PeoInfo data[MAX];// 可以存放1000个人的信息
	int size;// 记录通讯录中已经保存的信息个数
};

// 函数的声明
// 初始化通讯录的函数
void InitContact(struct Contact* ps);
// 添加联系人信息
void AddContact(struct Contact* ps);
// 展示通讯录中的信息(只是打印信息,不会去修改,加上const更加安全)
void ShowContact(const struct Contact* ps);
// 删除指定的联系人
void DelContact(struct Contact* ps);
// 通过姓名查找指定联系人所在下标
int FindByName(const struct Contacts* ps, char name[]);
// 查找指定的人的信息(只是查找信息,不会去修改,加上const更加安全)
void SearchContact(const struct Contact* ps);
// 修改指定联系人
void ModifyContact(struct Contact* ps);
// 排序通讯录内容
void SortContact(struct Contact* ps);

3、contact.c

// contact.c
#include "contact.h"

// 初始化通讯录
void InitContact(struct Contact* ps) // 结构体指针
{
    ps->size = 0; // 设置通讯录最初只有0个元素
	memset(ps->data, 0, sizeof(ps->data));
}

// 添加联系人信息
void AddContact(struct Contact* ps)
{
    // 判断通讯录人数是否已满
	if (ps->size == MAX)
	{
		printf("通讯录已满,无法增加!\n");
        return;
	}

    // 添加一个联系人的信息
    // 录入信息
	printf("请输入名字:>");
	scanf("%s", ps->data[ps->size].name);
	printf("请输入年龄:>");
	scanf("%d", &(ps->data[ps->size].age)); // 年龄是一个整型变量 需要取地址
	printf("请输入性别:>");
	scanf("%s", ps->data[ps->size].sex);
	printf("请输入电话:>");
	scanf("%s", ps->data[ps->size].tele);
	printf("请输入地址:>");
	scanf("%s", ps->data[ps->size].addr);

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

// 展示通讯录中的信息
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);
		}
	}
}

// 通过姓名查找指定联系人所在下标
static int FindByName(const struct Contact* ps, char name[MAX_NAME])
{
	int i = 0;
	for (i = 0; i < ps->size; i++)
	{
		if (0 == strcmp(ps->data[i].name, name))
		{
			return i; // 查找到返回联系人的下标
		}
	}

	return -1;// 找不到返回-1
}

// 删除指定的联系人
void DelContact(struct Contact* ps)
{
	char name[MAX_NAME];
	printf("请输入要删除人的名字:>");
	scanf("%s", name);

	// 1、查找要删除的人在什么位置
	int 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];
		}
		ps->size--;
		printf("删除成功!\n");
	}
}

// 查找指定的人的信息
void SearchContact(const struct Contact* ps)
{
	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)
{
	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 compareStructType_name(const void* elem1, const void* elem2)
{
	// 姓名成员是字符串,用strcmp比较
	return strcmp(((struct PeoInfo*)elem1)->name, ((struct PeoInfo*)elem2)->name);
}

// 以名字排序所有联系人
void SortContact(struct Contact* ps)
{
	// 判断通讯录是否为空
	if (ps->size == 0)
	{
		printf("通讯录为空,无法排序!\n");
		return;
	}
	else
	{
		// 根据姓名成员对结构体数组升序排列
		qsort(ps->data, ps->size, sizeof(ps->data[0]), compareStructType_name);
		printf("以名字排序联系人成功!\n");
	}
}

五、程序运行效果 


六、思考

目前这个通讯录程序能够存放 1000 个联系人的信息,我们在栈区开辟了能够存放 1000 人信息的内存空间。可是如果我只有 200 个联系人,后面的空间岂不是浪费了;如果随着我的使用,存的联系人信息越来越多,超过了 1000 个,那又该怎么办呢?

是否有一种方法,能够让我们动态开辟空间,想开辟多大就开辟多大,空间不够用了可以增加,这样我们的空间利用率不就大大提高了吗。这一问题涉及到了动态内存开辟,在后面的文章中会详细介绍,并对当前通讯录进行改进和完善。

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

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

相关文章

物联网智慧安防实训综合实训基地建设方案

一、系统概述 物联网智慧安防实训综合实训基地是一个为学生提供综合实践、培养技能的场所&#xff0c;专注于物联网技术与智慧安防应用的培训和实训。通过物联网智慧安防实训综合实训基地的建设和运营&#xff0c;学生可以在真实的环境中进行实践训练&#xff0c;提高其物联网技…

【网络基础】传输层

【网络基础】传输层 文章目录 【网络基础】传输层1、端口号1.1 工具 2、UDP协议2.1 协议端格式2.2 UDP特点2.3 传输数据报2.4 缓冲区2.5 基于UDP应用层协议2.6 使用注意事项 3、TCP协议3.1 协议段格式3.2 ACK机制3.3 超时重传机制3.4 连接管理机制3.5 滑动窗口3.6 流量控制3.7 …

RDMA概述

1. DMA和RDMA概念 1.1 DMA DMA(直接内存访问)是一种能力&#xff0c;允许在计算机主板上的设备直接把数据发送到内存中去&#xff0c;数据搬运不需要CPU的参与。 传统内存访问需要通过CPU进行数据copy来移动数据&#xff0c;通过CPU将内存中的Buffer1移动到Buffer2中。DMA模…

确定产品需求边界需重点关注4个方面

产品需求需要确定边界&#xff0c;因为资源的是有限的。而没有边界的需求&#xff0c;会造成项目目标混乱&#xff0c;工期的延长&#xff0c;开发成本增加等问题。 1、定义最小业务单元 一般来说&#xff0c;产品不可能做大而全&#xff0c;需有自己专属的业务市场。从用户角度…

vue3-vuex

一、概念 &#xff08;1&#xff09;Vuex 是一个状态和数据管理的框架&#xff0c;负责管理项目中多个组件和多个页面共享的数据。 &#xff08;2&#xff09;在开发项目的时候&#xff0c;我们就会把数据分成两个部分&#xff0c;一种数据是在某个组件内部使用&#xff0c;我…

升级iPhone 15 Pro Max还是等待下一代?看看我们的比较分析!

对于拥有13 Pro Max并即将结束两年合同的用户,或者任何想看看是否值得购买两年前非常好的旗舰iPhone的最新机型的人来说,分解iPhone 15 Pro Max与iPhone 13 Pro Max的差异非常重要。无论你的动机是什么,我们都会帮助你找到答案。 iPhone 15 Pro Max还没有发布,但很快我们就…

元宇宙和vr的区别是什么?元宇宙一定要借助vr吗

引言&#xff1a; 当前&#xff0c;虚拟现实&#xff08;VR&#xff09;和元宇宙&#xff08;Metaverse&#xff09;作为科技领域的两大亮点&#xff0c;正以其巨大的潜力带领着人类走向数字化。然而&#xff0c;尽管二者都与虚拟世界紧密相关&#xff0c;但它们之间却存在着…

CentOS系统环境搭建(九)——centos系统下使用docker部署项目

centos系统环境搭建专栏&#x1f517;点击跳转 关于Docker-compose安装请看CentOS系统环境搭建&#xff08;三&#xff09;——Centos7安装Docker&Docker Compose&#xff0c;该文章同样收录于centos系统环境搭建专栏。 Centos7部署项目 采用前后端分离的形式部署。使用Do…

功率放大器的测试指标有哪些内容

功率放大器是一种将低功率信号增益放大到高功率水平的电路元件。在进行功率放大器设计和生产时&#xff0c;需要对其进行多项测试&#xff0c;以保证其性能和质量。下面介绍功率放大器常见的测试指标。 增益 功率放大器的增益是指其输出信号与输入信号之比。增益是功率放大器最…

并发编程之创建线程和线程的状态

创建线程的三种方式 1.继承Thread类 重写run方法 class MyThread extends Thread{Overridepublic void run() {for (int i 0; i < 100; i) {System.out.println(getName() ":打了" i "个小兵");}} } public class Test {public static void main(…

QT学习笔记-QT5.15编译及安装谷歌拼音输入法(QtInputMethod_GooglePinyin)

QT学习笔记-QT5.15编译及安装谷歌拼音输入法&#xff08;QtInputMethod_GooglePinyin&#xff09; 0、背景1、环境2、下载QtInputMethod_GooglePinyin源码3、使用MinGW64构建套件编译3.1 编译QtInputMethod_GooglePinyin源码3.2、部署tgtsmlInputContextPlugin输入法插件3.3、运…

uniapp安卓ios打包上线注意事项

1、安卓包注意事项 隐私政策弹框提示 登录页面隐私政策默认不勾选隐私政策同意前不能获取用户权限APP启动时&#xff0c;在用户授权同意隐私政策前&#xff0c;APP及SDK不可以提前收集和使用IME1、OAID、IMS1、MAC、应用列表等信息 ios包注意事项 需要有注销账号的功能 3、安…

人工智能(一)基本概念

人工智能之基本概念 常见问题什么是人工智能&#xff1f;人工智能应用在那些地方&#xff1f;人工智能的三种形态图灵测试是啥&#xff1f;人工智能、机器学习和深度学习之间是什么关系&#xff1f;为什么人工智能计算会用到GPU&#xff1f; 机器学习什么是机器学习&#xff1f…

财务报表数据,你看懂了吗?

之前分享过一期&#xff0c;财务数据哪里找&#xff1f;现在当我们找到相应数据&#xff0c;那我们得了解这些数据代表什么&#xff0c;能否看懂这些下载的报告&#xff0c;无论对于企业还是高校、科研所都是很重要的。如果看不懂&#xff0c;就像是站在门外的人&#xff0c;拿…

((*(volatile unsigned long *) (reg)))

#define LONGREG(reg) ((*(volatile unsigned long *) (reg)))1.&#xff08;unsigned long *&#xff09;(reg) 代表“reg”是1个unsigned long类型的指针&#xff1b; volatile是一个修饰符&#xff0c;告诉编译器此段代码不要优化,确保本条指令不会因C 编译器的优化而被省…

安装部署docker以及基本的操作

目录 一.安装与部署docker 1.1 关闭防火墙 1.2 安装依赖包 1.3 设置阿里云镜像源 1.4安装docker-ce社区版 二.设置镜像加速 三.网络优化 四.docker镜像操作 4.1 搜索镜像——docker search 镜像 4.2 下载镜像——docker pull 仓库名/镜像名&#xff1a;标签 4.3 查看已下载…

成集云 | 鼎捷ERP采购单同步钉钉 | 解决方案

源系统成集云目标系统 方案介绍 鼎捷ERP&#xff08;Enterprise Resource Planning&#xff09;是一款综合性的企业管理软件&#xff0c;它包括了多个模块来管理企业的各个方面&#xff0c;其中之一就是采购订单模块。鼎捷ERP的采购订单模块可以帮助企业有效管理和控制采购过程…

JavaScript 第二天

深入对象内置构造函数 一. 深入对象 创建对象三种方式构造函数实例成员&静态成员 1.1 创建对象三种方式 ① 利用对象字面量创建对象 const o {name: 哈哈 } ② 利用new Object 创建对象 const o new Object({ name: 哈哈 }) ③ 构造函数创建对象 1.2 构造函数 …

C进阶(2/7)前篇——指针进阶

前言&#xff1a;本文章讲解部分指针进阶内容。后续继续更新。 文章重点&#xff1a; 1. 字符指针 2. 数组指针 3. 指针数组 4. 数组传参和指针传参 目录 前言&#xff1a;本文章讲解部分指针进阶内容。后续继续更新。 指针初阶了解&#xff1a; 1.字符指针 1.1一道有关于字…

day8 STM32数据搬运工 - DMA

DMA简介 DMA&#xff0c;全称为&#xff1a;Direct Memory Access&#xff0c;即直接存储器访问。 DMA 传输方式无需 CPU 直接控制传输&#xff0c;也没有中断处理方式那样保留现场和恢复现场的过程&#xff0c;通过硬件为 RAM 与 I/O 设备开辟一条直接传送数据的通路&#x…