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;
}

运行结果:

图解:

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


相关推荐
reyas28 分钟前
B树系列解析
数据结构·b树
Indigo_code1 小时前
【数据结构】【顺序表算法】 删除特定值
数据结构·算法
阿史大杯茶2 小时前
Codeforces Round 976 (Div. 2 ABCDE题)视频讲解
数据结构·c++·算法
LluckyYH2 小时前
代码随想录Day 58|拓扑排序、dijkstra算法精讲,题目:软件构建、参加科学大会
算法·深度优先·动态规划·软件构建·图论·dfs
转调2 小时前
每日一练:地下城游戏
开发语言·c++·算法·leetcode
不穿格子衬衫3 小时前
常用排序算法(下)
c语言·开发语言·数据结构·算法·排序算法·八大排序
wdxylb3 小时前
使用C++的OpenSSL 库实现 AES 加密和解密文件
开发语言·c++·算法
aqua35357423583 小时前
蓝桥杯-财务管理
java·c语言·数据结构·算法
CV金科3 小时前
蓝桥杯—STM32G431RBT6(IIC通信--EEPROM(AT24C02)存储器进行通信)
stm32·单片机·嵌入式硬件·算法·蓝桥杯
sewinger3 小时前
区间合并算法详解
算法