通讯录项目实现

引言:通过顺序表的逻辑实现通讯录。这里就不讲关于顺序表的函数了。如果有不明白的可以看我写的顺序表的博客。

目录

顺序表与通讯录的比较

各源文件文件大榄

Contact.c中通讯录相关函数的定义

初始化和销毁通讯录

添加联系人:

删除联系人:

打印通讯录中存储的所有的联系人的信息

查找联系人(通过名字)

修改联系人的信息

保存顺序表的内容

将文件的内容读入顺序表

将通讯录中的联系人的信息写入文件

优化后的的通讯录初始化和销毁函数

test.c

SeqList.h

SeqList.c

Contact.h

Contact.c 

结语:


顺序表与通讯录的比较

通讯录的底层逻辑就是顺序表,与存储int数据的顺序表相比,通讯录这个结构体存储的每个元素的类型为结构体,并且这个结构体定义的是每个联系人的基本信息。

图解:


 

各源文件文件大榄

SeqList.h顺序表的结构的声明,顺序表相关函数的声明,#define定义的符号
SeqList.c顺序表函数的定义
Contact.h通讯录中每个联系人的结构的定义,通讯录相关函数的声明
Contact.c通讯录相关函数的定义
test.c可以测试,通讯录的流程实现

Contact.h

#pragma once
#define NAME_MAX 20
#define GENDER_MAX 20
#define TEL_MAX 20
#define ADRR_MAX 20//联系人的信息的结构
typedef struct personInfo
{char name[NAME_MAX];//姓名char gender[GENDER_MAX];//性别int age;//年龄char tel[TEL_MAX];//电话char addr[ADRR_MAX];//家庭地址
}peoInfo;typedef struct SeqList Contact;//前置声明,将顺组表中的struct SeqList 改为 Contact 增加代码的可读性
//初始化和销毁
void ContactInit(Contact* ps);
void ContactDestory(Contact* ps);//添加和删除
void ContactAdd(Contact* ps);
void ContactDel(Contact* ps);//打印通讯录中的联系人
void ContactPrint(Contact* ps);//修改联系人的信息
void ContactModify(Contact* ps);//查找想要查找的联系人
void ContactFind(Contact* ps);//将文件的信息加载进通讯录
void ContactLoad(Contact* ps);
//销毁通讯录前将通讯录中的信息写入文件
void ContactSave(Contact* ps);

SeqList.h

#pragma once
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <assert.h>
#include "Contact.h"//顺序表中存储的元素的类型为定义的联系人的结构体
#define SLDataType peoInfo
typedef struct SeqList
{SLDataType* arr;int size;int capacity;
}SL;//初始化
void SLInit(SL* ps);
void SLDestory(SL* ps);
//打印
//void SLPrint(SL ps);
//尾插,尾删
void SLPushBack(SL* ps, SLDataType x);
void SLPushFront(SL* ps, SLDataType x);
//尾删,头删
void SLPopFront(SL* ps);
void SLPopBack(SL* ps);
//任意插,任意删
void SLInsert(SL* ps, int pos, SLDataType x);
void SLErase(SL* ps, int pos);

Contact.c中通讯录相关函数的定义

初始化和销毁通讯录

//初始化
void ContactInit(Contact* ps)
{SLInit(ps);
}
//销毁
void ContactDestory(Contact* ps)
{SLDestory(ps);
}

直接通过顺序表的初始化和销毁实现就可以了。

 

添加联系人:

void ContactAdd(Contact* ps)
{peoInfo s;//先定义一个联系人的变量存储要添加的联系人的信息printf("请输入要添加的联系人姓名:\n");scanf("%s", s.name);printf("请输入要添加联系人的性别:\n");scanf("%s", s.gender);printf("请输入要添加联系人的年龄:\n");scanf("%d", &s.age);printf("请输入要添加联系人的电话:\n");scanf("%s", s.tel);printf("请输入要添加联系人的地址:\n");scanf("%s", s.addr);SLPushFront(ps, s);//顺序表的头插,这里用尾插也可以
}

注意:用顺序表的头插或尾插将联系人的信息插入进通讯录.

删除联系人:

//通过名字在通讯录中找到要删除的人
int FindByName(Contact* ps, char* name)
{for (int i = 0; i < ps->size; i++){if (strcmp(ps->arr[i].name, name) == 0)return i;}return -1;
}//删除一个联系人
void ContactDel(Contact* ps)
{char name[NAME_MAX];printf("请输入你要删除的联系人的姓名:\n");scanf("%s",name);//如果通过名字找到联系人则返回存储该联系人的下标int find = FindByName(ps, name);if (find < 0){printf("你的通讯录中没有您要删除的人\n");return;}//通过顺序表的任意删除函数删除SLErase(ps, find);
}

问题:如何删除一个联系人呢?

首先,你需要给出这个联系人的名字或手机号,或家庭地址,通过这些信息找到这个联系人在顺序表中存储的位置;然后,在通过下标,利用顺序表的任意删除顺序表中的数据,删除该联系人。

这里再讲一下FindByName 函数,如果顺序表中存储的联系人的结构体的名字中有这个名字,则返回在顺序表中存储该联系人的下标;若没找到,则返回一个比0小的数。

打印通讯录中存储的所有的联系人的信息

预期结果:

实现代码:

void ContactPrint(Contact* ps)
{printf("%-5s%-5s%-5s%-5s%-5s\n", "姓名", "性别", "年龄", "电话", "家庭地址");for (int i = 0; i < ps->size; i++){printf("%-5s%-5s%-5d%-5s%-5s\n",ps->arr[i].name,ps->arr[i].gender,ps->arr[i].age,ps->arr[i].tel,ps->arr[i].addr);}}

这里代码比较简单,就不多说了。

查找联系人(通过名字)

//通过名字在顺序表中查询
int FindByName(Contact* ps, char* name)
{for (int i = 0; i < ps->size; i++){if (strcmp(ps->arr[i].name, name) == 0)return i;}return -1;
}//查找联系人
void ContactFind(Contact* ps)
{char name[NAME_MAX];printf("请输入想要查找的联系人的姓名:\n");scanf("%s", name);int find = FindByName(ps, name);//通过名字查找if (find < 0){printf("你想要查找的联系人的姓名不在通讯录中\n");return;}//找到了该联系人则打印一下这个联系人的信息printf("%-5s%-5s%-5s%-5s%-5s\n","姓名", "性别", "年龄", "电话", "家庭地址");printf("%-5s%-5s%-5d%-5s%-5s\n",ps->arr[find].name,ps->arr[find].gender,ps->arr[find].age,ps->arr[find].tel,ps->arr[find].addr);
}

这里的查找只是通过名字查找,你也可以通过电话,或家庭地址查找。

修改联系人的信息

void ContactModify(Contact* ps)
{char name[NAME_MAX];printf("请输入想要修改的联系人的姓名:\n");scanf("%s", name);int find = FindByName(ps, name);if (find < 0){printf("你想要修改的联系人的姓名不在通讯录中\n");return;}printf("请输入要添加的联系人姓名:\n");scanf("%s", ps->arr[find].name);printf("请输入要添加联系人的性别:\n");scanf("%s", ps->arr[find].gender);printf("请输入要添加联系人的年龄:\n");scanf("%d", &ps->arr[find].age);printf("请输入要添加联系人的电话:\n");scanf("%s", ps->arr[find].tel);printf("请输入要添加联系人的地址:\n");scanf("%s", ps->arr[find].addr);
}

实现思路:通过名字找到你想要修改的联系人在顺序表中存储的下标,有了下标就可以直接对这个位置的数据进行修改。

保存顺序表的内容

每次程序运行完,通讯录中的数据就会丢失,如何在下次运行程序时,继续使用上次的程序呢?

在每次销毁顺序表之前将通讯录中联系人的信息写入一个文件,每次初始化通讯录后将文件的内容读入通讯录就可以了。

将文件的内容读入顺序表

void ContactLoad(Contact* ps)
{FILE* pf = fopen("test.txt", "rb");if (pf == NULL){perror("fopen");return;}peoInfo s;//定义一个联系人的变量存储每次从文件中读出的联系人的信息while (fread(&s, sizeof(peoInfo), 1, pf))//每次读一个联系人的信息直至没有联系人的信息可以读{SLPushFront(ps, s);//将联系人的信息写入通讯录}fclose(pf);pf = NULL;
}

将通讯录中的联系人的信息写入文件

void ContactSave(Contact* ps)
{assert(ps);FILE* pf = fopen("test.txt", "wb");if (pf == NULL){perror("fopen");return;}fwrite(ps->arr, sizeof(peoInfo), ps->size, pf);//将通讯录中size个联系人的数据,也就是所有联系人的数据写入文件fclose(pf);pf = NULL;
}

优化后的的通讯录初始化和销毁函数

void ContactInit(Contact* ps)
{SLInit(ps);ContactLoad(ps);
}void ContactDestory(Contact* ps)
{ContactSave(ps);SLDestory(ps);
}

test.c

void menu()
{printf("************************************\n");printf("****1.添加联系人****2.删除联系人****\n"); printf("****3.修改联系人****4.查找联系人****\n");printf("****5.展示联系人****0. 退出     ****\n");}
int main()
{//ContactTest1();Contact s;ContactInit(&s);//初始化并载入文件中的联系人数据int op;do{menu();printf("请输入你的操作:\n");scanf("%d", &op);switch (op){case 1:ContactAdd(&s);break;case 2:ContactDel(&s);break;case 3:ContactModify(&s);break;case 4:ContactFind(&s);break;case 5:ContactPrint(&s);break;case 0:printf("退出.....emo\n");break;default:printf("你在干什么?请输入正确的操作数:\n");break;}} while (op);//销毁并肩现在通讯录中联系人的信息写入文件ContactDestory(&s);return 0;
}

SeqList.h

#include <string.h>
#include <stdlib.h>
#include <assert.h>
#include "Contact.h"#define SLDataType peoInfo
typedef struct SeqList
{SLDataType* arr;int size;int capacity;
}SL;//初始化
void SLInit(SL* ps);
void SLDestory(SL* ps);
//打印
//void SLPrint(SL ps);
//尾插,尾删
void SLPushBack(SL* ps, SLDataType x);
void SLPushFront(SL* ps, SLDataType x);
//尾删,头删
void SLPopFront(SL* ps);
void SLPopBack(SL* ps);
//任意插,任意删
void SLInsert(SL* ps, int pos, SLDataType x);
void SLErase(SL* ps, int pos);

SeqList.c

#include "SeqList.h"void CheckSLCapacity(SL* ps)
{if (ps->capacity == ps->size){int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;SLDataType* tmp = (SLDataType*)realloc(ps->arr, newcapacity * sizeof(SLDataType));if (tmp == NULL){perror("realloc");exit(-1);}//开辟成功ps->arr = tmp;ps->capacity = newcapacity;}
}void SLInit(SL* ps)
{assert(ps);ps->arr = NULL;ps->size = 0;ps->capacity = 0;
}void SLDestory(SL* ps)
{assert(ps);free(ps->arr);ps->arr = NULL;ps->size = 0;ps->capacity = 0;
}//void SLPrint(SL s)
//{
//	for (int i = 0; i < s.size; i++)
//		printf("%d ", s.arr[i]);
//	printf("\n");
//}void SLPushBack(SL* ps, SLDataType x)
{assert(ps != NULL);CheckSLCapacity(ps);ps->arr[ps->size] = x;ps->size++;
}void SLPushFront(SL* ps, SLDataType x)
{assert(ps != NULL);CheckSLCapacity(ps);for (int i = ps->size; i>0; i--){ps->arr[i] = ps->arr[i - 1];}ps->arr[0] = x;ps->size++;
}void SLPopBack(SL* ps)
{assert(ps != NULL);assert(ps->size > 0);ps->size--;
}void SLPopFront(SL* ps)
{assert(ps != NULL);assert(ps->size > 0);for (int i = 0; i <ps->size-1 ; i++)ps->arr[i] = ps->arr[i + 1];ps->size--;
}void SLInsert(SL* ps, int pos, SLDataType x)
{assert(ps);assert(pos >= 0 && pos <= ps->size);CheckSLCapacity(ps);for (int i = ps->size; i>pos ; i--){ps->arr[i] = ps->arr[i - 1];}ps->arr[pos] = x;ps->size++;
}void SLErase(SL* ps, int pos)
{assert(ps);assert(pos >= 0 && pos < ps->size);for (int i = pos; i < ps->size-1; i++){ps->arr[i] = ps->arr[i + 1];}ps->size--;}

Contact.h

#pragma once
#define NAME_MAX 20
#define GENDER_MAX 20
#define TEL_MAX 20
#define ADRR_MAX 20typedef struct personInfo
{char name[NAME_MAX];char gender[GENDER_MAX];int age;char tel[TEL_MAX];char addr[ADRR_MAX];
}peoInfo;typedef struct SeqList Contact;
//初始化和销毁
void ContactInit(Contact* ps);
void ContactDestory(Contact* ps);//添加和删除
void ContactAdd(Contact* ps);
void ContactDel(Contact* ps);//打印通讯录中的联系人
void ContactPrint(Contact* ps);//修改联系人的信息
void ContactModify(Contact* ps);//查找想要查找的联系人
void ContactFind(Contact* ps);//将文件的信息加载进通讯录
void ContactLoad(Contact* ps);
//销毁通讯录前将通讯录中的信息写入文件
void ContactSave(Contact* ps);

Contact.c 

#include "SeqList.h"//这个文件中有Contact的定义void ContactInit(Contact* ps)
{SLInit(ps);ContactLoad(ps);
}void ContactDestory(Contact* ps)
{ContactSave(ps);SLDestory(ps);
}void ContactAdd(Contact* ps)
{peoInfo s;printf("请输入要添加的联系人姓名:\n");scanf("%s", s.name);printf("请输入要添加联系人的性别:\n");scanf("%s", s.gender);printf("请输入要添加联系人的年龄:\n");scanf("%d", &s.age);printf("请输入要添加联系人的电话:\n");scanf("%s", s.tel);printf("请输入要添加联系人的地址:\n");scanf("%s", s.addr);SLPushFront(ps, s);
}int FindByName(Contact* ps, char* name)
{for (int i = 0; i < ps->size; i++){if (strcmp(ps->arr[i].name, name) == 0)return i;}return -1;
}void ContactDel(Contact* ps)
{char name[NAME_MAX];printf("请输入你要删除的联系人的姓名:\n");scanf("%s",name);int find = FindByName(ps, name);if (find < 0){printf("你的通讯录中没有您要删除的人\n");return;}SLErase(ps, find);
}void ContactPrint(Contact* ps)
{printf("%-5s%-5s%-5s%-5s%-5s\n", "姓名", "性别", "年龄", "电话", "家庭地址");for (int i = 0; i < ps->size; i++){printf("%-5s%-5s%-5d%-5s%-5s\n",ps->arr[i].name,ps->arr[i].gender,ps->arr[i].age,ps->arr[i].tel,ps->arr[i].addr);}}void ContactModify(Contact* ps)
{char name[NAME_MAX];printf("请输入想要修改的联系人的姓名:\n");scanf("%s", name);int find = FindByName(ps, name);if (find < 0){printf("你想要修改的联系人的姓名不在通讯录中\n");return;}printf("请输入要添加的联系人姓名:\n");scanf("%s", ps->arr[find].name);printf("请输入要添加联系人的性别:\n");scanf("%s", ps->arr[find].gender);printf("请输入要添加联系人的年龄:\n");scanf("%d", &ps->arr[find].age);printf("请输入要添加联系人的电话:\n");scanf("%s", ps->arr[find].tel);printf("请输入要添加联系人的地址:\n");scanf("%s", ps->arr[find].addr);
}void ContactFind(Contact* ps)
{char name[NAME_MAX];printf("请输入想要查找的联系人的姓名:\n");scanf("%s", name);int find = FindByName(ps, name);if (find < 0){printf("你想要查找的联系人的姓名不在通讯录中\n");return;}printf("%-5s%-5s%-5s%-5s%-5s\n","姓名", "性别", "年龄", "电话", "家庭地址");printf("%-5s%-5s%-5d%-5s%-5s\n",ps->arr[find].name,ps->arr[find].gender,ps->arr[find].age,ps->arr[find].tel,ps->arr[find].addr);
}void ContactLoad(Contact* ps)
{FILE* pf = fopen("test.txt", "rb");if (pf == NULL){perror("fopen");return;}peoInfo s;while (fread(&s, sizeof(peoInfo), 1, pf)){SLPushFront(ps, s);}fclose(pf);pf = NULL;
}void ContactSave(Contact* ps)
{assert(ps);FILE* pf = fopen("test.txt", "wb");if (pf == NULL){perror("fopen");return;}fwrite(ps->arr, sizeof(peoInfo), ps->size, pf);fclose(pf);pf = NULL;
}

最终结果展示:

第一次写:

写完之后文件中有一个联系人: 22  22  22  22   22   22 

文件的内容:

第二次使用程序:

 

结语:

总算写完了,现在脑袋还是昏昏的,哈哈哈哈.

下次的项目就是贪吃蛇了。

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

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

相关文章

Spring的BeanFactory和FactoryBean有什么区别?

两者的区别 BeanFactory定义了ioc容器的最基本形式,并提供了ioc容器应遵守的的最基本的接口,也就是Spring ioc所遵守的最底层和最基本的编程规范,它只是个接口,并不是ioc容器的具体实现。它的职责包括:实例化、定位、配置应用程序中的对象及建立这些对象间的依赖。再来说说…

UE4_X光效果设置_法线图影响透明度

UE4_X光效果设置_法线图影响透明度 2019-03-22 13:37 Exponentin 设置轮廓光扩散度 baseReflectFactionIn 设置内部黑色的亮度值。nromal&#xff0c;连接应用一张法线图&#xff0c;Lerp两色插值&#xff0c;给两个数值&#xff0c;制造一个渐变。 法线图影响透明度&#xf…

Python实现BOA蝴蝶优化算法优化卷积神经网络分类模型(CNN分类算法)项目实战

说明&#xff1a;这是一个机器学习实战项目&#xff08;附带数据代码文档视频讲解&#xff09;&#xff0c;如需数据代码文档视频讲解可以直接到文章最后获取。 1.项目背景 蝴蝶优化算法(butterfly optimization algorithm, BOA)是Arora 等人于2019年提出的一种元启发式智能算…

电商系列之促销

> 插&#xff1a;AI时代&#xff0c;程序员或多或少要了解些人工智能&#xff0c;前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到网站。 坚持不懈&#xff0c;越努力越幸运&#xff0c;大家…

C/C++程序的(编译,链接)翻译与运行

目录 前言&#xff1a; 1.程序环境 2.翻译环境 3.预处理&#xff08;预编译&#xff09; 4.编译 5.汇编 6.链接 7.运行环境 总结&#xff1a; 前言&#xff1a; 本篇来解释c/c程序的翻译环境与运行环境中的过程&#xff0c;不同的编程语言的翻译环境类似&#xff0c;…

YOLOv8改进 | 低照度检测 | 2024最新改进CPA-Enhancer链式思考网络(适用低照度、图像去雾、雨天、雪天)

一、本文介绍 本文给大家带来的2024.3月份最新改进机制,由CPA-Enhancer: Chain-of-Thought Prompted Adaptive Enhancer for Object Detection under Unknown Degradations论文提出的CPA-Enhancer链式思考网络,CPA-Enhancer通过引入链式思考提示机制,实现了对未知退化条件下…

java框架学习——注解/元注解概述及使用案例

前言&#xff1a; 整理下学习笔记&#xff0c;打好基础&#xff0c;daydayup!!! 注解 注解&#xff08;Annotation&#xff09;是java代码里的特殊标记。作用为&#xff1a;让其他程序根据注解信息来决定怎么执行该程序&#xff0c;如&#xff1a;Override,Test等。同时可以根…

956: 约瑟夫问题的实现

【学习版】 【C语言】 #include <iostream> #include <string> #include <algorithm> #include <cmath> #include <cstdlib> using namespace std; typedef struct Lnode {int date;struct Lnode* next; }Lnode, * Linklist; int In(Linklist&…

云原生:应用敏捷,华为视角下的应用现代化

Gartner 也提出&#xff0c;到 2023 年&#xff0c;新应用新服务的数量将达到 5 亿&#xff0c;也即是说&#xff1a;“每个企业都正在成为软件企业”。据IDC 预测&#xff0c;到 2025 年三分之二的企业将成为多产的“软件企业”&#xff0c;每天都会发布软件版本。越来越多的企…

尚硅谷50道Java面试题笔记 写的不全

b站链接&#xff1a;https://www.bilibili.com/video/BV1Bb411d7SL/?p4&vd_source714a8042f058b82c668750a0930ff9b0 1 mysql使用innodb引擎&#xff0c;请简述mysql索引的最左前缀如何优化orderby语句。 关键点&#xff1a; 如果排序字段不在索引列上&#xff0c;file…

Vue.js---------Vue基础

能够说出Vue的概念和作用能够使用vue/cli脚手架工程化开发能够熟练Vue指令 一.vue基本概念 1.学习vue Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态&#xff0c;并以相应的规则保证状态以一种可预测的方式发生变化。 渐进…

SpringCloud学习(6)-Micrometer+ZipKin分布式链路追踪

为什么会出现这个技术&#xff1f; 微服务架构中&#xff0c;一个由客户端发起的请求在后端系统中会经过多个不同的的服务节点调用来协同产生最后的请求结果&#xff0c;每一个前段请求都会形成一条复杂的分布式服务调用链路&#xff0c;链路中的任何一环出现高延时或错误都会…

Linux网络基础(一)网络基础探索之旅

⭐小白苦学IT的博客主页 ⭐初学者必看&#xff1a;Linux操作系统入门 ⭐代码仓库&#xff1a;Linux代码仓库 ❤关注我一起讨论和学习Linux系统 本节重点 了解网络发展背景, 对局域网/广域网的概念有基本认识;了解网络协议的意义, 重点理解TCP/IP五层结构模型;学习网络传输的基本…

docker安装elasticsearch

安装之前需要创建网络 为啥需要创建网络? 因为我们还需要部署kibana容器,因此需要让es和kibana容器互联 创建网络: docker network create es-kibana es-kibana:网络名称,自定义即可 拉取elasticsearch镜像使用7.12.1版本: docker pull elasticsearch7.12.1 …

修改element-ui table组件展开/收起图标、支持点击行展开/收起、隐藏不可展开行得图标

Element中table默认支持的&#xff0c;展开和收起功能&#xff0c;如下&#xff1a; 针对表格的展开收起&#xff0c;本文改造的主要有3点&#xff1a; 1、修改展开/收起的图标&#xff1b; 2、对于不支持展开/收起的行&#xff0c;隐藏图标&#xff1b; 3、点击行&#xff0…

leetcode代码记录(打家劫舍 II

目录 1. 题目&#xff1a;2. 我的代码&#xff1a;小结&#xff1a; 1. 题目&#xff1a; 一个专业的小偷&#xff0c;计划偷窃一个环形街道上沿街的房屋&#xff0c;每间房内都藏有一定的现金。这个地方所有的房屋都 围成一圈 &#xff0c;这意味着第一个房屋和最后一个房屋是…

Linux驱动学习:从Linux主机nfs共享文件到uboot

第一步&#xff1a;在Linux主机上开启NFS服务&#xff0c;使用如下命令安装NFS服务&#xff1a; sudo apt-get install nfs-kernel-server rpcbind 第二步&#xff1a;创建一个文件夹用于共享&#xff0c;直接以nfs命名就行&#xff1a; 第三步&#xff1a;打开nfs服务配置文…

ES6展开运算符

1.展开可迭代对象&#xff08;简单理解为数组和伪数组&#xff09;&#xff0c;如数组、 NodeList 、arguments。 可以通过展开运算符把一个伪数组转换为数组 const a [...document.body.children]; console.log(a); console.log(Array.isArray(a));2.实现数组的浅拷贝 cons…

分享three.js实现粒子背景

three.js中粒子效果的实现方式大概分为三种&#xff1a; 1、Javascript直接计算粒子的状态变化&#xff0c;即基于CPU实现&#xff1b; 2、Javascript通知顶点着色器粒子的生命周期&#xff0c;由顶点着色器运行&#xff0c;即基于GPU实现&#xff1b; 3、粒子生成与状态维护全…

C++基础13:C++输入输出

此专栏为移动机器人知识体系下的编程语言中的 C {\rm C} C从入门到深入的专栏&#xff0c;参考书籍&#xff1a;《深入浅出 C {\rm C} C》(马晓锐)和《从 C {\rm C} C到 C {\rm C} C精通面向对象编程》(曾凡锋等)。 12.C输入/输出 12.1 C流类 计算机的输入和输出是数据传送的过…