C语言指针进阶:数组与指针的联系

目录

  • [1. 数组名的本质](#1. 数组名的本质)
  • [2. 使用指针访问数组](#2. 使用指针访问数组)
  • [3. 一维数组传参的本质](#3. 一维数组传参的本质)
  • [4. 二级指针](#4. 二级指针)
  • [5. 指针数组](#5. 指针数组)
    • [5.1 指针数组模拟二维数组](#5.1 指针数组模拟二维数组)

正文开始。

1. 数组名的本质

数组名代表着这个数组中第一个元素的地址

例如:

c 复制代码
int arr[4] = { 1,2,3,4 };
int *p1 = &arr[0];
int *p2 = arr;

上述代码中指针变量p1p2所存储的地址是相同的。

数组名代表着数组中元素首元素的地址,但有两个特例需要特别关注:

  • sizeof(arr_name):sizeof 中单独放数组名,这里的数组名代表着整个数组,计算的是整个数组的大小,单位是字节。
  • &arr_name:这里的数组名表示的整个数组,取出的是整个数组的地址

除此之外,在其他任何地方使用数组名,它都表示首元素的地址。

需要注意的是,整个数组的地址和首元素的地址是有所不同的。整个数组的地址所指向的对象是一个自定义的数组类型 ;而首元素的地址所指向的对象是首元素的类型

例如:

可以看到,上述代码中,&arr所指向的对象类型为int [5],大小为20个字节;而arr所指向的对象类型为int,大小为4字节。

2. 使用指针访问数组

理解了数组名的本质,那我们就可以通过指针来访问数组了。

c 复制代码
#include <stdio.h>
int main()
{
	int arr[5] = { 0 };
	int size = sizeof(arr) / sizeof(arr[0]);
	int* p = arr;
	//p == arr == &arr[0]
	for(int i = 0; i < size; i++)
	{
		scanf("%d", p + i);
	//p + 1 == arr + i == &arr[0] + i == arr[i] == p[i]
	}
	for(int i = 0; i < size; i++)
	{
		printf("%d ", *(p + i));
	}
	return 0;
}

运行结果:

3. 一维数组传参的本质

我们时常需要将数组作为参数传递给函数,下面来讨论下一维数组传参的本质。

c 复制代码
#include <stdio.h>
void Num(int arr[10])
{
	int size = sizeof(arr);
	printf("%d", size);
}

int main()
{
	int arr[10] = { 0 };
	Num(arr);
	return 0;
}

32位环境下运行结果:

64位环境下运行结果:

在上述代码第11行调用函数时,函数的参数为arr,这里代表着该数组首元素的地址,所以传递进函数的参数实际上是一个地址

在函数定义时,用到了void Num(int arr[10]),其中的[10]只是一个形式上的声明,可以理解为告诉开发人员这是一个存放了十个元素的数组。

既然传入的参数本质上是一个地址,那我们当然也可以在定义函数的时候,就将参数设置为指针,例如上文代码等同于:

c 复制代码
#include <stdio.h>
void Num(int *p)
{
	int size = sizeof(p);
	printf("%d", size);
}

int main()
{
	int arr[10] = { 0 };
	Num(arr);
	return 0;
}

4. 二级指针

我们都知道,指针变量就是用来存放所指向对象的地址,那指针变量也是变量,是变量就有地址,那指针变量的地址存放在哪里呢?答案就是二级指针

c 复制代码
#include <stdio.h>
int main()
{
	int a = 5;
	//一级指针,存放变量 a 的地址
	int* p = &a;
	//二级指针,存放变量 p 的地址
	int** pp = &p;
	
	//指针的运算
	//一级指针解引用,*p == a == 5
	int b = *p;
	//二级指针解引用,*pp == p,**pp == a == 5
	int* c = *pp;
	int d = **pp;
	return 0;
}

这里只对二级指针做演示,按照二级指针的定义,以此类推,就可以得出多级指针的用法,这里不再赘述。

5. 指针数组

指针数组,究竟是指针呢,还是数组呢?

我们类比一下,韭菜盒子,到底是韭菜呢,还是盒子呢,很显然,它指的是韭菜馅的盒子。

那指针数组呢?是存放指针的数组

图例:

5.1 指针数组模拟二维数组

c 复制代码
#include <stdio.h>
int main()
{
	int arr1[5] = { 1,2,3,4,5 };
	int arr2[5] = { 2,3,4,5,6 };
	int arr3[5] = { 3,4,5,6,7 };
	//指针数组,每个元素都是一个指向一维数组的地址
	int* parr[3] = { arr1,arr2,arr3 };
	int i = 0;
	int j = 0;
	for(i = 0; i < 3; i++)
	{
		for(j = 0;j < 5; j++)
		{
			printf("%d ",parr[i][j]);
			//可理解为(parr[i])[j]
			//例如parr[1][3]
			//parr[1][3] == (parr[1])[3] == arr2[3] == 5
		}
		printf("\n");
	}
	return 0;
}

运行结果:

图解:

上述代码实现了二维数组的效果,但其本质上并不是二维数组,因为每一行在内存中并非是连续存储的,而二维数组的元素在内存中是连续存储的。


相关推荐
what丶k19 分钟前
深度解析:以Kafka为例,消息队列消费幂等性的实现方案与生产实践
java·数据结构·kafka
星火开发设计23 分钟前
C++ 输入输出流:cin 与 cout 的基础用法
java·开发语言·c++·学习·算法·编程·知识
We་ct33 分钟前
LeetCode 289. 生命游戏:题解+优化,从基础到原地最优
前端·算法·leetcode·矩阵·typescript
自己的九又四分之三站台34 分钟前
9:MemNet记忆层使用,实现大模型对话上下文记忆
人工智能·算法·机器学习
LXS_3571 小时前
STL - 函数对象
开发语言·c++·算法
aini_lovee1 小时前
基于粒子群算法(PSO)优化BP神经网络权值与阈值的实现
神经网络·算法
老鼠只爱大米1 小时前
LeetCode经典算法面试题 #230:二叉搜索树中第K小的元素(递归法、迭代法、Morris等多种实现方案详细解析)
算法·leetcode·二叉搜索树·二叉树遍历·第k小的元素·morris遍历
星期五不见面1 小时前
嵌入式学习!(一)C++学习-leetcode(21)-26/1/29
学习·算法·leetcode
AllData公司负责人1 小时前
【亲测好用】实时开发平台能力演示
java·c语言·数据库
pcm1235671 小时前
设计C/S架构的IM通信软件(3)
java·c语言·架构