c语言指针的应用场景


1.什么是指针?
当我们提起指针的时候,可能第一反应会露出惊喜的表情
在这里插入图片描述
(但是我们其实没必要那么慌,因为当我们随着我们学习的越来越深入就会发现,指针虽然看起来难,实际上也不怎么简单。哈哈哈开玩笑的,我们都要有迎难而上的勇气哦)
好了我们进入正题:
内存会划分为一个个的内存单元,每个内存单元都有一个独立的编号-编号也称为地址。

地址在C语言中也称为指针,指针(地址)需要存储起来,这个变量就被称为指针变量。

2.指针变量的大小

指针(地址)的大小是固定的4/8个字节(在32位平台上是4个字节,在64位平台上是8个字节)。

3.什么是数组指针

其实数组指针并没有我们想象的那么难以理解,可以类比一下:

(1)整型指针—指向整型变量的指针,存放整型变量的地址的指针变量

(2)字符指针—指向字符变量的指针,存放字符变量的地址的指针变量

数组指针—指向数组的指针,存放的是数组的地址的指针变量

这里我们需要搞清楚谁才是主体,就比如好孩子,他主要是在讲孩子;同理,数组指针,他的主体是指针,而不是数组。

4.二维数组

如果我们要定义一个一维数组,我们只需要定义空间的大小就可以了。

int arr[10]={1,2,3,4,5,6,7,8,9,10};

那如果我们要定义一个二维数组 ,还需要定义它的行数和列数

int arr[3][3]={1,2,3,4,5,6,7,8,9};

我们可以把这个二维数组抽象成这样来理解:

二维数组的每一行可以理解为二维数组的一个元素,每一行又是一个一维数组。所以,二维数组其实是一维数组的数组。

二维数组的数组名就是其首元素的地址,也就是第一行的地址。

5.结合strlen和sizeof来加深对数组和指针的理解

(1) strlen是库函数,是求字符串长度的,统计的是在字符串中\0之前的字符的个数,如果没有\0就会一直往后找。

(2)sizeof是一个单目操作符,主要用来计算类型的大小。
(3)数组名是数组首元素的地址
但是有2个例外:
1.sizeof(数组名),这里的数组名表示整个数组,计算的是整个数组的大小,单位是字节
2.&数组名,这里的数组名表示整个数组,取出的是整个数组的地址
接下来我们一起来看几组代码

int main()
{int a[]={1,2,3,4};printf("%d\n",sizeof(a));printf("%d\n",sizeof(a+0));printf("%d\n",sizeof(*a));printf("%d\n",sizeof(a+1));printf("%d\n",sizeof(a[1]));printf("%d\n",sizeof(&a));printf("%d\n",sizeof(*&a));printf("%d\n",sizeof(&a+1));printf("%d\n",sizeof(&a[0]));printf("%d\n",sizeof(&a[0]+1));return 0;
}

在开始看解析之前大家可以自己先猜一下运行结果分别是什么。
(1)首先我们来看第一个,a是数组名,单独放在sizeof里面,所以它计算的是整个数组的大小,这是一个整型数组,每个数组元素4个字节,共有4个元素,所以它的大小是4* 4 = 16个字节。
(2)第二个,sizeof里面放的不是单独的数组名,所以它表示的是首元素的地址,是地址就是4/8个字节。这里前往不能想当然了,觉得a+0跟单独的a没什么区别,要额外小心。
(3)第三个,数组名是首元素的地址,对它解引用就能找到数组的首元素,所以它表示首元素的大小,4个字节。
(4)第四个,数组名是首元素的地址,数组名加一就是第二个元素的地址,是地址就是4/8个字节。
(5)第五个,表示数组下标为1的元素,也就是第二个元素的大小,4个字节。
(6)第六个,&数组名取出的是整个数组的地址,是地址就是4/8个字节。
(7)第七个,这里的*和&会相当于会相互抵消,所以其实这个表达式是sizeof(a),所以这里表示整个数组的大小,16个字节。
(8)第八个,&数组名取出的是整个数组的地址,所以它加一跳过的是整个数组,但是就算跳过了整个数组,还是地址,是地址就是4/8个字节。如下图所示:
在这里插入图片描述
(9)第九个,&a [0]取出的是数组首元素的地址,是地址就是4/8个字节。
(10)第十个,&a [0] +1取出的是数组第二个元素的地址,4/8个字节。
我们来看一个字符数组:

int main()
{char arr[]={'a','b','c','d','e','f'};printf("%d\n", sizeof(arr));printf("%d\n", sizeof(arr+0));printf("%d\n", sizeof(*arr));printf("%d\n", sizeof(arr[1]));printf("%d\n", sizeof(&arr));printf("%d\n", sizeof(&arr+1));printf("%d\n", sizeof(&arr[0]+1)); 
return 0;
}

大家可以带着自己的答案来看解释。
(1)第一个,数组名单独放在sizeof里面,表示计算整个数组的大小,这是一个字符数组,每个数组元素大小是1个字节,共有6个数组元素,所以是6个字节。
(2)第二个,不是数组名单独放在sizeof里面,所以它表示首元素的地址,是地址就是4/8个字节。
(3)第三个,数组名表示首元素的地址,对它解引用就是首元素,所以这里计算的是首元素的大小,1个字节。
(4)第四个,这里计算数组下标为1,也就是第二个元素的大小,1个字节。
(5)第五个,&数组名,取出的是整个数组的地址,是地址就是4/8个字节。
(6)第六个,&数组名+1,表示跳过整个数组指向的那个地址,是地址就是4/8个字节。
(7)第七个,&arr[0]表示取出第一个元素的地址,再加一就是第二个元素的地址,是地址就是4/8个字节。
我们再来看一组 strlen的,注意, strlen是求字符串长度的,统计的是在字符串中\0之前的字符的个数,如果没有\0就会一直往后找。

int main()
{
char arr[]={'a','b','c','d','e','f'};
printf("%d\n", strlen(arr));
printf("%d\n", strlen(arr+0));
printf("%d\n", strlen(*arr));
printf("%d\n", strlen(arr[1]));
printf("%d\n", strlen(&arr));
printf("%d\n", strlen(&arr+1));
printf("%d\n", strlen(&arr[0]+1));
return 0;
}

(1)第一个,求’\0’之前的字符串长度,但是我们可以看到,这个数组中并没有’\0’,所以它在统计完数组中所有的元素后,还会继续往后面统计,直到遇到’\0’为止,但是在这个数组的后面我们并不知道存放着什么,所以这里产生的结果就是随机值。
(2)第二个,arr+0是数组首元素的地址,但是从首元素开始一直到最后都没有’\0’,没有’\0’,它就不会停下来,所以这里还是随机值。
(3)第三个,*arr找到的是数组的第一个元素,但是strlen()它的参数应该是地址,如果将a传进去,a的ASCII码值是97,那它就会从地址是97的地方开始统计,但是我们并不知道地址是97的内存里面存放了什么,这样就会造成非法访问,所以这里的写法是错误的,error。
(4)第四个,arr [1]表示数组的第二个元素,写法错误,error。
(5)第五个,&数组名取出整个数组的地址,整个数组的地址也是从首元素开始,所以这里还是随机值。
(6)第六个,&数组名+1,跳过整个数组,我们并不知道数组后面的内存情况,所以是随机值。
(7)第七个,&arr [0] +1找到的是第二个元素的地址,结果是随机值。
来看另外一组字符串的,字符串后面默认会有一个’\0’。

int main()
{
char arr[]="abcdef";
printf("%d\n", strlen(arr));
printf("%d\n", strlen(arr+0));
printf("%d\n", strlen(*arr));
printf("%d\n", strlen(arr[1]));
printf("%d\n", strlen(&arr));
printf("%d\n", strlen(&arr+1));
printf("%d\n", strlen(&arr[0]+1));
return 0;
}

数组在这里插入图片描述
这就是数组里面实际的情况。
(1)第一个,统计数组中的字符个数,我们可以看到在’\0’前面共有6个字符,所以结果就是6。
(2)第二个,表示首元素地址,从首元素一直到’\0’有6个字符,所以结果是6。
(3)第三个,*arr表示第一个元素,非法访问,error。
(4)第四个,arr [1]表示第二个元素,非法访问,error。
(5)第五个,&arr,从首元素开始到’\0’,共6个字符,结果是6。
(6)第六个,&arr+1,会跳过整个数组,指向’\0’后面,所以结果是随机值。
(7)第七个,&arr[0] +1,表示指向第二个元素,从第二个元素开始到’\0’共有5个字符,所以结果是5。
我们再来看一组

int main()
{
char arr[]="abcdef";
printf("%d\n", sizeof(arr));printf("%d\n", sizeof(arr+0));printf("%d\n", sizeof(*arr));printf("%d\n", sizeof(arr[1]));printf("%d\n", sizeof(&arr));printf("%d\n", sizeof(&arr+1));printf("%d\n", sizeof(&arr[0]+1)); 
return 0;
}

(1)第一个,计算的是整个数组的大小,前面的6个字符再加上后面隐藏的’\0’,共7个字符,所以结果是7。
(2)第二个,表示首元素地址,4/8个字节。
(3)第三个,表示第一个元素大小,1个字节。
(4)第四个,表示第二个元素大小,1个字节。
(5)第五个,表示整个数组的地址,4/8个字节。
(6)第六个,表示指向跳过整个数组之后的地址,4/8个字节。
(7)第七个,表示指向数组的第二个元素的地址,4/8个字节。
我们再来看一组指针的:

int main()
{
char* p="abcdef";
printf("%d\n",sizeof(p));
printf("%d\n",sizeof(p+1));
printf("%d\n",sizeof(*p));
printf("%d\n",sizeof(p[0]));
printf("%d\n",sizeof(&p));
printf("%d\n",sizeof(&p+1));
printf("%d\n",sizeof(&p[0]+1));
return 0;
}

z这里先提前说明一点,指针指向一个字符串,其实指向的是字符串的第一个字符的地址。所以这里p指向的是a的地址。
(1)第一个,p指向的是a的地址,所以是4/8个字节。
(2)第二个,p指向的是a的地址,p+1指向的就是b的地址,4/8个字节。
(3)第三个,p指向的是a的地址,对它解引用找到的就是a,所以这里计算的是a的大小,1个字节。
(4)第四个,p [0] = *(p+0) = *p,和上面的一样,计算的是a的大小,1个字节。
(5)第五个,&p表示取p的地址,4/8个字节。
(6)第六个,&p+1,表示指向p后面的地址,4/8个字节。
如果大家对这里比较疑惑的话,可以看图理解:
在这里插入图片描述

(7)第七个,&p [0]表示取出a的地址,再加一表示指向b的地址,4/8个字节。
我们再来下一组:

int main()
{
char* p="abcdef";
printf("%d\n",strlen(p));
printf("%d\n",strlen(p+1));
printf("%d\n",strlen(*p));
printf("%d\n",strlen(p[0]));
printf("%d\n",strlen(&p));
printf("%d\n",strlen(&p+1));
printf("%d\n",strlen(&p[0]+1));
return 0;
}

(1)第一个,因为p指向数组的第一个字符,所以从a开始一直到字符串最后的’\0’,共6个字符,所以结果是6。
(2)第二个,p+1指向第二个字符,结果是5。
(3)第三个,*p表示第一个字符,这里strlen 需要的参数是地址,所以是非法访问,error。
(4)第四个, p [0] = *(p+0) =*p,表示第一个字符,非法访问,error。
(5)第五个,&p表示取出p的地址,p里面的情况我们并不清楚,所以是随机值。
(6)第六个,&p+1,表示指向p后面的地址,p后面的情况我们并不清楚,所以是随机值。
(7)第七个,p [0] = *p,表示第一个字符,再对它取地址就是取a的地址,再加一就是指向b的地址,5个字节。
好啦,我们再来看最后一组重量级的压轴选手:

int main()
{
int a[3][4]={0};
printf("%d\n",sizeof(a));
printf("%d\n",sizeof(a[0][0]));
printf("%d\n",sizeof(a[0]));
printf("%d\n",sizeof(a[0]+1));
printf("%d\n",sizeof(*(a[0]+1)));
printf("%d\n",sizeof(a+1));
printf("%d\n",sizeof(*(a+1)));
printf("%d\n",sizeof(&a[0]+1));
printf("%d\n",sizeof(*(&a[0]+1)));
printf("%d\n",sizeof(*a));
printf("%d\n",sizeof(a[3]));
return 0;
}

在这里插入图片描述
这里给大家一张二维数组的抽象图来帮助理解。每一行就相当于一个一位数组,如果想描述一个具体元素的位置,就必须标明它的行和列,比如a [1] [1] ,就是第一行第一列的元素,但如果是a [1] ,则表示第一行的那个数组的数组名,而我们找到数组名通常表示数组首元素的地址,那一维数组a[1] 的首元素就是a[1] [0] ,对照上图理解会更容易。
(1)第一个,数组名单独放在sizeof里,表示整个数组的大小,这个数组共有12个元素,每个整型元素4个字节,所以结果是12 * 4 = 48个字节。
(2)第二个,表示求第0行第0列元素的大小,4个字节。
(3)第三个,a [0] 是第0行这个一维数组的数组名,所以这里是数组名单独放在sizeof里的情况,表示整个数组的大小,第0行共有4个元素,所以大小是16个字节。
(4)第四个,a [0]作为第0行的数组名,没有单独放在sizeo内部,没有&,a[0]表示数组首元素的地址,也就是a[0][0]的地址,所以a [0] +1是第0行第2个元素的地址,是地址就是4/8个字节。
(5)第五个,a [0] +1则表示第0行第2个元素的地址,对它解引用就可以找到第0行第2个元素,其大小是4个字节。
(6)第六个,数组名a表示首元素的地址,对二维数组来说,第0行就是它的首元素,a+1指向它的第二个元素的地址,也就是第1行的首元素的地址,是地址就是4/8个字节。
(7)第七个,* (a+1)= a [1] ,这个[ ]的运算在前面也出现过几次,需要我们格外小心注意,(我错好多次了呜呜呜),所以这里算是一维数组的数组名单独放在sizeof里的情况,计算第一行的元素大小,第一行4个元素,结果是16个字节。
(8)第八个,&a [0]表示取第0行的地址,加一跳过第0行,指向第1行的地址,即a [1] 的地址,是地址就是4/8个字节。这里不是整型指针,而是整型数组指针,即 int (*) [4] ,加一要跳过一个数组。
(9)第九个,对上面的数组指针解引用,得到的就是第一行的数组的元素,第一行共4个元素,16个字节。
(10)第十个,数组名a表示二维数组首元素,即第0行的地址,对其解引用得到的就是第0行的元素,16个字节。
(11)第十一个,看到a [3] 我们的第一反应是不对劲,这个数组一共才2行,哪里来的第三行,肯定是越界了,会出错。但如果我们去运行代码的话,会发现它还是会正常运行,是因为sizeof其实不会真正去访问内存,它只负责识别类型,然后计算它的大小,这里的a [3] 表示的情况还是数组名单独放在sizeof里的情况,计算的是整个数组的大小,我们给出的这个数组一行有4个元素,所以结果是16个字节。
本次的分享就到此为止啦,希望能够对你有帮助哦!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/829269.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

TCN-LSTM时间卷积网络长短期记忆网络多输入多输出回归预测

文章目录 效果一览文章概述 订阅专栏只能获取一份代码部分源码参考资料 效果一览 文章概述 TCN-LSTM时间卷积网络长短期记忆网络多输入多输出回归预测 matlab2021 订阅专栏只能获取一份代码 部分源码 %------------------------------------------------------------------…

c# winform打包

本次采用vs2022打包winform窗体应用,有时应用不需要打包为安装应用,执行一个EXE就运行了 测试了几次,winform 非.net Framework 和控制台程序也是非.net Framework项目能打包这种,后续在研究

边缘计算在视频监控领域的应用

一、边缘计算在视频监控领域的应用 运用边缘计算解决视频监控问题,可以带来许多优势。以下是一些具体的应用示例: 实时分析与处理:在视频监控系统中,边缘计算盒子可以实时处理和分析视频流,实现对监控画面的智能识别…

STM32H7 HSE时钟的使用方法介绍

目录 概述 1 STM32H750 HSE时钟介绍 2 使用STM32Cube创建Project 3 认识HSE时钟 3.1 HSE时钟的特性 3.2 HSE的典型应用电路 4 STM32Cube中配置时钟 4.1 时钟需求 4.2 配置参数 4.2.1 使能外围资源 4.2.2 使用STM32Cube注意项 4.2.3 配置参数 5 总结 概述 本文主要…

IBM SPSS Statistics for Mac v27.0.1中文激活版:强大的数据分析工具

IBM SPSS Statistics for Mac是一款功能强大的数据分析工具,为Mac用户提供了高效、精准的数据分析体验。 IBM SPSS Statistics for Mac v27.0.1中文激活版下载 该软件拥有丰富的统计分析功能,无论是描述性统计、推论性统计,还是高级的多元统计…

论文解读:(CAVPT)Dual Modality Prompt Tuning for Vision-Language Pre-Trained Model

v1文章名字:Dual Modality Prompt Tuning for Vision-Language Pre-Trained Model v2文章名字:Class-Aware Visual Prompt Tuning for Vision-Language Pre-Trained Model 文章汇总 对该文的改进:论文解读:(VPT)Visual Prompt …

Visual Studio 对 C++ 头文件和模块的支持

在 C 编程领域,头文件和模块的管理有时候确实比较令人头疼。但是,有许多工具和功能可以简化此过程,提高效率并减少出错的可能性。下面是我们为 C 头文件和模块提供的几种工具的介绍。 构建明细 通过菜单栏 Build > Run Build Insights&a…

【个人博客搭建】(11)swagger添加jwt信息

这个主要是为了方便使用swagger时,能更好的带入我们的token。 ps:如果使用其他第三方api工具(apipost、postman等)则不需要。 (当然,不用不能没有,是吧) 1、在AddSwaggerGen内添加…

本地Windows主机,使用pycharm通过wsl的ubuntu来创建django项目

Windows主机在pycharm中通过wsl的ubuntu来创建django项目 需求:在windows主机中创建python项目再转接到linux服务器中运行,有点麻烦。【特别是存放日志文件或其他文件路径时需要修改为linux中的路径】 1:我的是windows主机 2:有…

关于SSL加密,您应该知道什么?

SSL加密,全称为安全套接字层加密,是一种网络安全协议,主要用于在网络通信中提供隐私和数据完整性。它通过在客户端和服务器之间建立一个加密的通道,确保数据在传输过程中不被窃取或篡改。随着互联网的普及和电子商务的快速发展&am…

前端提高篇(二十四)JS进阶18对象属性的高级用法

x:1, y:2, } Object.defineProperty(obj1, ‘z’,{ value:3, writable:true, enumerable:true, configurable:true, }) for (var i in obj1){ console.log(i ’ : ’ obj1[i]); } 运行效果: 不可枚举时: var obj1 { x:1, y:2, } Obj…

windows Jenkins运行python+selenium打开浏览器一直无响应,运行中,还没有打开浏览器

一开始解决办法是把打开服务把Jenkins给禁用了 但是没有用,然后找到安装目录 C:\Program Files\Jenkins 在这个路径下,在地址栏输入cmd打开命令窗口运行Jenkins启动命令 java -jar jenkins.war --httpPort8080 打开浏览器进入链接 http://localhost:…

使用工具速记

文章目录 一、sqlyoy登录账号信息迁移二、idea导入之前的已配置的idea信息三、设置windows UI大小四、其他 提示:以下是本篇文章正文内容,下面案例可供参考 一、sqlyoy登录账号信息迁移 工具(sqlyog上面菜单栏)->导入导出详情->选择要导出的账号…

Centos/linux根目录扩容、分区、挂载。LVM、物理卷、逻辑卷

前言    (空格) :分区挂载和扩容是两码事 每个Linux使用者在安装Linux时都会遇到这样的困境:在为系统分区时,如何精确评估和分配各个硬盘分区的容量,因为系统管理员不但要考虑到当前某个分区需要的容量&a…

你的网站还在使用HTTP? 免费升级至HTTPS吧

如果您的网站还在使用老的http协议,可以申请一个免费的SSL证书升级至https! 具体步骤如下: 1 申请免费SSL证书 根据你的需求选择合适的SSL证书类型,如单域名证书,多域名证书、通配符证书 登录免费供应商JoySSL官网&…

施耐德 Unity Pro 编程软件导入导出变量

适用范围 施耐德中高端PLC,使用的编程软件为 UnityPro (最新版更名为 Ecostructure Control Expert) 中端 PLC:Premium,M340高端 PLC:Quantum,M580 导出/导入变量 导出变量可导出【变量和 FB…

表情识别 | LBP+SVM实现脸部动态特征的人脸表情识别程序(Matlab)

表情识别 | LBPSVM实现脸部动态特征的人脸表情识别程序(Matlab) 目录 表情识别 | LBPSVM实现脸部动态特征的人脸表情识别程序(Matlab)预测效果基本介绍程序设计参考资料 预测效果 基本介绍 1 运行环境 程序运行在Windows系统下&am…

微信小程序:11.本地生活小程序制作

开发工具: 微信开发者工具apifox进行创先Mock 项目初始化 新建小程序项目输入ID选择不使用云开发,js传统模版在project.private.config中setting配置项中配置checkinalidKey:false 梳理项目结构 因为该项目有三个tabbar所以我们要创建三…

百种提权及手段一览系列第10集

特权升级的危险是显而易见的。通过提升权限,攻击者可以绕过网络安全措施,从而损害数据完整性、机密性和系统可用性。对于组织而言,这可能会导致数据泄露、系统停机以及潜在的法律和声誉后果。识别权限升级的迹象并部署预防性网络安全措施对于…

【01-机器学习入门:理解Scikit-learn与Python的关系】

文章目录 前言Python与机器学习Scikit-learn简介Scikit-learn与Python的关系使用Scikit-learn进行机器学习结语 前言 在当今的数据科学和人工智能领域,机器学习已经成为了一个不可或缺的组成部分。而对于那些刚刚踏入这一领域的新手来说,理解机器学习的基…