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

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;
}

在这里插入图片描述

============================================================================

  1. 函数封装数组初始化和遍历
  2. 作为形参的指针,在调用函数时也会分配自己的一个地址,作为指针,指向传过来的地址(下面传过来的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语言杂记(指针篇)

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

ES window 系统环境下连接问题

环境问题&#xff1a;&#xff08;我采用的版本是 elasticsearch-7.9.3&#xff09;注意 开始修正之前的配置&#xff1a;前提&#xff1a;elasticsearch.yml增加或者修正一下配置&#xff1a;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 基本概念 我们都使用过连接池&#xff0c;比如C3P0、DBCP、hikari、Druid&#xff0c;虽然 HikariCP 的速度稍快&#xff0c;但 Druid 能够提供强大的监控和扩展功能。Druid DataSource 是阿里巴巴开发的号称为监控而生的数据库连接池&#xff0c;它不仅可以…...

maven镜像源及代理配置

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

【Java面试篇】Spring中@Transactional注解事务失效的常见场景

文章目录Transactional注解的失效场景☁️前言&#x1f340;前置知识&#x1f341;场景一&#xff1a;Transactional应用在非 public 修饰的方法上&#x1f341;场景二&#xff1a; propagation 属性设置错误&#x1f341;场景三&#xff1a;rollbackFor属性设置错误&#x1f3…...

【C】分配内存的函数

#include <stdlib.h>//分配所需的内存空间&#xff0c;并返回一个指向它的指针。 void *malloc(size_t size);//分配所需的内存空间&#xff0c;并返回一个指向它的指针。并且calloc负责把这块内存空间用字节0填//充&#xff0c;而malloc并不负责把分配的内存空间清零 vo…...

IDEA 断点总是进入class文件没有进入源文件解决

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

【flink】 flink入门教程demo 初识flink

文章目录通俗解释什么是flink及其应用场景flink处理流程及核心APIflink代码快速入门flink重要概念什么是flink&#xff1f; 刚接触这个词的同学 可能会觉得比较难懂&#xff0c;网上搜教程 也是一套一套的官话&#xff0c; 如果大家熟悉stream流&#xff0c;那或许会比较好理解…...

LeetCode 1487. 保证文件名唯一

【LetMeFly】1487.保证文件名唯一 力扣题目链接&#xff1a;https://leetcode.cn/problems/making-file-names-unique/ 给你一个长度为 n 的字符串数组 names 。你将会在文件系统中创建 n 个文件夹&#xff1a;在第 i 分钟&#xff0c;新建名为 names[i] 的文件夹。 由于两个…...

详细剖析|袋鼠云数栈前端框架Antd 3.x 升级 4.x 的踩坑之路

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

【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类型&#xff1a;字符和小整数3.1.9 bool类型3.2 const修饰符3.3浮点数3.3.1 书写浮点数3…...

【基础算法】单链表的OJ练习(1) # 反转链表 # 合并两个有序链表 #

文章目录前言反转链表合并两个有序链表写在最后前言 上一章讲解了单链表 -> 传送门 <- &#xff0c;后面几章就对单链表进行一些简单的题目练习&#xff0c;目的是为了更好的理解单链表的实现以及加深对某些函数接口的熟练度。 本章带来了两个题目。一是反转链表&#x…...

离散数学笔记(1)命题逻辑

文章目录1.命题符号化及联结词基本概念本节题型2.命题公式及分类基本概念本节题型1.命题符号化及联结词 基本概念 命题的定义&#xff1a;能够判断真假的陈述句称为命题。 备注&#xff1a;感叹句、疑问句、祈使句和类似于xy>5之类真值不唯一的句子都不是命题。 真值的真假…...

IDEA Android 网格布局(GridLayout)示例(计算器界面布局)

网格布局(GridLayout&#xff09; 示例程序效果&#xff08;实现类似vivo手机自带计算器UI&#xff09; 真机和模拟器运行效果&#xff1a; 简述&#xff1a; GridLayout(网格布局)和TableLayout&#xff08;表格布局&#xff09;有类似的地方&#xff0c;通俗来讲可以理解为…...

【蓝桥杯嵌入式】拓展板之数码管显示

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

Web Spider案例 网洛克 第三题 AAEncode加密 练习(七)

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

【javaScript面试题】2023前端最新版javaScript模块,高频24问

&#x1f973;博 主&#xff1a;初映CY的前说(前端领域) &#x1f31e;个人信条&#xff1a;想要变成得到&#xff0c;中间还有做到&#xff01; &#x1f918;本文核心&#xff1a;博主收集的关于javaScript的面试题 目录 一、2023javaScript面试题精选 1.js的数据类型…...

Hadoop集群启动从节点没有DataNode

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

FIFO IP Core

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

挑战杯推荐项目

“人工智能”创意赛 - 智能艺术创作助手&#xff1a;借助大模型技术&#xff0c;开发能根据用户输入的主题、风格等要求&#xff0c;生成绘画、音乐、文学作品等多种形式艺术创作灵感或初稿的应用&#xff0c;帮助艺术家和创意爱好者激发创意、提高创作效率。 ​ - 个性化梦境…...

shell脚本--常见案例

1、自动备份文件或目录 2、批量重命名文件 3、查找并删除指定名称的文件&#xff1a; 4、批量删除文件 5、查找并替换文件内容 6、批量创建文件 7、创建文件夹并移动文件 8、在文件夹中查找文件...

边缘计算医疗风险自查APP开发方案

核心目标:在便携设备(智能手表/家用检测仪)部署轻量化疾病预测模型,实现低延迟、隐私安全的实时健康风险评估。 一、技术架构设计 #mermaid-svg-iuNaeeLK2YoFKfao {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg…...

关于iview组件中使用 table , 绑定序号分页后序号从1开始的解决方案

问题描述&#xff1a;iview使用table 中type: "index",分页之后 &#xff0c;索引还是从1开始&#xff0c;试过绑定后台返回数据的id, 这种方法可行&#xff0c;就是后台返回数据的每个页面id都不完全是按照从1开始的升序&#xff0c;因此百度了下&#xff0c;找到了…...

转转集团旗下首家二手多品类循环仓店“超级转转”开业

6月9日&#xff0c;国内领先的循环经济企业转转集团旗下首家二手多品类循环仓店“超级转转”正式开业。 转转集团创始人兼CEO黄炜、转转循环时尚发起人朱珠、转转集团COO兼红布林CEO胡伟琨、王府井集团副总裁祝捷等出席了开业剪彩仪式。 据「TMT星球」了解&#xff0c;“超级…...

【SQL学习笔记1】增删改查+多表连接全解析(内附SQL免费在线练习工具)

可以使用Sqliteviz这个网站免费编写sql语句&#xff0c;它能够让用户直接在浏览器内练习SQL的语法&#xff0c;不需要安装任何软件。 链接如下&#xff1a; sqliteviz 注意&#xff1a; 在转写SQL语法时&#xff0c;关键字之间有一个特定的顺序&#xff0c;这个顺序会影响到…...

Neo4j 集群管理:原理、技术与最佳实践深度解析

Neo4j 的集群技术是其企业级高可用性、可扩展性和容错能力的核心。通过深入分析官方文档,本文将系统阐述其集群管理的核心原理、关键技术、实用技巧和行业最佳实践。 Neo4j 的 Causal Clustering 架构提供了一个强大而灵活的基石,用于构建高可用、可扩展且一致的图数据库服务…...

CMake 从 GitHub 下载第三方库并使用

有时我们希望直接使用 GitHub 上的开源库,而不想手动下载、编译和安装。 可以利用 CMake 提供的 FetchContent 模块来实现自动下载、构建和链接第三方库。 FetchContent 命令官方文档✅ 示例代码 我们将以 fmt 这个流行的格式化库为例,演示如何: 使用 FetchContent 从 GitH…...

图表类系列各种样式PPT模版分享

图标图表系列PPT模版&#xff0c;柱状图PPT模版&#xff0c;线状图PPT模版&#xff0c;折线图PPT模版&#xff0c;饼状图PPT模版&#xff0c;雷达图PPT模版&#xff0c;树状图PPT模版 图表类系列各种样式PPT模版分享&#xff1a;图表系列PPT模板https://pan.quark.cn/s/20d40aa…...

稳定币的深度剖析与展望

一、引言 在当今数字化浪潮席卷全球的时代&#xff0c;加密货币作为一种新兴的金融现象&#xff0c;正以前所未有的速度改变着我们对传统货币和金融体系的认知。然而&#xff0c;加密货币市场的高度波动性却成为了其广泛应用和普及的一大障碍。在这样的背景下&#xff0c;稳定…...