在指针中我学习了利用指针操作函数查询、存储数据返回多个值将函数结果与计算分开和指针高级指针高级其中有指针运算运算有无意义野指针和悬空指针void类型指针数组指针利用索引遍历数组得二种方法利用指针遍历数组二种方法函数指针。在字符串中我学习了字符串定义格式输入字符串遍历字符串数组字符串常见函数、练习用户登陆和统计次数。在结构体中我学习了结构体定义格式结构体数组起别名结构体作为函数参数传递结构体嵌套指针是什么内存地址指针本质是地址它的核心作用是定位内存作用1. 唯一标识一块内存——通过地址能精确找到某个变量/数据2. 作为参数传递——把地址传给函数让函数能操作原数据3. 作为返回值返回多个值——函数返回地址让调用者访问某块内存4. 构成数据结构——链表节点靠下一个节点的地址串联利用指针同时返回多个值//定义一个函数求数组中的最大值和最小值并进行返回 //1.定义数组 { int arr[] { 12,17,23,549,7,62,4 }; int len sizeof(arr) / sizeof(int); //2.定义变量最大值和最小值 int max arr[0]; int min arr[0]; //3.调用函数 getmaxandmin(arr, len, max, min); printf(数组最大值为%d\n, max); printf(数组最小值为%d\n, min); } void getmaxandmin(int arr[], int len,int* max,int* min) { //求数组的最大值 * max arr[0]; for (int i 1;i len;i) { if (arr[i] * max) { *max arr[i]; } } //求数组的最小值 * min arr[0]; for (int i 1;i len;i) { if (arr[i] *min) { *min arr[i]; } } } */指针变量是什么专门用来保存地址的变量作用1.间接访问-解引用2.函数传地址调用3.动态内存管理4.高效管理数组/字符串5.构建复杂数据结构6.实现多态/回调函数指针利用指针存储数据修改数据//1.定义一个变量 int a 10; //2.定义一个指针去指向变量a int* p a; //3.利用指针去获取变量a中的值 printf(%d\n, *p); //获取a的数据 printf(%d\n, p); //获取a的内存地址 //4.利用指针去存储变量/修改变量 *p 200; //5.输出打印 printf(%d\n, *p); //获取修改后a的数据 printf(%d\n, a); //修改后a的值指针高级指针运算步长指针移动一次的字节个数步长的大小与数据类型有关int -4 char-1 short-2 long-4 longlong-8int a 10; int* p a; //作用;用指针p记录变量a的地址 printf(%p\n, p); //输出是内存地址 printf(%p\n, p1); printf(%p\n, p-1);运算的有意义/无意义操作有意义操作1.指针跟整数进行加、减操作每次移动n个步长2.指针跟指针减操作可知二指针间隔步长int arr[] { 1,2,3,4,5,6,7,8,9,10 }; //获取0索引内存地址 int* p1 arr[0]; //通过指针p获取数据 printf(%d\n, *p1); printf(%d\n, *(p11)); //获取5索引内存地址 int* p2 arr[5]; //p2-p1间隔多少步长 printf(%d\n, p2 - p1); // 五个步长20个字节无意义操作1.指针跟整数进行乘、除操作这是错误的因为此时指针指向不明2.指针跟指针进行加、减、乘、除操作指向不明的指针野指针指针指当空间未分配悬空指针指针指向空间已经分配但是被释放了void类型指针格式void*p这个指针不表示任何类型无步长概念它只可以记录地址值可接受任何地址。不可以获得变量中的数据也不可以进行计算不同类型之间的指尖不可以进行互相赋值但void类型可以void类型可接受任意类型指针记录的内存地址注意事项在 C 语言中void*无类型指针是可以自动转换成任何其他类型的指针的隐式转换 而C 是一种非常严格的强类型语言。为了防止犯错它彻底取消了 void* 到其他具体类型指针的隐式转换 编译器行为一旦 VS 看到 .cpp它就会调用 C 编译器来编译这段代码它也会拿 C 的严格标准来审查你 所以.cpp无法自动转换任何其他类型的指针。如果改成.c再次编译VS 就会调用 C 编译器就可实现自动转换void类型互换数据//1.定义二个变量 int a 10; short b 20; //2.定义二个指针 int* p1 a; short* p2 b; //利用void类型直接互换 void* p3 p1; void* p4 p2;二级指针格式数据类型**指针名其中指针类型跟指向空间数据类型保持一致作用可以操作一级指针记录的地址(可以获取一级指针的地址也可以获取一级指针的数据也可以修改一级指针的内存地址//定义变量 int a 10; int b 20; //定义一级指针 int* p a; //定义二级指针指向一级指针p int** q p; //作用1.利用二级指针修改改一级指针里记录的内存地址 *q b; //作用2.利用二级指针获取变量中记录的值 printf(%p\n, a); printf(%p\n, b); printf(%p\n, p); printf(%p\n, *q); //解引1获取一级指针记录的内存地址 printf(%d\n, **q); //解引2获取到变量中的数据 打印结果数组指针是什么指向数组的指针作用方便操作数组中的各种数据细节arr直接参与计算的时候会自动退化为第一个元素的指针特殊情况1.sizeof参与计算时不会退化还是整体eg算数组长度2.arr获取地址时不会退化int arr[] { 1,2,3,4,5,6,7,8,9, }; int len sizeof(arr) / sizeof(int); //实际上获取的是数组的首地址然后再把首地址赋值给*p int *parr int* p arr[0];细节//sizeof 运算的时候不会退化arr还是整体 printf(%zu\n, sizeof(arr)); //36个字节 //1.首地址对比 printf(%p\n, arr); //一般用该种更多 printf(%p\n, arr); //2.步长对比 printf(%p\n, arr1); //4 printf(%p\n, arr1); //36二维数组是什么把多个小地址放到一个大数组中定义格式int arr[m][n] m是二维数组的长度n是一维数组的长度{成员1 成员2 ...... };利用索引遍历二维数组第一种方法局限于二维数组中每一个一维数组长度相同//1.定义二维数组 int arr[3][5] { { 1,2,3,4,5 }, { 2,3,4,5,6 }, { 3,4,5,6,7 } }; for (int i 0;i 3;i) //i依次表示二维数组中的索引 { //内循环遍历每一个一维数组 for (int j 0;j 5;j) //j依次表示一维数组中的索引 { printf(%d, arr[i][j]); } printf(\n); //当内循环结束表示一维数组遍历完毕 }第二种方法允许每一个一维数组长度不一样核心思路事先先把所有一维数组定义完毕再放入二维数组当中 //1.定义三个一维数组 int arr1[3] { 1,2,3 }; int arr2[4] { 1,2,3,4 }; int arr3[5] { 1,2,3,4,5 }; //预先计算每一个一维数组的长度 int len1 sizeof(arr1) / sizeof(int); int len2 sizeof(arr2) / sizeof(int); int len3 sizeof(arr3) / sizeof(int); //再定义一个数组表示每一个一维数组的长度 int len[3] { len1,len2,len3 }; //2.把三个一维数组放到二维数组中 //数组的数据类型与内部存储的元素类型保持一致 int* arr[3] { arr1,arr2,arr3 }; 指针数组 //此时二维数组存储的是一维数组的int类型的内存地址, arr数组元素类型是指向整数的指针也就是int* for (int i 0;i 3;i) { for (int j 0;j len[i];j) //len[i]依次表示三个一维数组的长度该处可体现长度不一样该如何表示 { printf(%d, arr[i][j]); } printf(\n); }利用指针遍历二维数组第一种方法利用二维数组指针遍历int arr[3][5] { { 1,2,3,4,5 }, { 2,3,4,5,6 }, { 3,4,5,6,7 } };//获取二维数组的指针 int(* p)[5] arr; 最关键的一步数组----指针//数组指针类型是与数组内部存储元素的数据类型保持一致 //二维数组里存的是一维数组且一维数组的数据类型是int又一维数组有5个int元素 for (int i 0;i 3;i) { //内循环遍历一维数组 for (int j 0;j 5;j) { printf(%d, *(*p j)); } printf(\n); //移动二维数组的指针继续遍历下一个一维数组 //(如果不移动指针遍历的一直都是第一个一维数组 p; }第二种方法指针数据指针遍历//1.定义三个一维数组 int arr1[3] { 1,2,3 }; int arr2[3] { 2,3,4 }; int arr3[3] { 3,4,5 }; //2,把这三个一维数组的内存地址放到二维数组当中 int* arr[3] { arr1,arr2,arr3 }; //此时这个二维数组是一个指针数组三个元素都是指针int*//3.获取指针 int* * p arr; 此时arr已经是指针了所以这里是二级指针//与方法一唯一不同就是获取指针----int(*p)[5] arr; //4.循环遍历数组 for (int i 0;i 3;i) { for (int j 0;j 3;j) { printf(%d, *(*p j)); } //换行 printf(\n); //移动指针 p; }函数指针定义格式返回值类型*指针名形参函数名 调用函数格式:1.调用无参函数指针名 2.调用有参函数数据类型 变量名指针名实参 这里定义变量是用来接受返回值作用利用函数指针动态调用函数//1.定义二个指针指向二个函数 void (*p1) () method1; int (*p2) (int, int) method2; //2.利用函数指针调用函数 p1(); int nump2(10,20); //定义一个临时变量接住它 printf(%d\n, num); } void method1() //无返回值 { printf(method1\n); } int method2(int num1, int num2) //有返回值 { printf(method2\n); return num1 num2;字符串获取字符串二种格式1.字符数组双引号char str1[4] abc;利用该方法可以修改字符串的内容2.指针双引号char* str2 abcd;利用该方法会把底层的字符放在只读常量区只读常量区特点1.内容不可以修改2.里面定义的字符串是可以复用的eg创建abc时会检查只读常量区有无abc如有不会创建新的而是进行复用 日无则会创建新的字符串数组在这里我们需要注意当我们遍历的是字符串数组时利用%s%s是专门用来接收地址的当在打印printf时printf拿到地址会自己去找需要的字符串根本不需要解引用*如加了*是会报错的 普通整数 (int) %d 具体的数字值 需要 (*p) 单个字符 (char) %c 具体的字符值 可加可不加 (c 或 *p 都行) 整个字符串 (char*) %s 字符串的首地址指针 绝对不能加 (str)//定义一个二维数组用来存储多个学生的名字,并遍历// 第一种方式二维数组char strarr[5][100] { xuanqi, xuanqii, xuuanqi, xuannqi, xuanqiqi }; //2.遍历二维数组 for (int i 0;i 5;i) //i表示二维数组中每一个索引 {char* str strarr[i];//strarr[i]表示二维数组中每i行一维数组的首地址利用char*str指针来接住这个地址printf(%s\n,str); //数组strarr是一块连续的500字节的内存每次i在内存中的跨度是100个字节 }//第二种方式//把五个字符串的指针放到一个数组中----(指针数组)char* strarr2[] { xuanqi, xuanqii, xuuanqi, xuannqi, xuanqiqi }; for (int i 0;i 5;i) //i表示二维数组中每一个索引 {char* str strarr2[i];//strarr2[i]表示指针数组中第i个元素这个元素本身就是一个char*类型的指针printf(%s\n,str); //数组strarr2是一块连续的40字节的内存存储5个指针每次i在内存中的跨度是8个字节 }字符串常见函数(在使用以下函数时应添加头文件string.hstrlen-获取字符串长度strcpy-复制字符串strcat-拼接二个字符串strcmp-比较二个字符串strlwr-字符串小写str字符串大写char* str1 abc; //底层会把字符数组放在只读常量区1.只可读不可修改2.复用 char str2[100] abcd; //可修改字符串内容 char str3[5] { x , a ,q,i,\0 };需要注意每个函数的使用格式和细节结构体结构体是什么可理解为自定义的数据类型由一批数据组合而成的结构性数据里面的每一个数据都是结构体的成员。书写位置函数里面--局部只可在本函数中使用---函数外面--全局在所有函数中均可使用格式struct 结构体名字 { 成员1 成员2 ..... }struct friend{ char name[100]; int age; char gender; double height; }; int main() { //使用结构体 //1.定义一个朋友类型的变量struct friendf1; //2.给朋友赋值strcpy(f1.name, 徐安琪1);//name是一个数组数组不可以整体进行赋值只能挨个元素赋值或者进行字符串函数复制 f1.age 18; f1.gender F; //在这里定义gender没有方括号只是一个普通的字符变量可以直接进行赋值 f1.height 1.68; //3.输出打印 printf(朋友的名字叫做%s\n,f1.name); printf(朋友的年龄为%d\n,f1.age); printf(朋友的性别为%c\n,f1.gender); printf(朋友的身高为%.2f\n,f1.height);结构体数组struct student { char name[100]; int age; }; int main() { //1.定义三个学生并直接进行赋值struct student stu1 { xuanqi,18 }; struct student stu2 { xuanqii,19 }; struct student stu3 { xuaanqi,20 }; //2.把三个学生放入到数组中struct student arr[3] { stu1,stu2,stu3 }; //3.遍历数组 for (int i 0;i 3;i) { struct student temp arr[i]; printf(学生信息为姓名为%s 年龄为%d\n,temp.name, temp.age); } }在上述二个代码中体现了二种结构体给变量赋值1.一个一个赋值struct friend stu1; strcpy(f1.name, 徐安琪1); stu1.age 18; stu1.gender F;2.批量赋值struct student stu1 { xuanqi,18 };起别名格式 typedef struct 结构体名字 { 成员1 成员2 ... }别名当起了别名在主函数定义的时候可以省略 struct 结构体名字直接使用别名即可结构体最为函数参数传递二种情况1.传递结构体中的数据值2.传递结构体的地址值传递推荐用指针传递传地址---因为利用指针传递结构体地址可以直接在函数内修改原结构体且避免拷贝typedef struct student { char name[100]; int age; }S; void method(S* p); //使用函数且函数里面使用到结构体所以申明必须写在结构体下面 int main() { //1.定义一个学生 S stu1; //2.给学生赋初始值 strcpy(stu1.name, aaa); stu1.age 0; //3.输出打印 printf(学生的初始数据姓名为%s 年龄为%d\n, stu1.name, stu1.age); //4.调用函数 method(stu1); //5.输出打印 printf(学生的修改后姓名为:%s 年龄为:%d\n, stu1.name, stu1.age); } void method(S*p)//S*pS*stu1,二者都是指针变量//无论是p还是stu1都是用来存内存地址的所以哪种表达都可以看自己那种可以理解 { printf(接收到main函数中学生的初始数据为:%s,%d\n,(*p).name,(*p).age); //为什么这里*p要小括号因为.成员访问运算符优先级高于*解引用运算符 //我们应先执行*p先把指针p指向的结构体变量stu1取出来 //再对这个取出来的结构体变量stu1中成员name进行访问 //修改 printf(请输入要修改学生的名字\n); scanf(%s, (*p).name);//(*p).name:表示先通过指针找到原结构体然后提取出这个结构体中name的成员printf(请输入要修改学生的年龄\n); scanf(%d, ((*p).age)); printf(在method函数中修改完的学生名字%s 年龄为%d\n, (*p).name, (*p).age); }结构体嵌套什么意思如果结构体成员的类型是其他结构体那么就用到了结构体嵌套struct message { char phone[12]; char mail[100]; }; struct student { char name[20]; int age; char gender; double height;struct message msg;//此时该成员ms的类型是其他结构体的}; //定义变量 struct student stu; //给成员赋值赋值时也有一点小区别 1.一个一个赋值strcpy(stu.msg.phone, 12345678910); strcpy(stu.msg.mail, 123456789qq.com);2.批量赋值(结构体嵌套在赋值时也要用大括号嵌套 struct student stu2 { 徐安琪,18,F,1.68,{ 12345678910,123456789qq.com }};
企业数字化 ERP 产品动态
相关推荐
行政不要再替同事背锅了!分享一套工作留痕办法 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/5 8:00:54
3小时写出飞行游戏,17天100万美元ARR 一个从没做过游戏的人,让 AI 写了个浏览器里的飞行模拟器,3 小时就上线了,17 天后做到 100 万美元 ARR。真正撑起这个数字的不是游戏本身,而是游戏里悬着的那几艘广告飞艇。
故事是什么
起点小得不能再小。2025 年 2 月 22 日&… · 2026/11/5 8:00:54
从零手写 SPMI Slave:Verilog 状态机、时序实现与仿真验证全流程实战 摘要:本文面向负责底层驱动与 IP 核开发的工程师,系统梳理 SPMI(System Power Management Interface)协议在 Slave 端的完整实现路径。文章从协议核心机制与 Slave 角色定位出发,依次覆盖开发环境与工程目录标准化、接口信号与时序参数约束、基于状态机的接收与命令解码、… · 2026/11/5 8:00:54
STM32F407六路串口DMA全开实战:零丢包多协议通信方案 简介:本资源是一套面向STM32嵌入式开发者的高实用性实验工程,聚焦STM32F407芯片在多路串口并发通信场景下的DMA高效传输与中断协同处理,适用于工业控制、物联网网关等需稳定管理6路UART的中高级开发者。压缩包含106个文件,主体为4… · 2026/11/5 8:29:10
WPS字体名相同却样式不同:分层排查字体回退与格式污染 排版这份活儿干久了,你会发现一个特别反直觉的现象:真正让人抓狂的往往不是"字体设错了",而是"字体明明设对了"。全选一遍,字体框里清清楚楚写着宋体,字号也是小四,可屏幕上就是有那么… · 2026/11/5 8:29:10
VB6凸轮设计系统:压力角与曲率半径实时计算闭环 简介:本资源是一份面向机械类本科生的《机械原理》课程大作业专项材料,聚焦凸轮机构的设计与分析核心内容,适用于课程设计、期末大作业及工程实践参考。资源为单个Word文档(.doc),大小363KB,内容… · 2026/11/5 8:29:10
过滤器模式解析:高效处理多条件筛选的设计与实践 1. 过滤器模式的核心概念解析 过滤器模式(Filter Pattern)是面向对象设计中一种结构型模式,它允许开发人员使用不同的标准来过滤一组对象,并通过逻辑运算以解耦方式组合这些标准。这种模式在集合处理场景中尤为常见,比… · 2026/11/5 8:29:10
MinIO端口混淆问题解析与正确配置指南 1. MinIO端口混淆问题解析:从403错误到正确配置 那天凌晨两点,服务器监控突然报警,文件上传服务大面积失败。我盯着日志里满屏的403 AccessDenied错误,第一反应是权限系统崩了。但当我看到错误请求指向203.186.109.106:55463这个端… · 2026/11/5 8:29:10
OpenMV与STM32F103C8T6串口通信实现物料搬运机器人视觉控制 简介:这份资源面向参加工程训练类比赛的学生与嵌入式初学者,提供一套基于OpenMV视觉模块与STM32F103C8T6微控制器的物料搬运机器人完整代码方案,用C语言实现图像识别、目标定位与运动控制的协同,解决机器人自主识别物料并完成抓取… · 2026/11/5 8:28:09
双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 3:16:49
STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 6:59:29
DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 7:02:38
多智能体协作系统架构设计与实践优化 1. 多智能体协作系统的时代背景2017年Transformer架构的诞生彻底改变了人工智能的发展轨迹。当行业还沉浸在单一大模型带来的性能突破时,Anthropic的研究团队已经将目光投向了更前沿的领域——如何让多个智能体通过协作产生超越单体能力的系统智能。这就像交响乐团中… · 2026/11/5 0:00:39
大模型系统性入门实战指南:从原理到部署微调的全链路路线 提到大模型的系统性入门,我先说个结论:这事真不难,难的是资料太散、路线太多,今天这个框架明天那个工具,新人很容易在“收藏夹吃灰”和“教程看到一半放弃”之间反复横跳。市面上关于大模型的内容少说有几十万篇&#… · 2026/11/5 0:00:39
鸿蒙文件系统沙箱机制解析与开发实践 1. 鸿蒙文件系统沙箱机制深度解析作为一名从Android转向鸿蒙开发的工程师,我深刻体会到文件系统访问是迁移过程中最先遇到的"拦路虎"。在Android上运行良好的文件读写代码,在鸿蒙真机环境却频频出现文件写入后神秘消失或直接抛出权限拒绝错误的… · 2026/11/5 0:00:39
双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 3:16:49
STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 6:59:29
DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 7:02:38