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

指针浅谈(三)

     在指针浅谈(二)http://t.csdnimg.cn/SKAkD中我们讲到了const修饰指针、指针运算、野指针、assert断言和传址调用的内容,今天我们继续学习有关数组名、指针访问数组、一维数组传参的本质相关的内容,内容比较深入,如果觉得哪里讲解的不行,可以参考其他大佬的文章呦。

1.数组名的理解

     在之前我们使用指针访问数组时,有以下代码:

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

     这里&arr[0]表示取出数组第一个元素的地址赋给指针变量p,但是你看下面这个代码和运行结果:

#include<stdio.h>
int main()
{int arr[10]={1,2,3,4,5,6,7,8,9,10};printf("&arr[0]=%p\n",&arr[0]);printf("arr=%p",arr);return 0;
}

     你会神奇的发现,wc,这出错了吧,这怎么可能,数组名的地址怎么能和数组第一个元素的地址相同呢?但事实上,数组名就是数组首元素的地址。

      这时候倘若我放出下面这段代码,阁下该如何应对?

#include <stdio.h>
int main()
{int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };printf("%d\n", sizeof(arr));return 0;
}

       我直接懵逼了,到底哪个是对的?其实两个都是对的,数组名确实是数组首元素的地址,但在两个情况下是例外的:

 (1)sizeof(数组名):sizeof中放数组名,数组名表示整个数组,计算整个数组的大小。

 (2)&数组名,这里的数组名表示整个数组,取出的是整个数组的地址,这和首元素的地址是有区别的。区别就在于下面这段代码

#include <stdio.h>
int main()
{int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };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);printf("&arr = %p\n", &arr);printf("&arr+1 = %p\n", &arr+1);return 0;
}

     我们发现&arr[0]和&arr[0]+1相差4个字节,arr和arr+1相差4个字节,这是我们意料之中的,毕竟数组名是数组首元素的地址,但&arr和&arr+1相差40个字节,这是因为&arr是数组的地址,+1之后直接跳过整个数组,虽然它和数组首元素地址相同,但区别就在于指针+-运算跳过的多少。

     总的来说,数组名是数组首元素的地址,但是有sizeof和&数组名两个意外。

2.使用指针访问数组

     讲的是指针,那我们就要用指针,已经知道了这么多关于数组的知识,就应该学习如何用指针访问数组。

#include <stdio.h>
int main()
{int arr[10] = {0};int i = 0;int sz = sizeof(arr)/sizeof(arr[0]);//输⼊int* p = arr;for(i=0; i<sz; i++){scanf("%d", p+i);//scanf("%d", arr+i);//也可以这样写//scanf("%d", arr[i]);//scanf("%d", p[i]);}//输出for(i=0; i<sz; i++){printf("%d ", *(p+i));printf("%d ", p[i]);//或者这样写printf("%d ", arr[i]);}return 0;
}

      这段代码怎么理解呢?其实并不难,将数组首元素的地址赋给了指针变量p,那我们就可以访问整个数组,毕竟数组是一段连续的存储空间,知道了首元素地址,就可以顺藤摸瓜找到其他元素,运用指针运算,遍历整个数组进行赋值,因为数组首元素也是地址,相当于一个指针,所以也可以写成arr+i,等价于arr[i]。其实数组名arr和p在这里等价,所以也可以是p[i],输出时,我们需对指针变量解引用获取元素值即可。

3.一维数组传参的本质

     我们知道数组是可以传递给函数的,那数组是把自己所有元素全部传过去吗?显然不是,在早期的计算机设备中,内存是很小的,如果一下传很多元素过去,会很占用内存,效率低下,那数组是怎么传过去呢?下面就让我们了解一下。

     之前我们都是在函数外部计算数组的元素个数,那能不能在函数内部进行求解呢?

#include <stdio.h>
void test(int arr[])//形参也可以写成int* arr,写成数组形式,本质上还是指针
{int sz2 = sizeof(arr)/sizeof(arr[0]);printf("sz2 = %d\n", sz2);
}
int main()
{int arr[10] = {1,2,3,4,5,6,7,8,9,10};int sz1 = sizeof(arr)/sizeof(arr[0]);printf("sz1 = %d\n", sz1);test(arr);return 0;
}

     我们发现其实并不能这样做,这时候就要学习数组传参的本质了,刚才学到数组名是数组首元素的地址,那传参传的是数组名,也就是说本质上数组传参传递的是数组首元素的地址。

     所以函数形参应该使用指针变量来接收首元素地址,那我们在函数内部写sizeof(arr)计算的是一个地址的大小,不是数组的大小,正是因为这样,我们在函数内部是没有办法求数组元素个数的。

     今天的指针先讲到这里,下期再见!

相关文章:

  • 1842_emacs使用company-irony实现C语言的自动补全
  • pymysql代替mysqlclient,解决mysqlclient因版本不兼容无法安装成功而无法连接mysql的问题
  • 使用Java将图片添加到Excel的几种方式
  • 机器学习---Boosting
  • 代理ip一般适用于什么行业,什么场景
  • linux下部署frp客户端服务端-内网穿透
  • Linux下的软硬链接
  • 生产派工自动化:MES系统的关键作用
  • 第三十二章 控制到 XML 模式的映射 - %ListOfObjects
  • 金融专题 | 对复杂的金融工具进行设计、定价和对冲分析
  • Redis第1讲——入门简介
  • 【MODBUS】Modbus主站云端服务器和边缘设备部署区别
  • yarn或者pnpm第一次执行的时候遇到报错yarn : 无法加载文件......因为在此系统上禁止运行脚本
  • flex布局,换行的元素上下设置间距
  • 计算机毕业设计 基于SpringBoot的乡村政务办公系统的设计与实现 Java实战项目 附源码+文档+视频讲解
  • 【划重点】MySQL技术内幕:InnoDB存储引擎
  • ECS应用管理最佳实践
  • ES2017异步函数现已正式可用
  • JavaScript 无符号位移运算符 三个大于号 的使用方法
  • javascript数组去重/查找/插入/删除
  • Laravel 菜鸟晋级之路
  • node入门
  • node学习系列之简单文件上传
  • Zsh 开发指南(第十四篇 文件读写)
  • 从伪并行的 Python 多线程说起
  • 简单基于spring的redis配置(单机和集群模式)
  • 码农张的Bug人生 - 见面之礼
  • 每个JavaScript开发人员应阅读的书【1】 - JavaScript: The Good Parts
  • 排序(1):冒泡排序
  • 前端面试之CSS3新特性
  • 如何用vue打造一个移动端音乐播放器
  • 一文看透浏览器架构
  • Java性能优化之JVM GC(垃圾回收机制)
  • 正则表达式-基础知识Review
  • #NOIP 2014# day.1 生活大爆炸版 石头剪刀布
  • #我与Java虚拟机的故事#连载12:一本书带我深入Java领域
  • (1)STL算法之遍历容器
  • (3)nginx 配置(nginx.conf)
  • (超详细)2-YOLOV5改进-添加SimAM注意力机制
  • (二)Eureka服务搭建,服务注册,服务发现
  • (附源码)spring boot网络空间安全实验教学示范中心网站 毕业设计 111454
  • (幽默漫画)有个程序员老公,是怎样的体验?
  • (转)Linux NTP配置详解 (Network Time Protocol)
  • (转)为C# Windows服务添加安装程序
  • (转载)Linux 多线程条件变量同步
  • .NET Core 控制台程序读 appsettings.json 、注依赖、配日志、设 IOptions
  • .net framework 4.0中如何 输出 form 的name属性。
  • .NetCore Flurl.Http 升级到4.0后 https 无法建立SSL连接
  • .Net程序帮助文档制作
  • .net连接oracle数据库
  • @31省区市高考时间表来了,祝考试成功
  • @javax.ws.rs Webservice注解
  • @Tag和@Operation标签失效问题。SpringDoc 2.2.0(OpenApi 3)和Spring Boot 3.1.1集成
  • [ vulhub漏洞复现篇 ] GhostScript 沙箱绕过(任意命令执行)漏洞CVE-2019-6116
  • [AutoSAR系列] 1.3 AutoSar 架构