深入了解指针(二)--认识数组名、指针访问数组、二级指针、指针数组

1.数组名的理解

int arr[10] = { 0 };
int* p = &arr[0];
int* p = arr;

当我们用指针访问数组时,会有上面俩种写法。其实&arr[0]是拿到数组中的第一个元素的地址;大家要知道数组名本来就是地址,而且是数组首元素的地址。

通过输出结果,我们发现数组名和数组首元素打印出来的结果是一样的,数组名就是数组首元素(第一个元素)的地址 。


 其实数组名就是数组首元素(第一个元素)是对的,但是有俩个例外:

  • sizeof(数组名),sizeof中单独放数组名,这⾥的数组名表⽰整个数组,计算的是整个数组的⼤⼩, 单位是字节
  • &数组名,这⾥的数组名表⽰整个数组,取出的是整个数组的地址(整个数组的地址和数组⾸元素 的地址是有区别的)
#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;
}

输出的结果是:40。指针的大小根据编译器是4/8字节,而这里就是例外。


int arr[10] = { 0 };
printf(" &arr[0] = %p\n", &arr[0]); //指针类型是int*
printf(" &arr[0] + 1 = %p\n", &arr[0] + 1);

printf("arr = %p\n", arr); //指针类型是int*
printf("arr + 1 = %p\n", arr + 1);

printf("&arr = %p\n", &arr); //这个类型呢?

printf("&arr + 1 = %p\n", &arr + 1);

输出结果:

 这⾥我们发现&arr[0]和&arr[0]+1相差4个字节,arr和arr+1 相差4个字节,是因为&arr[0] 和 arr 都是 ⾸元素的地址,+1就是跳过⼀个元素。而它们的类型都是int* ,大家可以理解为指针变量只能存储一个地址。

但是&arr 和 &arr+1相差40个字节(如图是十六进制,差28,转成10进制是40),这就是因为&arr是数组的地址,+1 操作是跳过整个数组的。而它的类型是什么呢?大家可以思考一下,之后为大家解答。

总的来说:

指针类型决定了指针+-整数时的步长


 2.指针访问数组

有了前面的知识作为铺垫,再结合数组的特点,我们可以使用指针访问数组。

#include <stdio.h>
int main()
{
	int arr[10] = { 0 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	int* p = arr;
	int i = 0;
	//输入
	for (i = 0; i < sz; i++)
	{
		scanf("%10d", p + i); //也可以写成arr + i
	}
	//打印
	for (i = 0; i < sz; i++)
	{
		//printf("%d ", *(p + i));
		//printf("%d ", *(arr + i));
		//printf("%d ", arr[i]);
		printf("%d ", p[i]);
	}
	

	return 0;
}

 这个代码搞明⽩后,我们再试⼀下,如果我们再分析⼀下,数组名arr是数组⾸元素的地址,可以赋值 给p,其实数组名arr和p在这⾥是等价的。

当我们用数组的内容arr[i]打印各个元素时,数组元素的访问在编译器处理的时候,也是转换成首元素地址+偏移量求出元素地址,然后再解引用访问。

结论:arr[i] ---> *(arr + i) ---> *(i + arr) -->i[arr],这种大家需要了解一下,当然在写代码中写成i[arr]是不好的,不建议大家使用,但是大家需要知道这种写法。


3.二级指针

指针变量也是变量,是变量就有地址,那指针变量的地址存放在哪⾥? 这就是⼆级指针 。 

int a = 100;
int* pa = &a;
int** ppa = &p;  //pa就是二级指针变量,二级指针就是用来存放一级指针变量的
printf("%d ", **pa);

首先,&a指的是取地址,pa是指针变量,而*指的是它是指针变量,int指的是指向的对象a是int类型。 接下来看二级指针,ppa是二级指针变量,*指的是它是指针变量,int*指的是指向的对象p的类型是int*。

如图,因为创建变量的本质上是在内存中开辟一块新的地址。 

当然了,二级指针也能解引用运算

**ppa = 30;

///等价于*pa = 30;

//等价于a = 30;

 **ppa 先通过 *ppa 找到 pa ,然后对 pa 进⾏解引⽤操作: *pa ,那找到的是 a .


4. 指针数组

 大家来思考一下指针数组是什么?是指针?还是数组?

我们先来类比一下,整型数组,是存放整型的数组,字符数组是存放字符的数组。

 那指针数组呢?我们可以得知是存放指针的数组。

#include <stdio.h>
int main()
{
	int a = 20;
	int b = 11;
	int c = 12;
	int* arr[] = { &a, &b, &c }; //指针数组
	int i = 0;
	//打印
	for (i = 0; i < 3; i++)
	{
		printf("%d ", *(arr[i]));
	}
	return 0;
}

指针数组模拟二维数组

#include <stdio.h>
int main()
{
	int arr1[5] = { 1,2,3,4,5 };
	int arr2[6] = { 2,3,4,5,6 };
	int arr3[5] = { 3,4,5,6,8 };

	int* parr[]= { arr1, arr2, arr3 };
	int i = 0;
	for (i = 0; i < 3; i++)
	{
		//arr[i]
		int j = 0;
		for (j = 0; j < 5; j++)
		{
			printf("%d ", p[i][j]);
		}
		printf("\n");
	}
	return 0;
}

 parr[i]是访问parr数组的元素,parr[i]找到的数组元素指向了整型⼀维数组,parr[i][j]就是整型⼀维数 组中的元素。

 上述的代码模拟出⼆维数组的效果,实际上并⾮完全是⼆维数组因为每⼀⾏并⾮是连续的。

  • 10
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值