C语言杂记(指针篇)
指针篇
指针就是地址,地址就是指针 指针变量就是存放地址的变量
*号只有定义的时候表示定义指针变量,其他表示从地址里面取内容
通过指针的方法使main函数中的data1和data2发生数据交换。
#include <stdio.h>
void chang_data(int *data1,int *data2)
{int tmp;tmp = *data1;*data1 = *data2;*data2 = tmp;}int main()
{int data1 = 10;int data2 = 20;chang_data(&data1,&data2);printf("data1:%d data2:%d\n",data1,data2);return 0;
}
============================================================================
指针指向固定的区域
volatile :防止编译器进行编译优化,导致原来的值发生变化
#include <stdio.h>int main()
{volatile unsigned int *p = (volatile unsigned int *)0x0000000001234567;printf("p:%p\n",p);return 0;
}
============================================================================
输入三个数,要求不管怎么输入,在输出的时候要由大到小输出,用函数封装的方法
#include <stdio.h>
int func(int *data1,int *data2,int *data3)
{int tmp;if(*data1 < *data2){tmp = *data1;*data1 = *data2;*data2 = tmp;}if(*data1 < *data3){tmp = *data1;*data1 = *data3;*data3 = tmp;}if(*data2 < *data3){tmp = *data2;*data2 = *data3;*data3 = tmp;}}
int main()
{int data1;int data2;int data3;scanf("%d %d %d",&data1,&data2,&data3);func(&data1,&data2,&data3);printf("大到小:%d %d %d \n",data1,data2,data3);return 0;
}
============================================================================
1.定义一个指针变量指向数组
在C语言当中,数组名(不包括形参数组名)代表数组中首元素的地址,所以p = &a[0];//或者p =a;这两个等价的
2. 指针的偏移,偏移多少根据指针的类型,int偏移四个字节,char就偏移一个字节,使用的指针偏移遍历数组
3.指针的访问效率是远远大于数组下标的访问效率的
int main()
{int i = 0;int a[] = {1,2,3};int *p;p = &a[0];//或者p = a;for(i=0;i<sizeof(a)/sizeof(a[0]);i++){printf("a[%d] = %d \n",i,*p++);}p = a;//让指针重新指向数组的首元素地址return 0;
}
============================================================================
64位操作系统,一个指针占8个字节,所以八个字节表示一个地址
struct demo{int a;char c;
};
int main()
{struct demo *test;printf("sizeof int *:%d\n",sizeof(int *));printf("sizeof char *:%d\n",sizeof(char *));printf("sizeof double *:%d\n",sizeof(double *));printf("sizeof struct *:%d\n",sizeof(test));return 0;
}
============================================================================
- 函数封装数组初始化和遍历
- 作为形参的指针,在调用函数时也会分配自己的一个地址,作为指针,指向传过来的地址(下面传过来的main函数arr的首地址),后续就是对传过来的地址进行操作
ps:下面输出遍历的时候为什么不用把parr重新指向arr的首地址,因为这是两个函数,每个传过来的就是parr就是arr的首地址
#include <stdio.h>void Init_arr(int *parr,int len)
{int i= 0;for(i=0;i<len;i++){*parr = i;parr++; }
}void Printf_arr(int *parr,int len)
{int *tmp2;for(int i = 0;i<len;i++){printf("arr:%d\n",*parr);parr++;}}int main()
{int arr[5];int len = sizeof(arr)/sizeof(arr[0]);Init_arr(arr,len);Printf_arr(arr,len);return 0;
}
============================================================================
练习:数组翻转
#include <stdio.h>void Init_arr(int *parr,int len)
{int i= 0;for(i=0;i<len;i++){*parr = i;parr++; }
}void Overturn_arr(int *arr,int len)
{int i,j;int tmp;for(i=0;i<(len/2);i++){j = len-1-i;tmp = *(arr+i);*(arr+i) = *(arr+j);*(arr+j) = tmp;
}
}
void Printf_arr(int *parr,int len)
{for(int i = 0;i<len;i++){printf("arr:%d\n",*parr);parr++;}}int main()
{int arr[5];int len = sizeof(arr)/sizeof(arr[0]);Init_arr(arr,len);Overturn_arr(arr,len);Printf_arr(arr,len);return 0;
}
============================================================================
二维数组的认知 现在有一个二维数组,我们可以把二维数组理解为父子数组,还有数组名就是地址
int a[3][4] = {{1,2,3,4},{5,6,7,8},{9,10,11,12}};
那么父数组的名字就是a,而字数组的名字就是a[0],a[1],a[2],那么我们可以看出a的地址和a[0]的地址是一样的,但是要注意他们的偏移量是不一样的,a+1偏移的是一整个子数组的大小,a[0]+1是偏移一个数组元素的大小。
a[0] 等价于 &a[0][0] a[1]等价于 = &a[1][0] a[2]等价于 = &a[2][0]
那么a表示父数组的地址,a[0]表示的字数组的首地址
(a)等价与a[0]的首地址(因为a不可能取到整个子数组的值),*(a)+1就是(a[0])+1
#include <stdio.h>
int main()
{int a[3][4] = {{1,2,3,4},{5,6,7,8},{9,10,11,12}};printf("a父数组地址 IP:%p %d\n",a,*(a));printf("a[0]子数组地址 IP:%p %d\n",a[0],*(a[0]));printf("a+1父数组地址偏移 IP:%p %d\n",(a+1),*(a+1));printf("a[0]+1字数组地址偏移 IP:%p %d\n",(a[0]+1),*(a[0]+1));//*(a)等价与a[0]的首地址,*(a)+1就是(a[0])+1printf("*(a)字数组地址偏移 IP:%p *(a)+1的地址: %p\n",*(a),*(a)+1);return 0;
}
总结:
============================================================================
数组指针:就是数组的指针,其实就是一个指向数组的指针。 数组指针才是等同于二维数组名
#include <stdio.h>
int main()
{int arr[2][3] = {{1,2,3},{4,5,6}};int (*p)[3];//指向有3个元素数组的指针p = arr;int i,j;printf("p=%p\n",p);printf("++p:%p\n",++p);//这里看出地址偏移是12字节,就是一个子数组的大小p = arr;//这里让p重新指向二维数组名,再使用p遍历数组for(i=0;i<2;i++){for(j=0;j<3;j++){//printf("arr:%d\n",arr[i][j]);printf("arr:%d\n",*(*(p+i)+j));}}return 0;
}
============================================================================
数组指针的和二维数组的配合使用
题目:用数组指针方法,输出二维数组任意行列的数
#include <stdio.h>void InputNum(int *hang,int *lie)
{printf("输入行列号:\n");scanf("%d %d",hang,lie);
}int SearchNum(int (*p)[4],int hang,int lie)
{return (*(*(p+hang)+lie));
}int main()
{int a[3][4] = {{0,1,2,3},{4,5,6,7},{8,9,10,11}};int hang,lie;int data;//提示输出InputNum(&hang,&lie);//找到对于的数字data = SearchNum(a,hang,lie);//打印出来printf("第%d行第%d列的数字为:%d\n",hang,lie,data);return 0;
}
============================================================================
函数指针,就是一个指向函数入口地址的指针。
1.函数指针:如果程序中定义了一个函数,在编译的时候,编译系统会为函数代码分配一段存储空间,这段存储空间的起始地址(又成为入口地址)称为这个函数的指针。
2.函数名就是地址
3.如何定义一个函数指针变量:int (*p)(int a,int b)
4.定义函数指针的时候要和指向的函数的类型保持一致
#include <stdio.h>void printfWeclme()
{printf("hello world\n");}int DataAdd(int data)
{return ++data;}int main()
{void (*p)(); //函数指针的定义int (*p2)(int data);p = printfWeclme;//指向printfWeclme这个函数p2 = DataAdd;(*p)();//利用函数指针调用这个函数printf("++data:%d\n",(*p2)(10));return 0;
}
练习:用函数指针实现两个整数ab,输入1 2 或者3,1:输出ab中的大者,2:输出ab中的小者,3:输出ab之和
#include <stdio.h>
#include <stdlib.h>
int GetMax(int a,int b)
{int Max;if(a>b){Max = a;}else{Max = b;}return Max;
}int GetMin(int a,int b)
{int Min;if(a<b){Min = a;}else{Min = b;}return Min;
}float GetAvg(int a,int b)
{return ((float)a+(float)b)/2;
}int dataHandler(int a,int b,int (*func1)(int,int))
{int ret;ret = (*func1)(a,b);return ret;}float dataHandler2(int a,int b,float (*func2)(int,int))
{float ret;ret = (*func2)(a,b);return ret;}
int main()
{int a = 10;int b = 20;int mark;int ret;float ret2;int (*func1)(int,int);float (*func2)(int,int);printf("Input:");scanf("%d",&mark);switch(mark){case 1:func1 = GetMax;break;case 2:func1 = GetMin;break;case 3:func2 = GetAvg;break;default:printf("Input error\n");exit(-1);}if(mark != 3){ret = dataHandler(a,b,func1);printf("ret:%d\n",ret);}else{ret2 = dataHandler2(a,b,func2);printf("ret2:%0.2f\n",ret2);}return 0;
}
============================================================================
数组指针:
理解::指针数组就是存放指针的数组,数组的每一项都是指针变量
int main()
{int a = 1;int b = 2;int c = 3;int* arr[3] = {&a,&b,&c};for(int i=0;i<3;i++){printf("%d ",*(arr[i]));} return 0;
}
定义一个函数指针数组,然后进行函数调用:
#include <stdio.h>
#include <stdlib.h>int GetMax(int a,int b)
{int Max;if(a>b){Max = a;}else{Max = b;}printf("Max:%d\n",Max);return Max;
}int GetMin(int a,int b)
{int Min;if(a>b){Min = b;}else{Min = a;}printf("Min:%d\n",Min);return Min;
}int main()
{int a = 10;int b = 20;int (*pfun[2])(int,int) = {GetMax,GetMin};//定义了一个指向函数入口的函数指针数组,每一项都指向一个函数入口地址for(int i=0;i<2;i++){(*pfun[i])(a,b);//进行调用}return 0;
}
============================================================================
指针函数:返回指针值的函数
有3个学生,每个学生对于四门成绩,要求用用户输入学生序号后,输出该学生的全部成绩。用函数指针实现
#include <stdio.h>int *getPosPenson(int pos,int (*pstu)[4])//函数指针
{int *p;p = (int *)(pstu+pos);return p;}int main()
{int arr[3][4] = {{1,2,3,4},{5,6,7,8},{45,52,63,54} };int *ppos;int pos;//学生0 1 2do{printf("输入学生012:");scanf("%d",&pos);}while(pos!=0 && pos!=1 && pos!=2 );ppos = getPosPenson(pos,arr);for(int i=0;i<4;i++){printf("%d ",*(ppos++));}return 0;
}
============================================================================
二级指针:保存指针地址的指针
#include <stdio.h>int main()
{int data = 10;int *p;p = &data;int **p2;printf("data的地址:%p\n",&data);printf("p存放的地址(data的地址):%p\n",p);printf("p本身的地址:%p\n",&p);p2 = &p;printf("p2保存的地址(p本身的地址):%p\n",p2);printf("*p2是:%p\n",*p2);//这里取到的应该是data的地址printf("**p2是:%d\n",**p2);//这里就取到data的值了return 0;
}
============================================================================
下面对于ppos的理解
#include <stdio.h>void getPosPenson(int pos,int (*pstu)[4],int **ppos)//函数指针
{*ppos = (int *)(pstu+pos);//*ppos取到的就是main函数一级指针ppos的地址,这个指针指向了pstu这个指针的偏移地址,所以main函数中的ppos就再*(取一次内容)就访问到里面的值了}int main()
{int arr[3][4] = {{1,2,3,4},{5,6,7,8},{45,52,63,54} };int *ppos;int pos;//学生0 1 2do{printf("输入学生012:");scanf("%d",&pos);}while(pos!=0 && pos!=1 && pos!=2 );getPosPenson(pos,arr,&ppos);//这里传过去的时ppos的地址(指针的地址需要二级指针来承接)for(int i=0;i<4;i++){printf("%d ",*(ppos++));}return 0;
}
============================================================================
二级指针不能简单粗暴指向二维数组
============================================================================
搞懂下面这张图
================================================================================================================================================================
相关文章:

C语言杂记(指针篇)
指针篇 指针就是地址,地址就是指针 指针变量就是存放地址的变量 *号只有定义的时候表示定义指针变量,其他表示从地址里面取内容 通过指针的方法使main函数中的data1和data2发生数据交换。 #include <stdio.h> void chang_data(int *data1,int *da…...

ES window 系统环境下连接问题
环境问题:(我采用的版本是 elasticsearch-7.9.3)注意 开始修正之前的配置:前提:elasticsearch.yml增加或者修正一下配置:xpack.security.enabled: truexpack.license.self_generated.type: basicxpack.secu…...

hexo部署github搭建个人博客 完整详细带图版(更新中)
文章目录0. 前置内容1. hexo创建个人博客2. GitHub创建仓库3. hexo部署到GitHub4. 常用命令newcleangenerateserverdeploy5. 添加插件5.1 主题5.2 博客基本信息5.3 创建新的菜单5.4 添加搜索功能5.5 添加阅读时间字数提示5.6 打赏功能5.7 切换主题5.8 添加不蒜子统计5.9 添加百…...

SpringBoot集成DruidDataSource实现监控 SQL 性能
一、快速入门 1.1 基本概念 我们都使用过连接池,比如C3P0、DBCP、hikari、Druid,虽然 HikariCP 的速度稍快,但 Druid 能够提供强大的监控和扩展功能。Druid DataSource 是阿里巴巴开发的号称为监控而生的数据库连接池,它不仅可以…...

maven镜像源及代理配置
在公司使用网络一般需要设置代理, 我在idea中创建springboot工程时,发现依赖下载不了,原以为只要浏览器设置代理,其他的网络访问都会走代理,经过查资料设置了以下几个地方后工程创建正常,在此记录给大家参考…...

【Java面试篇】Spring中@Transactional注解事务失效的常见场景
文章目录Transactional注解的失效场景☁️前言🍀前置知识🍁场景一:Transactional应用在非 public 修饰的方法上🍁场景二: propagation 属性设置错误🍁场景三:rollbackFor属性设置错误dz…...
【C】分配内存的函数
#include <stdlib.h>//分配所需的内存空间,并返回一个指向它的指针。 void *malloc(size_t size);//分配所需的内存空间,并返回一个指向它的指针。并且calloc负责把这块内存空间用字节0填//充,而malloc并不负责把分配的内存空间清零 vo…...

IDEA 断点总是进入class文件没有进入源文件解决
前言 idea 断点总是进入class文件没有进入源文件解决 问题 在源文件里打了断点,断点模式启动时却进入了class文件里的断点,而没有进入到java源文件里的断点。 比如:我在 A.java 里打了断点,调试时却进入到了 jar 包里的 A.clas…...

【flink】 flink入门教程demo 初识flink
文章目录通俗解释什么是flink及其应用场景flink处理流程及核心APIflink代码快速入门flink重要概念什么是flink? 刚接触这个词的同学 可能会觉得比较难懂,网上搜教程 也是一套一套的官话, 如果大家熟悉stream流,那或许会比较好理解…...
LeetCode 1487. 保证文件名唯一
【LetMeFly】1487.保证文件名唯一 力扣题目链接:https://leetcode.cn/problems/making-file-names-unique/ 给你一个长度为 n 的字符串数组 names 。你将会在文件系统中创建 n 个文件夹:在第 i 分钟,新建名为 names[i] 的文件夹。 由于两个…...

详细剖析|袋鼠云数栈前端框架Antd 3.x 升级 4.x 的踩坑之路
袋鼠云数栈从2016年发布第⼀个版本开始,就始终坚持着以技术为核⼼、安全为底线、提效为⽬标、中台为战略的思想,坚定不移地⾛国产化信创路线,不断推进产品功能迭代、技术创新、服务细化和性能升级。 在数栈过去的产品迭代中受限于当前组件的…...

【C++PrimerPlus】第三章 处理数据
文章目录前言内容目录3.1 简单变量3.1.2 变量名3.1.2 整形3.1.3 整形short,int,long,long long3.1.4 无符号类型3.1.5 选择整形类型3.1.6 整形字面值3.1.7 C如何确定常量的类型3.1.8 char类型:字符和小整数3.1.9 bool类型3.2 const修饰符3.3浮点数3.3.1 书写浮点数3…...

【基础算法】单链表的OJ练习(1) # 反转链表 # 合并两个有序链表 #
文章目录前言反转链表合并两个有序链表写在最后前言 上一章讲解了单链表 -> 传送门 <- ,后面几章就对单链表进行一些简单的题目练习,目的是为了更好的理解单链表的实现以及加深对某些函数接口的熟练度。 本章带来了两个题目。一是反转链表&#x…...
离散数学笔记(1)命题逻辑
文章目录1.命题符号化及联结词基本概念本节题型2.命题公式及分类基本概念本节题型1.命题符号化及联结词 基本概念 命题的定义:能够判断真假的陈述句称为命题。 备注:感叹句、疑问句、祈使句和类似于xy>5之类真值不唯一的句子都不是命题。 真值的真假…...

IDEA Android 网格布局(GridLayout)示例(计算器界面布局)
网格布局(GridLayout) 示例程序效果(实现类似vivo手机自带计算器UI) 真机和模拟器运行效果: 简述: GridLayout(网格布局)和TableLayout(表格布局)有类似的地方,通俗来讲可以理解为…...

【蓝桥杯嵌入式】拓展板之数码管显示
文章目录硬件电路连接方式函数实现文章福利硬件电路 通过上述原理图,可知拓展板上的数码管是一个共阴数码管,也就是说某段数码管接上高电平时,就会点亮。 上述原理图还给出一个提示,即:三个数码管分别与三个74HC59…...

Web Spider案例 网洛克 第三题 AAEncode加密 练习(七)
声明 此次案例只为学习交流使用,抓包内容、敏感网址、数据接口均已做脱敏处理,切勿用于其他非法用途; 文章目录声明一、资源推荐二、逆向目标三、抓包分析 & 下断分析逆向3.1 抓包分析3.2 下断分析逆向拿到混淆JS代码3.3 AAEncode解决方…...

【javaScript面试题】2023前端最新版javaScript模块,高频24问
🥳博 主:初映CY的前说(前端领域) 🌞个人信条:想要变成得到,中间还有做到! 🤘本文核心:博主收集的关于javaScript的面试题 目录 一、2023javaScript面试题精选 1.js的数据类型…...

Hadoop集群启动从节点没有DataNode
一、问题背景 之前启动hadoop集群的时候都没有问题,今天启动hadoop集群的时候,从节点的DataNode没有启动起来。 二、解决思路 遇见节点起不来的情况,可以去看看当前节点的日志文件 我进入当前从节点的hadoop安装目录的Logs文件下去查看日…...

FIFO IP Core
FIFO IP Core 先进先出的缓存器常常被用于数据的缓存,或者高速异步数据交互(跨时钟信号传递)和RAM和ROM的区别是没有地址线,无法指定地址 写时钟(Write Clock Domain),读时钟写复位(wr_rst),读…...

阿里云ACP云计算备考笔记 (5)——弹性伸缩
目录 第一章 概述 第二章 弹性伸缩简介 1、弹性伸缩 2、垂直伸缩 3、优势 4、应用场景 ① 无规律的业务量波动 ② 有规律的业务量波动 ③ 无明显业务量波动 ④ 混合型业务 ⑤ 消息通知 ⑥ 生命周期挂钩 ⑦ 自定义方式 ⑧ 滚的升级 5、使用限制 第三章 主要定义 …...

大数据零基础学习day1之环境准备和大数据初步理解
学习大数据会使用到多台Linux服务器。 一、环境准备 1、VMware 基于VMware构建Linux虚拟机 是大数据从业者或者IT从业者的必备技能之一也是成本低廉的方案 所以VMware虚拟机方案是必须要学习的。 (1)设置网关 打开VMware虚拟机,点击编辑…...

高等数学(下)题型笔记(八)空间解析几何与向量代数
目录 0 前言 1 向量的点乘 1.1 基本公式 1.2 例题 2 向量的叉乘 2.1 基础知识 2.2 例题 3 空间平面方程 3.1 基础知识 3.2 例题 4 空间直线方程 4.1 基础知识 4.2 例题 5 旋转曲面及其方程 5.1 基础知识 5.2 例题 6 空间曲面的法线与切平面 6.1 基础知识 6.2…...

相机从app启动流程
一、流程框架图 二、具体流程分析 1、得到cameralist和对应的静态信息 目录如下: 重点代码分析: 启动相机前,先要通过getCameraIdList获取camera的个数以及id,然后可以通过getCameraCharacteristics获取对应id camera的capabilities(静态信息)进行一些openCamera前的…...

基于Docker Compose部署Java微服务项目
一. 创建根项目 根项目(父项目)主要用于依赖管理 一些需要注意的点: 打包方式需要为 pom<modules>里需要注册子模块不要引入maven的打包插件,否则打包时会出问题 <?xml version"1.0" encoding"UTF-8…...

令牌桶 滑动窗口->限流 分布式信号量->限并发的原理 lua脚本分析介绍
文章目录 前言限流限制并发的实际理解限流令牌桶代码实现结果分析令牌桶lua的模拟实现原理总结: 滑动窗口代码实现结果分析lua脚本原理解析 限并发分布式信号量代码实现结果分析lua脚本实现原理 双注解去实现限流 并发结果分析: 实际业务去理解体会统一注…...
pycharm 设置环境出错
pycharm 设置环境出错 pycharm 新建项目,设置虚拟环境,出错 pycharm 出错 Cannot open Local Failed to start [powershell.exe, -NoExit, -ExecutionPolicy, Bypass, -File, C:\Program Files\JetBrains\PyCharm 2024.1.3\plugins\terminal\shell-int…...
【FTP】ftp文件传输会丢包吗?批量几百个文件传输,有一些文件没有传输完整,如何解决?
FTP(File Transfer Protocol)本身是一个基于 TCP 的协议,理论上不会丢包。但 FTP 文件传输过程中仍可能出现文件不完整、丢失或损坏的情况,主要原因包括: ✅ 一、FTP传输可能“丢包”或文件不完整的原因 原因描述网络…...
React核心概念:State是什么?如何用useState管理组件自己的数据?
系列回顾: 在上一篇《React入门第一步》中,我们已经成功创建并运行了第一个React项目。我们学会了用Vite初始化项目,并修改了App.jsx组件,让页面显示出我们想要的文字。但是,那个页面是“死”的,它只是静态…...

Qwen系列之Qwen3解读:最强开源模型的细节拆解
文章目录 1.1分钟快览2.模型架构2.1.Dense模型2.2.MoE模型 3.预训练阶段3.1.数据3.2.训练3.3.评估 4.后训练阶段S1: 长链思维冷启动S2: 推理强化学习S3: 思考模式融合S4: 通用强化学习 5.全家桶中的小模型训练评估评估数据集评估细节评估效果弱智评估和民间Arena 分析展望 如果…...