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

「1」指针进阶——详解

🚀🚀🚀大家觉不错的话,就恳求大家点点关注,点点小爱心,指点指点🚀🚀🚀 

目录

🐰指针的回顾

🐰字符指针

🐰指针数组

🌸模拟二维数组(整形)

🐰数组指针

🌸数组指针和指针数组的区分

🌸&数组名和数组名的区别

🌸数组指针p,*p等价于arr,*p就是数组名

🌸数组指针的使用

🌸数组参数和指针参数

🐰函数指针-指向函数的指针

🌸函数指针数组


🐰指针的回顾

1.指针是内存中一个最小单元的编号,也就是地址

2.平时口语上所说的指针,通常指的是指针变量,是用来存放地址的变量

3.把内存划分为一个个的内存单元,这个内存单元大小是1字节,从概念上讲:编号 == 地址 == 指针

指针变量:

我们可以通过& (取地址操作符) 取出变量的内存起始地址,把地址可以存放到一个变量中,这个变量就是指针变量

4.指针大小(4字节 32位/8字节 64位)

🐰字符指针

#include<stdio.h>
int main()
{char ch='w';char* pc=&ch;const char* p="abcdef";//"abcdef",是把字符串的首地址放到p中//"abcdef"是常量字符串,是不可以修改的char arr[]="abcdef";//"abcdef",这里的arr的值是可以修改的char *pa=arr;*pa='w';printf("%s\n",arr);//修改的结果为wbcdefreturn 0;
}

‼️注:常量字符串在内存中只保存一份!!!

#include<stdio.h>
int main()
{char str1[]="abcdef";char str2[]="abcdef";char* str3="abcdef";//保存的就是常量字符串char* str4="abcdef";//保存的就是常量字符串if(str1==str2)//数组保存的字符串是变量,所以str1!=str2{printf("str1==str2\n");}else{printf("str1!=str2\n");}if(str3==str4)//常量字符串在内存中只保留一份,所以str3==str4{printf("str3==str4\n");}else{printf("str3!=str4\n");}return 0;
}

结果为:
str1!=str2

str3==str4

🐰指针数组

字符数组-存放字符的数组
char arr[10];
整形数组-存放整形的数组
int arr[10];
指针数组-存放的就是指针
char* arr[10];
int* arr[10];
#include<stdio.h>
int main()
{char* arr[]={"abc","bcd","edf"};//指针数组,保存了三个字符串的首地址for(int i=0;i<3;i++){printf("%s\n",arr[i]);}return 0;
}
结果为:

abc

bcd

edf

🌸模拟二维数组(整形)

#include<stdio.h>
int main()
{int arr1[]={1,2,3,4,5};int arr2[]={1,2,3,4,5};int arr3[]={1,2,3,4,5};int arr4[]={1,2,3,4,5};int* arr5[]={arr1,arr2,arr3,arr4};for(int i=0;i<4;i++){for(int j=0;j<5;j++){printf("%d",*(arr5[i]+j));//printf("%d\n",arr5[i][j]);//结果一样}printf("\n");}return 0;
}

结果为:

12345

12345

12345

12345

🐰数组指针

整形指针-指向整形的指针
int a=10;
int* P=&a
字符指针-指向字符的指针
char ch='w';
char* pc=&ch;
数组指针-指向数组的指针
int arr[10];
&arr就是数组的地址
int (*pa)[10]=&arr;
char arr[10];
char(*pc)[10]=&arr
int* arr[5];
int* (*pa)[5]=&arr//这个数组指针指向的是arr这个指针数组

🌸数组指针和指针数组的区分

指针数组->存放指针的数组
数组指针->是一种指向数组的指针-存放的是数组的地址

🌸&数组名和数组名的区别

数组名是数组首元素地址
sizeof(数组名)--这个时候表示的不是首元素的首地址,计算的整个数组的大小
&数组名--这里的数组名表示整个数组,取出的是整个数组的地址,从地址角度看和数组首元素的地址一样,他们的类型不一样
#include<stdio.h>
int main()
{int arr[10]={0};printf("arr=%p\n",arr);//数组首元素的地址printf("arr+1=%p\n",arr+1);//数组第二个元素的地址printf("&arr[0]=%p\n",&arr[0]);//数组首元素的地址printf("&arr[0]+1=%p\n",&arr[0]+1);//数组第二个元素的地址printf("&arr=%p\n",&arr);//整个数组的地址printf("&arr+1=%p\n",&arr+1);//数组第最后一个元素的下一个的地址int(*p)[10]=&arr;//数组指针保存整个数组的地址return 0;
}

结果

r=0x7ffeefbff3c0
arr+1=0x7ffeefbff3c4
&arr[0]=0x7ffeefbff3c0
&arr[0]+1=0x7ffeefbff3c4
&arr=0x7ffeefbff3c0
&arr+1=0x7ffeefbff3e8

🌸数组指针p,*p等价于arr,*p就是数组名

#include<stdio.h>
int main()
{int arr[10]={1,2,3,4,5,6,7,8,9,10};int (*p)[10]=&arr;for(int i=0;i<10;i++){printf("%d ",*((*p)+i));//*p等价于arr,*p就是数组名}return 0;
}
结果为:

1 2 3 4 5 6 7 8 9 10

🌸数组指针的使用

#include<stdio.h>
void print(int (*arr)[5],int r,int c)
{for(int i=0;i<r;i++){for(int j=0;j<c;j++){printf("%d ",*(*(arr+i)+j));//arr+i==&arr[i]//printf("%d ",arr[i][j]);}}
}
int main()
{//二维数组的数组名,也表示首元素地址//二维数组的首元素是第一行的地址,是一个一维数组的地址int arr[3][5]={1,2,3,4,5,6,7,8,9,10};print(arr,3,5);return 0;
}

结果为:
1 2 3 4 5 6 7 8 9 10 0 0 0 0 0

二维数组arr

int (*p)[10]=&arr;
p等价于arr
arr=&arr[i]
arr[i]=&arr[i][0]
分析代码
int arr[5];
int *parr1[10];//指针数组
int (*parr2)[10];//数组指针
int (*parr3[10])[5];//数组中存放的数组指针

🌸数组参数和指针参数

一维数组传参
一维数组传参,形参可以是数组,可以是指针
二维数组传参
参数可以是指针,可以是数组,如果是指针,传过去的是第一行的地址
函数形参的设计只能省略第一个[]的数字,因为一个二维数组,可以不知道有对少行,但是必须知道一行有多少元素
一级指针传参
当一个函数的参数部分为一级指针的时候,函数能接收什么参数
数组,指针
二级指针传参
当一个函数的参数部分为二级指针的时候,函数能接收什么参数
二级指针变量,一级指针的地址,指针数组

🐰函数指针-指向函数的指针

函数指针存放的是函数的地址,函数也是有地址的
‼️注:函数名和取地址函数名 是一样的
#include<stdio.h>
int Add(int x,int y)
{return x+y;
}
//函数是存在地址
int main()
{printf("%p\n",&Add);//0x100003f40printf("%p\n",Add);//0x100003f40int (*pf)(int,int)=Add;//pf就是函数指针int ret=(*pf)(3,5);//函数指针的调用int rat=pf(3,5);//*pf和pf等价//这里的*没有实际的意义,可以不要pf(3,5),可以多加(**pf)(3,5),都不影响结果,*pf)(3,5)是为了方便理解printf("%d %d\n",ret,rat);
}

结果为:

0x100003ef0

0x100003ef0

8 8

🌸函数指针数组

数组的每个元素是一个函数指针
这是利用switch()语句制作的两位数计算器
#include<stdio.h>
int Add(int x,int y)
{return x+y;
}
int Sub(int x,int y)
{return x-y;
}
int Mul(int x,int y)
{return x*y;
}
int Div(int x,int y)
{return x/y;
}
void menu(void)
{printf("****    两位数的计算器     ****\n");printf("****    1.Add   2.Sub   ****\n");printf("****    3.Mul   4.Div   ****\n");printf("****    0.exit          ****\n");
}
int main()
{int input=0;do{menu();printf("请选择\n");scanf("%d",&input);int x=0,y=0,ret=0;switch(input){case 1:printf("请输入两个操作数\n");scanf("%d %d",&x,&y);ret=Add(x,y);printf("%d\n",ret);break;case 2:printf("请输入两个操作数\n");scanf("%d %d",&x,&y);ret=Sub(x,y);printf("%d\n",ret);break;case 3:printf("请输入两个操作数\n");scanf("%d %d",&x,&y);ret=Mul(x,y);printf("%d\n",ret);break;case 4:printf("请输入两个操作数\n");scanf("%d %d",&x,&y);ret=Div(x,y);printf("%d\n",ret);break;default:printf("输入错误\n");}}while(input);
}

结果为:

****      两位数的计算器     ****

****      1.Add   2.Sub        ****

****      3.Mul   4.Div         ****

****      0.exit                      ****

请选择

1

请输入两个操作数

3 8

11

这种算法,太冗余了,不够简洁
这是利用函数指针数组制作的两位数计算器
#include<stdio.h>
int Add(int x,int y)
{return x+y;
}
int Sub(int x,int y)
{return x-y;
}
int Mul(int x,int y)
{return x*y;
}
int Div(int x,int y)
{return x/y;
}
void menu(void)
{printf("****    两位数的计算器     ****\n");printf("****    1.Add   2.Sub   ****\n");printf("****    3.Mul   4.Div   ****\n");printf("****    0.exit          ****\n");
}
int main()
{int input=0;do{int x=0,y=0;menu();printf("请选择\n");scanf("%d",&input);printf("请输入两个操作数\n");scanf("%d %d",&x,&y);int (*pf[5])(int,int)={0,Add,Sub,Mul,Div};//这里之所以数组元素给了5个,是为了与菜单对应起来if(input<5&&input>=0){int ret=(*pf[input])(x,y);printf("%d\n",ret);}else if(input==0){printf("计算结束\n");break;}else{printf("输入错误\n");}}while(input);
}

结果为:

****      两位数的计算器     ****

****      1.Add   2.Sub        ****

****      3.Mul   4.Div         ****

****      0.exit                      ****

请选择

1

请输入两个操作数

3 8

11

这种算法,很简洁,逻辑更清晰。

🌸🌸🌸如果大家还有不懂或者建议都可以发在评论区,我们共同探讨,共同学习,共同进步。谢谢大家! 🌸🌸🌸      

相关文章:

「1」指针进阶——详解

&#x1f680;&#x1f680;&#x1f680;大家觉不错的话&#xff0c;就恳求大家点点关注&#xff0c;点点小爱心&#xff0c;指点指点&#x1f680;&#x1f680;&#x1f680; 目录 &#x1f430;指针的回顾 &#x1f430;字符指针 &#x1f430;指针数组 &#x1f338;模…...

JS语法让人困惑的点 “==与===”

在JS中有很多神奇的语法&#xff0c;非常让人困惑&#xff0c;我们就先一一道来&#xff0c;相信你在开发中或多或少都踩过这些坑&#xff0c;或者让人无法理解。 今天我们就来说下【】和【】 这题对于很多没有系统学过前端开发的技术人员来说&#xff0c;算个重点&#xff0c…...

《狂飙》壁纸大嫂如此惊艳,做成日历壁纸天天看

兄弟们&#xff0c;今年的反腐大剧狂飙都有看吗 &#xff1f; 话说&#xff0c;名字虽然叫狂飙&#xff0c;但是全剧只有有田一个人在狂飙&#xff01; 当然&#xff0c;有田虽然亮眼&#xff0c;但是毕竟是个糟老头子&#xff0c;正经人谁看有田啊&#xff0c;当然是看大嫂了…...

手机照片删除了怎么恢复

手机照片删除了怎么恢复?喜欢拍照的小伙伴&#xff0c;都会不定期删除手机上的照片&#xff0c;因为这些爱拍照的人&#xff0c;手机中会存储着很多照片&#xff0c;删除照片是必然的&#xff0c;但在手机删除照片时&#xff0c;如果是一张一张删除太麻烦了&#xff0c;就直接…...

maven pom.xml 依赖的scope属性

maven pom.xml 依赖的scope属性 compile 适用范围 编译期、测试期、运行期 作用 从中央仓库拉取依赖到本地&#xff0c;并编译 打包到结果包中 runtime 适用范围 测试期、运行期 作用 runtime 用在 Class.forName(“com.mysql.jdbc.Driver”) 时&#xff0c;compile 编…...

git 的使用方法 (下 - 远程仓库和图形化)

目录前言&#xff1a;一、什么是协同开发二、Gitee 使用协同开发1. 首先注册一个码云账号2. 新建一个仓库3. 根据下图把新建仓库设置为开源4. 在远端合并分支的方法5. 链接 git 远程6. 提交&#xff08;同步&#xff09;远程7. 远程拉取至本地8. 远程分支三、git 图形化的使用1…...

Java基础:拼图小游戏

涉及到的知识: 1.图形用户接口GUI(Graphical User Interface)用图形化的方式显示操作界面 两个体系: AWT包和Swing包 2.界面会用到JFrame类 3.界面中的菜单会用到JMenuBar, JMenu, JMenuItem 4.添加图片 在设置完JLabel的location之后还需要获得展示内容的窗体, 通过setLay…...

一个跟蘑菇结缘的企业老板

记得那是一个很久以前的一家公司了董事长办公室里中的大型盆栽里面长了一个蘑菇董事长认为是祥瑞每天都会浇水后来一个新来的保洁阿姨以为杂草啥的给他掰掉扔垃圾桶了董事长第二天来浇水的时候发现没了就问谁动了他的蘑菇问道之后就跑到楼道大垃圾桶那里把蘑菇找回来种在花盆里…...

【Leetcode 剑指Offer】第 4 天 查找算法(简单)

查找剑指 Offer 03. 数组中重复的数字剑指 Offer 53 - I. 在排序数组中查找数字 I二分法题目链接剑指 Offer 03. 数组中重复的数字 题&#xff1a;在一个长度为 n 的数组 nums 里的所有数字都在 0&#xff5e;n-1 的范围内。数组中某些数字是重复的&#xff0c;但不知道有几个数…...

Jenkins利用docker部署vue项目

Jenkins利用docker部署vue项目一、环境准备1、安装docker2、安装nodejs3、安装cnpm与配置淘宝镜像4、jenkins安装nodejs插件二、jenkins以vue项目1、全局参数配置2、源码配置3、构建环境4、构建三、构建项目四、访问一、环境准备 本次jenkins与部署vue项目在同一台机器&#x…...

【Linux】如何将ntfs硬盘挂载到home目录下并具有读写权限

步骤1. 查看当前挂载的硬盘及其挂载点2. 查看需要挂载到home下的磁盘类型信息3. 在home下新建一个空的文件夹作为该磁盘的新挂载点4. 以ntfs类型的硬盘为例&#xff0c;使用mount命令进行挂载5. 问题1&#xff1a;进程占用了磁盘6. 问题2&#xff1a;磁盘权限为只读的7. 永久挂…...

拖拽删除元素、拖拽排序、拖拽预览图片和拖拽移动元素

介绍 HTML5 提供了专门的拖拽与拖放的 API&#xff0c;目前各浏览器都已支持&#xff0c;包括 IE。HTML 拖放&#xff08;Drag and Drop&#xff09;接口使应用程序能够在浏览器中使用拖放功能。例如&#xff0c;用户可使用鼠标选择可拖拽&#xff08;draggable&#xff09;元素…...

yarn的global安装命令不生效

问题 yarn全局安装某个依赖完成之后&#xff0c;但依赖没有生效&#xff0c;一般有两种情况导致的。 解决思路 1.yarn命令问题 yarn在全局安装某个依赖时&#xff0c;global要紧接在yarn之后&#xff0c;然后才是add yarn global add xxxx如果出现global在add之后&#xff…...

如何发布自己的npm包?

1 文件组成 package.json文件components文件css样式文件index.js文件 2 package.json配置 description&#xff1a;描述title&#xff1a;题目keywords&#xff1a;搜索关键词typings&#xff1a;指定TypeScript的入口文件main&#xff1a;加载的入口文件module&#xff1a;…...

达梦数据库 闪回查询

当用户操作不慎导致错误的删改数据时&#xff0c;非常希望有一种简单快捷的方式可以恢复数据。闪回技术&#xff0c;就是为了用户可以迅速处理这种数据逻辑损坏的情况而产生的。 闪回技术主要是通过回滚段存储的 UNDO 记录来完成历史记录的还原。如果提交了&#xff0c;还没有…...

java基础学习 day44(多态的优点和劣势)

1. 多态的优势 在多态形式下&#xff0c;右边对象可以实现解耦合&#xff08;即之后的代码与右边的子类对象不绑定&#xff0c;在更改子类对象后&#xff0c;之后的代码仍可以使用&#xff09;&#xff0c;便于扩展和维护在定义方法的时候&#xff0c;使用父类型作为参数&…...

Guna UI WinForms 2.0.4.4 Crack

Guna.UI2 WinForms is the suite for creating groundbreaking desktop app UI. It is for developers targeting the .NET Windows Forms platform. 50 多个 UI 控件 具有广泛功能的综合组件可帮助您开发任何东西。 无尽的定制 只需拖放即可创建视觉效果命令和体验。 出色的…...

零售航母沃尔玛公布业绩:喜忧参半

2月21日美股盘前&#xff0c;零售巨无霸沃尔玛公布了截至1月的2023财年第四季度业绩报告。财报中不乏可圈可点之处&#xff0c;但是利润迎来六年首降&#xff0c;新财年的利润指引要也比预期低很多&#xff0c;可以说喜忧参半。 一、Q4业绩可圈可点 营收方面&#xff1a;在本…...

Python学习笔记丨while、for、if循环结构基础知识与易错点

Python流程控制 本篇笔记的主要内容是&#xff1a;条件控制和循环控制&#xff0c;包括if语句、while语句、for语句等。 Python条件控制 if (m : 1) > 0: # :是海象运算符&#xff0c;用于在函数内部为变量赋值 print("ok")ok 通过if语句来判断条件是否成立&am…...

【ROS学习笔记1】ROS快速体验输出Hello World

【ROS学习笔记1】ROS快速体验输出Hello World 文章目录【ROS学习笔记1】ROS快速体验输出Hello World1.1 ROS快速体验1.1.1 Hello World快速实现简介1.1.2 Hello World的C实现1.1.3 Hello World的Python实现写在前面&#xff0c;本系列笔记参考的是AutoLabor的教程&#xff0c;具…...

STM32单片机学习(27) —— SPI相关概念

文章目录概述SPI通信的核心特性I2C和SPI的简单对比SPI学习的补充说明SPI硬件电路设计SPI的四条通信线SPI通信的片选线低电平选中不支持广播通信SPI通信的时序结构&#xff08;重点&#xff09;SPI通信的比特序通信空闲状态&#xff0c;SPI时钟极性采样时机&#xff0c;SPI时钟相…...

别再盲跑了!手把手教你用Arduino Zero在IDE 2.0里设置断点单步调试

告别盲跑时代&#xff1a;Arduino Zero与IDE 2.0的源码级调试实战指南 当你的Arduino项目逻辑越来越复杂&#xff0c;仅靠串口打印调试就像在迷宫里摸黑前行——直到遇见Arduino Zero与IDE 2.0的调试组合。本文将揭示如何用这套工具实现 源码级精准调试 &#xff0c;即使你手…...

Unity发行版DLL调试实战:DnSpy无源码IL级断点指南

1. 这不是“反编译”&#xff0c;而是Unity游戏开发者的日常调试手段你有没有遇到过这样的情况&#xff1a;接手一个Unity发行版游戏&#xff0c;想快速验证某个功能逻辑是否按预期执行&#xff0c;或者排查一个偶发的崩溃&#xff0c;但手头只有打包后的Assembly-CSharp.dll&a…...

文件-语言-系统:基础IO-2.0——IO重定向接口,语言层缓冲区,系统级缓冲区。内核级分析!

bit::Shadow✧(≖ ◡ ≖✿ 目录 重定向接口dup2() ">" ">>" "<" 函数原型 输出重定向1和2的使用 文件描述符表 ./a.out运行&#xff1a; "./a.out >"默认重定向是fd 1 合并标准输入输出 缓冲区 什么是缓冲…...

Web渗透测试能力成长地图:从工具使用到漏洞认知跃迁

1. 这不是工具清单&#xff0c;而是一张Web渗透测试的“能力成长地图”你刚点开这篇文章&#xff0c;大概率正站在两个路口之间&#xff1a;一边是网上铺天盖地的“十大免费扫描器推荐”&#xff0c;点进去全是截图下载链接一句“一键扫漏洞”&#xff0c;结果装完跑两下&#…...

Hindsight测试策略:单元测试、集成测试和端到端测试

Hindsight测试策略&#xff1a;单元测试、集成测试和端到端测试 【免费下载链接】hindsight Hindsight: Agent Memory That Learns 项目地址: https://gitcode.com/GitHub_Trending/hindsight2/hindsight Hindsight作为一款专注于Agent Memory的开源项目&#xff0c;其可…...

LoRa物联网与动态基线算法在养殖体温监测中的实战应用

1. 项目概述&#xff1a;为什么我们需要一个智能体温监测系统&#xff1f;在规模化养殖场里干了十几年&#xff0c;我见过太多因为体温异常没被及时发现而导致的损失。一头育肥猪突然不吃食&#xff0c;等饲养员第二天巡栏发现时&#xff0c;可能已经高烧好几天&#xff0c;继发…...

微信小程序项目实战:从npm安装Vant Weapp到解决样式冲突的完整避坑指南

微信小程序工程化实战&#xff1a;Vant Weapp集成与样式冲突解决方案全解析 第一次在小程序里引入Vant Weapp时&#xff0c;我对着满屏错位的组件样式发呆了半小时——原本优雅的按钮变成了扭曲的色块&#xff0c;表单元素叠在一起像抽象画。这不是个例&#xff0c;根据社区反…...

Java项目中如何提升整体系统性能?

性能优化可以说是我们程序员的必修课&#xff0c;如果你想要跳出CRUD的苦海&#xff0c;成为一个更“高级”的程序员的话&#xff0c;性能优化这一关你是无论无何都要去面对的。为了提升系统性能&#xff0c;开发人员可以从系统的各个角度和层次对系统进行优化。除了最常见的代…...

XZ6128A工作电压5-100V 输出电流5A 升压型大功率LED灯恒流驱动控制芯片

概述 XZ6128A是一款高效率、高精度的升压型大功率LED灯恒流驱动控制芯片。 XZ6128A内置高精度误差放大器&#xff0c;固定关断时间控制电路&#xff0c;恒流驱动电路等&#xff0c;特别适合大功率、多个高亮度LED灯串的恒流驱动。 XZ6128A采用固定关断时间的控制方式&#xff0…...