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

【C语言】数组指针与指针数组

前言

前面的文章讲了指针的一些基本内容,这里我们来讲一下数组指针与指针数组,数组指针是指针运用的一个明显体现,准确来说是通过指针访问内存地址的具体体现

一、一维数组的指针

首先,我们先来看一段代码

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

	return 0;
}

在这里插入图片描述
在上述结果中我们发现,数组arr的首元素地址与arr这个数组的名字是一样的,所以数组名就是首元素的地址


同时在【C语言】自定义类型数据-数组这篇文章中我们说过,数组是一个连续的内存空间,所以,我们可以通过指针的运算来逐一访问数组的元素,请看下面的代码

#include <stdio.h>
int main() {
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	int* pa = &arr[0];
	
	for (int i = 0; i < 10; i++) {
		printf("%d ", *(pa + i));
	}
	
	return 0;
}

在这里插入图片描述


arr是首元素地址的特殊情况

一、&arr
我们上面说了,数组名arr就是数组arr首元素的地址,那么当我们&arr时,得到的会是什么呢?那让我们看一下下面的代码

#include <stdio.h>
int main() {
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	int* pa = &arr[0];

	printf("pa   -> %p\n", pa);
	printf("parr -> %p\n", &arr);

	printf("pa + 1   -> %p\n", pa + 1);
	printf("parr + 1 -> %p\n", &arr + 1);

	return 0;
}

在这里插入图片描述
结果如下:
pa -> 000000D1FA16F5D8
parr -> 000000D1FA16F5D8
pa + 1 -> 000000D1FA16F5DC
parr + 1 -> 000000D1FA16F600
我们可以发现,pa与pa + 1相差了4个字节,也就是一个整形,但是parr与parr + 1相差了40个字节,隔了一个数组的大小,也就是说,&arr得到的parr是整个数组的地址,当parr + 1时指针会走过一个数组,所以此时的arr不是首元素的地址,而是整个数组

二、sizeof(arr)
我们先看代码

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

	return 0;
}

在这里插入图片描述
这里我们可以发现,sizeof(arr)得到的并不是地址的大小,而是arr数组的大小,也就说sizeof(arr)中的arr并不代表着首元素的地址,而是代表整个数组的


二、二维数组指针

我们上面很详细地介绍了一维数组的指针,接下来我们介绍一下二维数组的指针,对于二维数组我们可以如此定义:

类型 (*ptr)[M] = arr;

这里的类型也就是二维数组的元素的数据类型,而ptr则是指针的名称,M则是一行数组的元素数量,我们看下面的代码

#include <stdio.h>
int main() {
	int arr[2][5] = {1,2,3,4,5,6,7,8,9,10};
	int(*pa)[5] = arr;

	return 0;
}

这里我们定义了一个行为2列为5的二维数组指针变量,那么,这个指针变量究竟是什么呢?让我们继续看下面的代码

#include <stdio.h>
int main() {
	int arr[2][5] = { 1,2,3,4,5,6,7,8,9,10 };
	int(*pa)[5] = arr;

	printf("*pa        -> %p\n", *pa);
	printf("&arr[0]    -> %p\n", &arr[0]);
	printf("&arr[0][0] -> %p\n", &arr[0][0]);
	printf("\n");
	printf("*(pa + 1)  -> %p\n", *(pa + 1));
	printf("&arr[1]    -> %p\n", &arr[1]);
	printf("&arr[1][0] -> %p\n", &arr[1][0]);

	printf("\n");
	printf("**pa       -> %d\n", **pa);

	return 0;
}

在这里插入图片描述
其实我们根据结果可以发现二维数组的指针是一个二级指针,而且存放的是一个行数组的指针(arr[0]),也就是首元素地址,当我们进行(pa + 1)时,指针变成了第二行数组的指针(arr[1]),也是第二行数值的首元素地址,我们可以简单用图表示*
在这里插入图片描述
所以通过指针我们也可以对二维数组进行访问


三、指针数组

我们之前说过,数组是一种基本的数据结构,用于存储相同类型的多个值,当然相同类型的多个值也包括指针类型,所以我们可以定义一个数组来存储我们的指针,请看下面的代码

#include <stdio.h>

int main() {
	int* ptrarr[3] = { 0 };
	int arr[3] = { 1,2,3 };
	
	ptrarr[0] = &arr[0];
	ptrarr[1] = &arr[1];
	ptrarr[2] = &arr[2];

	for (int i = 0; i < 3; i++) {
		printf("ptrarr[%d] -> %p\n", i + 1, ptrarr[i]);
	}

	return 0;
}

在这里插入图片描述
这里我们定义了一个整形类型指针数组用来储存我们的整形指针,定义指针类型的方法与定义普通类型的数组是一样的,所以我就不再多讲啦!


End

对于指针的所有内容,博主只能到这个地步啦,谢谢大家的阅读,希望我的文章对大家有帮助!


http://www.kler.cn/a/457485.html

相关文章:

  • OWASP ZAP之API 请求基础知识
  • unity学习5:创建一个自己的3D项目
  • kafka开机自启失败问题处理
  • java Redisson 实现限流每秒/分钟/小时限制N个
  • java接口下载zip,不生成中间文件,返回前端文件流
  • 建立一个Macos载入image的实例含界面
  • Formality:匹配(match)是如何进行的?
  • 通过MySQL binlog日志,使用canal同步分库分表数据,到 Elasticsearch
  • 大数据技术-Hadoop(一)Hadoop集群的安装与配置
  • 【每日学点鸿蒙知识】navigation跳转异常、默认加载移动端版本网页、Menu位置、View生成图片保存相册、H5原生交互
  • 2024/12/29 黄冈师范学院计算机学院网络工程《路由期末复习作业一》
  • Linux day 1129
  • java高频面试之SE-05
  • 关于ESD(静电放电)等级的划分
  • .net8使用log4.net并自定义日志表的字段
  • Django管理界面自定义操作重启ECS服务
  • 业务智能化的关键:探索事件驱动的业务规则模型
  • 网络的类型
  • 面试场景题系列:设计键值存储系统
  • 在Bash Shell脚本中创建和使用变量
  • 如何正确使用Jmeter
  • vue2使用pdfjs-dist和jsPDF生成pdf文件
  • 多显卡服务器如何设置使用集成显卡输出信号?
  • 从零开始开发纯血鸿蒙应用之UI封装
  • HarmonyOS NEXT应用开发实战:一分钟写一个网络接口,JsonFormat插件推荐
  • java开发配置文件集合