当前位置: 首页 > article >正文

C++基础(六)——数组与字符串

家人们好呀如果你要把全班50个学生的成绩存起来难道要定义score1、score2、score3……一直到score50吗那你的代码会像超市小票一样长得让人绝望。幸运的是C早就帮你准备好了解决方案——数组Array。你可以把它想象成一排带编号的储物柜一个名字就能管理一整排柜子通过编号下标直接找到对应的那个。而字符串String本质上也是一种特殊的数组——字符的数组。但由于字符串实在太常用了C为它准备了专门的“VIP待遇”。本文就是你的“数组与字符串完全指南”。我们将从C风格的“老古董”讲起一直到C标准库里的现代“利器”。准备好了吗让我们开始给数据排排坐。一、数组1.1 什么是数组数组是一块连续的内存空间里面存放着一串相同类型的数据。它的核心特点有三个类型相同一个数组里只能放同一种类型的数据全是int、全是double……。大小固定对于内置数组 一旦创建数组的长度就不能改变。连续存储所有元素在内存中是紧密相邻的这赋予了数组极高的访问效率。数组就像一列首尾相接的火车车厢。你有一列int号列车它的每节车厢都只能装整数。你可以通过“第几节车厢”下标立刻找到里面的东西元素因为这列火车的车厢是连续编号的。1.2 C风格数组虽然C11之后有了更现代的std::array但C风格的原始数组仍然是很多底层代码的基石也是理解指针和内存的第一步。声明与初始化// 声明并初始化方式1指定大小随后赋值其他元素自动为0intscores[5]{95,88,76,92,100};// 声明并初始化方式2让编译器自动算大小doubleprices[]{9.99,19.99,29.99};// 自动推导出大小为3// 声明方式3先声明后赋值所有元素初值为垃圾值intdata[10];// 局部数组元素值是随机的重要提醒局部作用域的C风格数组在函数内部声明的如果只声明不初始化里面的值是垃圾值内存中残留的随机数。访问元素下标操作符 []数组用下标从0开始来访问元素intscores[5]{95,88,76,92,100};cout第一个人的成绩scores[0]endl;// 输出95cout第三个人的成绩scores[2]endl;// 输出76scores[1]90;// 把第二个人的成绩改成90数组编序号是从0开始的这被称为“零基索引”。所以有5个元素的数组有效下标是0, 1, 2, 3, 4。为什么程序员数数总是从0开始因为他们习惯了——数组的第一个元素在偏移量为0的位置就这么简单。这导致程序员在生活中也经常“从0开始”去餐厅点菜可能会说“我要第0道菜”……数组越界这是C风格数组最危险的特性访问数组时C不检查下标是否有效intdata[5]{1,2,3,4,5};coutdata[10];// 越界了但编译能通过运行时可能崩溃也可能读到随机值这种错误被称为未定义行为UB。结果可能是程序崩溃运气好也可能是悄悄读到/写入了不该动的内存导致程序在另一个完全不相关的地方出错运气差调试到你怀疑人生。1.3 数组与指针的“纠缠”这是C/C中最核心也最令人头疼的关系之一数组名在大多数情况下会被视为指向数组首元素的指针。intarr[5]{10,20,30,40,50};int*ptrarr;// arr被隐式转换为指向arr[0]的指针cout*ptrendl;// 输出10cout*(ptr1)endl;// 输出20指针偏移到arr[1]有四个例外情况数组名不会被转换为指针作为sizeof的操作数sizeof(arr)返回整个数组的大小5 × 4 20字节。作为取地址操作符的操作数arr的类型是int(*)[5]指向包含5个int的数组的指针而不是int**。作为字符串字面量用于初始化字符数组。作为decltype的操作数。指针算术指针加1实际上加的是指针所指向类型的大小而不是1个字节。对于int*加1就是地址加4字节。数组作为函数参数当你把数组名传给函数时实际上传的是指针数组首地址函数并不知道数组有多大。所以通常需要把大小也一并传过去或者用一个“哨兵值”标记数组结束C风格字符串用的就是’\0’。// 两种写法完全等价voidprintArray(intarr[],intsize);// arr本质上是指针voidprintArray(int*arr,intsize);// 和上面一模一样1.4 std::array来自C11的现代化“改良版”std::array定义在array头文件中是对C风格数组的C封装大小固定但功能更丰富。它支持迭代器、有size()方法、不会退化为指针是固定大小数组的首选。#includearrayusingnamespacestd;arrayint,5scores{95,88,76,92,100};// 大小在签名中指定// 遍历方式1标准for循环for(inti0;iscores.size();i){coutscores[i] ;}// 遍历方式2范围for推荐for(intx:scores){coutx ;}// 实用成员函数scores.size();// 获取元素个数scores.at(0);// 带越界检查的访问越界会抛出异常scores.front();// 第一个元素scores.back();// 最后一个元素scores.fill(0);// 所有元素填充为0scores.empty();// 判断是否为空std::array的优势是它不会退化为指针当作函数参数传递时类型信息得以保留使用迭代器遍历也更加安全。在现代C中能用std::array的地方就不要用C风格数组。二、多维数组套娃的艺术当一维数组不能满足需求时比如要存一个矩阵或者一张图像的数据就需要二维甚至更高维的数组。2.1 二维数组基础// 声明一个3行4列的矩阵intmatrix[3][4]{{1,2,3,4},{5,6,7,8},{9,10,11,12}};coutmatrix[0][2]endl;// 输出3第0行第2列二维数组的本质是“数组的数组”。在内存中它是按行连续存储的行优先。2.2 std::array二维版本arrayarrayint,4,3matrix2{{{1,2,3,4},{5,6,7,8},{9,10,11,12}}};for(constautorow:matrix2){// 外层遍历每一行for(intval:row){// 内层遍历行中的每个元素coutval ;}coutendl;}2.3 多维数组作为函数参数这是最需要注意的地方——当你把多维数组作为参数传递给函数时除了第一维其他维度的大小必须明确指定// 正确指定了列数voidprintMatrix(intmatrix[][4],introws){/* ... */}// 错误编译器无法确定行的大小// void printMatrix(int matrix[][]) { ... }对于更高维数组也是除了最左边的第一维其余维度大小都需要在形参声明中指定。三、C风格字符串以’\0’为终点的时代在C早期字符串就是用字符数组来处理的并以一个特殊字符’\0’空字符ASCII码为0作为结束标志。这种字符串被称为C风格字符串。3.1 基础用法charname1[]Alice;// 编译器自动在末尾加\0数组大小为6charname2[]{B,o,b,\0};// 手动添加\0charname3[20]Charlie;// 预留足够空间coutname1endl;// 输出Alice遇到\0才停关键点Alice这个字符串字面量实际占用6个字符5个字母 1个’\0’。忘记给’\0’留空间是新手常犯的错误。3.2 常用操作函数定义在cstring函数用途注意strlen(s)获取长度不含’\0’遍历到’\0’为止strcpy(dst, src)复制字符串确保dst空间足够strcat(dst, src)拼接字符串同上strcmp(s1, s2)比较大小返回0表示相等#includecstringusingnamespacestd;charbuffer[50];strcpy(buffer,Hello);// buffer现在是Hellostrcat(buffer, World);// buffer现在是Hello Worldcoutstrlen(buffer)endl;// 输出11coutstrcmp(abc,abd)endl;// 输出负数abc abdC风格字符串的优点是简单、与C语言API兼容。但缺点也很明显操作麻烦、容易越界忘了留’\0’的空间可能导致缓冲区溢出这是很多安全漏洞的根源、不能直接用比较内容。四、std::string现代C的字符串王者std::string定义在string头文件是C标准库提供的字符串类型自动管理内存、支持动态扩容使用起来像是给字符串操作开了“外挂”。4.1 基础操作#includestringusingnamespacestd;string s1;// 空字符串string s2Hello;// 初始化strings3(World);// 另一种初始化方式string s4s2 s3!;// 直接拼接输出Hello World!长度与访问string strHello;coutstr.length()endl;// 输出5coutstr[0]endl;// 输出H不检查越界coutstr.at(0)endl;// 输出H检查越界越界会抛异常str[0]h;// 修改字符str变成hello比较string可以直接用、、进行比较按字典序逐个字符比对if(str1str2){/* ... */}if(str1str2){/* 按字典序比较 */}子串与查找string strHello World;string substr.substr(0,5);// Hello从索引0开始取5个字符size_t posstr.find(World);// 返回6首次出现的位置size_t pos2str.find(o,5);// 从索引5开始找o返回7size_t pos3str.find(xyz);// 返回string::npos表示没找到str.replace(6,5,C);// 从索引6开始把5个字符替换成Cstr.erase(5,1);// 从索引5开始删除1个字符str.insert(0,Say: );// 在索引0处插入遍历stringstring strC;for(charch:str){// 范围for遍历coutch ;}for(size_t i0;istr.size();i){// 传统下标遍历coutstr[i] ;}4.2 string与数值互转C11起// 字符串转数值intastoi(42);// string to intdoublebstod(3.14);// string to doublelonglongcstoll(12345678);// string to long long// 数值转字符串string s1to_string(42);// int to string → 42string s2to_string(3.14);// double to string → 3.140000注意默认6位小数4.3 string vs C风格字符串对比维度C风格字符串char[]std::string内存管理手动容易溢出自动扩容安全拼接strcat需手动管理空间直接用号比较strcmp不能直接直接用获取长度strlenO(n)遍历.size()O(1)作为函数参数退化为指针可以传引用保留类型信息学习建议理解原理知道怎么用就行日常开发首选五、std::vectorC动态数组如果数组的大小不确定——比如你需要存一个班的学生成绩但这个班的人数随时可能变化——那么std::vector就是你的最佳选择。std::vector定义在vector头文件中是一个动态数组可以随时增长或缩小。#includevectorusingnamespacestd;vectorintv;// 空vectorvectorintv2(5);// 5个元素初始值为0vectorintv3(5,42);// 5个元素初始值为42vectorintv4{1,2,3};// 初始化列表核心操作操作代码说明添加元素v.push_back(10);在末尾添加删除末尾v.pop_back();删除最后一个元素访问v[0]、v.at(0)[]不检查越界.at()会检查大小v.size()当前元素个数容量v.capacity()已分配的内存能容纳多少个元素清空v.clear()删除所有元素size变0判空v.empty()是否为空首/尾元素v.front()、v.back()获取第一个/最后一个元素在任意位置插入v.insert(it, val)在迭代器it位置前插入删除任意位置v.erase(it)删除迭代器it指向的元素遍历vectorvectorintv{10,20,30,40,50};for(intx:v){coutx ;}// 范围forfor(size_t i0;iv.size();i){coutv[i];}// 下标for(autoitv.begin();it!v.end();it){cout*it;}// 迭代器vector是动态数组向其中添加元素可能触发重新分配内存当size()超过capacity()时。如果你大致知道会用多少元素可以用v.reserve(n)预先分配空间来避免多次重新分配。六、字符串输入再探getline与cin混用的终极解决方案在上一篇文章中我们提到过这个“千古谜题”这里再系统梳理一遍。问题cin 读取数字后紧接getline(cin, str)getline会被跳过。intage;string name;cinage;// 输入25按回车getline(cin,name);// 读到了回车符直接返回空字符串原因cin 读取了数字但把行尾的换行符’\n’留在了输入缓冲区。getline一上来就看到换行符以为读到了一行空行。终极解决方案cinage;cin.ignore(numeric_limitsstreamsize::max(),\n);// 清掉换行符getline(cin,name);// 现在正常工作了如果前面有多次cin 也可以用循环来清空缓冲区但最稳妥的做法就是在每次cin 之后、getline之前加cin.ignore()。七、现代C新特性C17到C267.1 C17std::string_viewstd::string_view定义在string_view头文件相当于一个“窗口”它指向一个已存在的字符串的某一段但不拥有内存因此创建开销极小。#includestring_viewusingnamespacestd;string strHello World;string_view svstr;// 不复制字符串内容string_view subsv.substr(0,5);// Hello也没有复制voidprint(string_view sv){// 可以同时接受string和const char*coutsvendl;}使用场景函数只需要读取字符串内容而不需要持有它时用string_view可以避免不必要的拷贝。但要注意string_view不拥有内存原字符串被销毁后不能继续使用。7.2 C20starts_with 和 ends_withstring strHello World;boolb1str.starts_with(Hell);// trueboolb2str.ends_with(rld);// trueboolb3str.contains(lo Wo);// C23true7.3 C20/23数组相关的其他改进C20起部分编译器已支持constexpr vectorC23全面支持。std::spanC20提供了对连续内存区域的安全视图访问。八、最佳实践能用std::string就别用char[]。能用std::array就别用C风格数组固定大小。能用std::vector就别用new出来的动态数组大小可变。需要只读访问字符串时考虑std::string_view。提交代码前检查所有数组下标是否可能越界。cin 后紧接getline记得清缓冲区。九、动手实践打开Visual Studio把下面的代码跑起来#includeiostream#includestring#includearray#includevectorusingnamespacestd;intmain(){// 1. std::array 演示cout std::array endl;arrayint,5scores{95,88,76,92,100};for(intx:scores)coutx ;coutendl;cout最高分*max_element(scores.begin(),scores.end())endl;// 2. std::string 演示cout\n std::string endl;string greetingHello;greeting C;coutgreeting长度greeting.length()endl;cout子串greeting.substr(0,5)endl;// 3. std::vector 演示cout\n std::vector endl;vectorstringnames;names.push_back(张三);names.push_back(李四);names.push_back(王五);for(constautoname:names)coutname ;coutendl;system(pause);return0;}十、总结恭喜你现在你已经拿下了批量存储数据的基本技能。快速回顾· C风格数组固定大小、连续内存、下标从0开始、容易越界· std::arrayC风格的安全升级版固定大小但不退化指针· 多维数组数组的数组参数传递时除第一维外都要指定大小· C风格字符串以’\0’结尾的字符数组提供操作函数· std::string现代C首选自动管理、支持拼接、比较· std::vector动态数组随时增减元素· std::string_viewC17轻量级只读字符串视图思考题为什么C风格数组作为函数参数时往往还需要传一个“大小”参数Hello这个字符串字面量实际占用几个字节为什么std::string可以直接用比较内容那char[]可以吗如果可以它比较的是什么在什么场景下你会选择std::vector而不是std::arraystd::string_view和std::string的区别是什么下一篇文章我们将学习C的函数——如何把代码组织成一个个可以重复使用的“功能模块”让程序结构更清晰。到时候你会发现main函数只是整个程序的“总导演”精彩的戏都在你自己写的函数里—— 一个曾经因为数组越界而让程序“乱码乱飞”的C学习者——————呵呵哒——————家人们真的很感谢你们的支持有幸刷到我的文章也是一种不可磨灭的缘分我还只是个命苦的学生如果你的手指还没有残废的话麻烦点一下点赞收藏关注让我不解的是为什么有的人点了赞却不收藏或者随便评论一下也行能给双方加积分。我的专栏里还有很多有趣的内容呃如果不想买的话可以看里面的试读文章我真的好良心一堆试读的我也会不断更新当然买下来我会大大滴感谢泥真的想赚点零花钱呜呜呜T_T

相关文章:

C++基础(六)——数组与字符串

家人们好呀!!! 如果你要把全班50个学生的成绩存起来,难道要定义score1、score2、score3……一直到score50吗?那你的代码会像超市小票一样长得让人绝望。 幸运的是,C早就帮你准备好了解决方案——数组&#…...

手把手教你用Python PyVISA连接Keysight示波器,实现数据自动采集与可视化

Python PyVISA实战:Keysight示波器数据采集与可视化全流程解析 当实验室里的Keysight示波器屏幕不断闪烁,而你需要连续记录数百组波形数据时,手动操作不仅效率低下,还容易出错。这就是Python PyVISA展现价值的时刻——通过几行代码…...

C++基础(四)——流程控制语句(超详细)

家人们好呀!!!前几篇文章里,我们先让计算机喊出了“Hello World”,又教会了它“记事情”(变量和数据类型),最后让它学会了“算算术”(运算符和表达式)。但到目…...

打工人必备!OpenClaw极速部署指南

想要一个能编程、搜索资料、执行脚本、处理日常事务的智能助手?现在通过OpenClaw一键部署,5分钟即可拥有你的专属AI助理! 本教程将从技术特性、环境准备、部署流程、功能验证到报错排查等维度进行全面讲解,提供可直接上手的实践指…...

NVIDIA GH200 NVL32超级芯片架构解析与AI计算革命

1. NVIDIA GH200 NVL32超级芯片架构解析在2023年AWS re:Invent大会上,NVIDIA与AWS联合发布的GH200 NVL32架构重新定义了AI计算基础设施的标准。这套系统最引人注目的特点是其突破性的内存架构设计——通过32颗GH200 Grace Hopper超级芯片的NVLink互连,构…...

智慧树刷课插件终极指南:3分钟安装,彻底解放你的学习时间

智慧树刷课插件终极指南:3分钟安装,彻底解放你的学习时间 【免费下载链接】zhihuishu 智慧树刷课插件,自动播放下一集、1.5倍速度、无声 项目地址: https://gitcode.com/gh_mirrors/zh/zhihuishu 还在为智慧树平台繁琐的视频播放流程而…...

Arthas进阶技巧:用classloader和dump命令破解类加载难题

Arthas进阶技巧:用classloader和dump命令破解类加载难题 在Java应用的开发和运维过程中,类加载问题就像是一个难以捉摸的幽灵,总是在最意想不到的时刻出现。你是否遇到过这样的场景:明明类路径配置正确,却抛出ClassNot…...

这个Unity插件,直接帮你做了一个“炉石传说”

一、插件简介 Card Craft: Epic Card Game Engine 是一款高度完整的卡牌游戏开发框架,整体设计思路明显参考了 Hearthstone 这类成熟的CCG(Collectible Card Game)产品。它不仅提供了完整的卡牌系统,还内置了联网对战、AI对战、卡…...

【Unity游戏模板】Sort Match Color Puzzle 一款能赚钱的三消替代游戏项目架构深度分析

在当前休闲游戏市场中,“分类匹配”类玩法一直保持着较高的用户粘性,而《Sort Match Color Puzzle》正是这样一款具备完整商业化能力的模板项目。它不仅提供了成熟的玩法框架,还在架构设计、系统拆分、性能优化以及商业化集成方面达到了可以直…...

用树莓派Pico和MicroPython打造一个简易数据记录器:从环境传感器到SD卡存储

用树莓派Pico构建环境数据记录器的完整指南 在物联网和嵌入式系统开发中,可靠的数据采集与存储是许多项目的核心需求。想象一下,您需要在温室中持续监测温湿度变化,或者在野外记录气象数据,甚至只是简单地跟踪家中空气质量——这些…...

颠覆性文件系统:如何重塑Windows与Linux的边界

颠覆性文件系统:如何重塑Windows与Linux的边界 【免费下载链接】btrfs WinBtrfs - an open-source btrfs driver for Windows 项目地址: https://gitcode.com/gh_mirrors/bt/btrfs 在当今跨平台开发成为常态的时代,你是否曾为Windows与Linux之间的…...

芯片制造企业如何解决CAD图纸粘贴到CKEditor的矢量输出?

企业网站后台管理系统Word/微信公众号内容导入功能解决方案 需求背景 作为广西某国企的项目负责人,我们面临在企业网站后台管理系统中增强内容编辑功能的需求。具体需求包括: Word粘贴功能:从Word复制内容可直接粘贴到编辑器,图…...

别再只用鼠标了!SketchUp 2021 高手效率秘籍:自定义快捷键与6种选择技巧实战

别再只用鼠标了!SketchUp 2021 高手效率秘籍:自定义快捷键与6种选择技巧实战 当你在SketchUp中反复点击、拖拽、切换工具时,是否感觉效率被无形消耗?专业建模师与普通用户的区别,往往在于对键盘-鼠标协同工作流的掌控程…...

日志丢失、格式混乱、排查耗时>2小时?27天重构Docker日志架构,实现100%可追溯、零盲区监控

第一章:Docker日志架构重构的痛点与目标在大规模容器化生产环境中,Docker默认的日志驱动(json-file)暴露出显著瓶颈:日志文件无自动轮转、磁盘空间不可控、多容器日志检索低效、缺乏结构化字段支持,且无法与…...

如何用TaskbarX打造专业级Windows任务栏?终极美化完整指南

如何用TaskbarX打造专业级Windows任务栏?终极美化完整指南 【免费下载链接】TaskbarX Center Windows taskbar icons with a variety of animations and options. 项目地址: https://gitcode.com/gh_mirrors/ta/TaskbarX 想要让Windows任务栏焕然一新吗&…...

MCA Selector:终极Minecraft区块管理工具,轻松释放硬盘空间

MCA Selector:终极Minecraft区块管理工具,轻松释放硬盘空间 【免费下载链接】mcaselector A tool to select chunks from Minecraft worlds for deletion or export. 项目地址: https://gitcode.com/gh_mirrors/mc/mcaselector 你是否发现Minecra…...

终极指南:使用DS4Windows让PS4手柄完美兼容Windows游戏

终极指南:使用DS4Windows让PS4手柄完美兼容Windows游戏 【免费下载链接】DS4Windows Like those other ds4tools, but sexier 项目地址: https://gitcode.com/gh_mirrors/ds/DS4Windows DS4Windows是一款免费开源的手柄映射工具,专门解决PlayStat…...

BBDown终极指南:如何轻松下载B站视频的完整教程

BBDown终极指南:如何轻松下载B站视频的完整教程 【免费下载链接】BBDown Bilibili Downloader. 一个命令行式哔哩哔哩下载器. 项目地址: https://gitcode.com/gh_mirrors/bb/BBDown Bilibili Downloader(简称BBDown)是一款强大的命令行…...

Apex Legends压枪宏终极指南:告别后坐力,轻松实现精准射击

Apex Legends压枪宏终极指南:告别后坐力,轻松实现精准射击 【免费下载链接】Apex-NoRecoil-2021 Scripts to reduce recoil for Apex Legends. (auto weapon detection, support multiple resolutions) 项目地址: https://gitcode.com/gh_mirrors/ap/A…...

Real-ESRGAN-GUI终极指南:如何快速实现AI图像超分辨率增强

Real-ESRGAN-GUI终极指南:如何快速实现AI图像超分辨率增强 【免费下载链接】Real-ESRGAN-GUI Lovely Real-ESRGAN / Real-CUGAN GUI Wrapper 项目地址: https://gitcode.com/gh_mirrors/re/Real-ESRGAN-GUI Real-ESRGAN-GUI是一款基于Flutter开发的跨平台桌面…...

2026年Java后端开发技能树(附学习路线图)

2026年Java后端开发技能树:掌握未来技术的关键路径 在数字化转型加速的2026年,Java后端开发依然是企业级应用的核心支柱。随着云原生、AI集成和微服务架构的普及,开发者需要系统化更新技术栈。本文将通过一份2026年Java后端开发技能树&#…...

从一张TF卡开始:详解树莓派3B+系统烧录与网络配置中的那些‘坑’

树莓派3B系统烧录与网络配置实战避坑指南 第一次接触树莓派时,我满怀期待地按照网上的教程操作,却在烧录系统后遭遇了Windows提示"需要格式化TF卡"的尴尬。更糟的是,精心配置的WiFi连接始终无法建立,SSH连接也频频失败。…...

Bilibili视频转文字神器:3步实现高效智能的文字提取方案

Bilibili视频转文字神器:3步实现高效智能的文字提取方案 【免费下载链接】bili2text Bilibili视频转文字,一步到位,输入链接即可使用 项目地址: https://gitcode.com/gh_mirrors/bi/bili2text bili2text是一个专业的Bilibili视频转文字…...

PSIM仿真进阶:手把手教你用C语言模块实现自定义电路功能(从简化到通用C块详解)

PSIM仿真进阶:手把手教你用C语言模块实现自定义电路功能 在电力电子和控制系统仿真领域,PSIM凭借其高效的算法和友好的界面成为工程师的首选工具之一。但当我们遇到需要模拟特殊非线性控制器、定制传感器模型或复杂数据处理算法时,内置元件库…...

XQuery FLWOR 与 HTML 的结合:深度解析与实践指南

XQuery FLWOR 与 HTML 的结合:深度解析与实践指南 引言 XQuery 是一种用于处理 XML 和 XHTML 数据的查询语言,而 HTML 作为网页内容的载体,两者在数据检索和处理方面有着广泛的应用。本文将深入探讨 XQuery 的 FLWOR 模式与 HTML 的结合,分析其优势、应用场景及实践方法。…...

别再死记硬背FOC和DTC了!用‘开手动挡 vs 自动挡’的比喻,5分钟搞懂异步电机矢量控制的精髓

别再死记硬背FOC和DTC了!用‘开手动挡 vs 自动挡’的比喻,5分钟搞懂异步电机矢量控制的精髓 想象一下驾驶手动挡和自动挡汽车的区别——前者需要精准控制离合与油门的配合,后者则追求快速响应和简化操作。这种差异恰好对应了异步电机控制中**…...

AZ音乐下载器完整指南:轻松下载高品质音乐的终极教程

AZ音乐下载器完整指南:轻松下载高品质音乐的终极教程 【免费下载链接】AZMusicDownloader AZ音乐下载器 - 优雅地下载音乐 - 多API集成客户端 | Download music gracefully 项目地址: https://gitcode.com/gh_mirrors/az/AZMusicDownloader 还在为找不到心仪…...

别再只用WebRTC了!试试用WebSocket+AudioContext在Vue和SpringBoot里做个简易语音通话

WebSocketAudioContext:在Vue与SpringBoot中构建轻量级语音通话方案 当开发者需要实现浏览器端的语音通话功能时,WebRTC往往是第一选择。但WebRTC的复杂性——包括信令服务器、NAT穿透、编解码协商等——让许多简单场景下的开发变得过度复杂。实际上&…...

从B站视频保存难题到Java下载神器:BiliDownload的完整解决方案

从B站视频保存难题到Java下载神器:BiliDownload的完整解决方案 【免费下载链接】BiliDownload B站视频下载工具 项目地址: https://gitcode.com/gh_mirrors/bil/BiliDownload 作为一名B站内容创作者,你是否曾遇到过这样的困境:精心收藏…...

如何将照片从 iPhone 传输到笔记本电脑?4 种方法搞定

想把 iPhone 里的照片保存到笔记本电脑备份,却不知道怎么传输?别担心,有多种方法可以实现,包括使用iReaShare iPhone Manager、Windows 文件资源管理器、iCloud 照片库,以及电脑自带的 “照片” 应用。(如需…...