【C语言】指针剖析(2)

©作者:末央&

©系列:C语言初阶(适合小白入门)
©说明:以凡人之笔墨,书写未来之大梦

在这里插入图片描述

一、数组名

什么是数组名?例如以下

1.概念

int arr[10];
//arr就是数组名;

那么数组名在内存中的地址有什么特殊的地方吗,可以看看。
在这里插入图片描述

总结:数组名是数组首元素的地址,即arr[0]的地址

2.sizeof和&里面的数组名

这里相对于我们上面总结的可以理解"数组名是数组首元素的地址"是两个例外

sizeof

int arr[10];
printf("%d\n", sizeof(arr));

在这里插入图片描述

&

int arr[10];
printf("arr[0]%p\n", &arr[0]);
printf("arr   %p\n", &arr);

在这里插入图片描述
这里值得注意的是arr和arr[0]的地址是一样的,那么&arr和&arr[0]还有区别吗?我们不妨在上面基础上再修改一下代码。

int arr[10];
printf("arr[0]%p\n", &arr[0]+1);		
printf("arr   %p\n", &arr+1);

结合我们上期的知识,知道指针加减一个整数取决于他的指针类型,&arr[0]的指针类型是int,&arr的指针类型是一个数组指针(后期会讲),那么那么前者+1就是跳过一个int(4个字节),后者+1就是跳过一个数组(40个字节)
这里还要注意的是我们为什么可以进行直接的指针+1-1运算,因为我们数组在内存中是连续存放的,如果不是连续存放的就有可能访问到我们没有权限访问的空间。
在这里插入图片描述

总结:sizeof(数组名),sizeof中单独放数组名,这⾥的数组名表⽰整个数组,计算的是整个数组的⼤⼩, 单位是字节
&数组名,这⾥的数组名表⽰整个数组,取出的是整个数组的地址(整个数组的地址和数组⾸元素 的地址是有区别的)
除此之外,任何地⽅使⽤数组名,数组名都表⽰⾸元素的地址。

二、使用指针访问数组

我们通常访问数组都是以数组下标的方式来访问数组的,例如:

	int arr[10] = { 0 };
	int i;
	for (i = 0; i < 10; i++)
	{
		printf("%d ", arr[i]);
	}


但是我们也可以这样写:

int arr[10] = { 0 };
int i = 0;
int* p = arr;
for (i = 0; i < 10; i++)
{
	printf("%d\n", p[i]);
}

为什么指针也可以替代数组名的位置了,其实不管是数组访问还是指针访问都可以化成这样的形式:*(数组名/指针变量名+变量/常量)
那也可以这样写:

int arr[10];
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);//也可以这样写
}
//输出
for (i = 0; i < sz; i++)
{
	printf("%d ", *(p + i));
}

i[p]和i[arr]也可以,编译器
会把数组名[变量]转换为*
(数组名+变量)形式这里的[变量]
相当于a+b中的+号如果是-变量则是减号,支持加
法交换律

三、一维数组传参本质

看以下代码
1.

void test(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;

在这里插入图片描述
为什么这里的sz2是1而不是和sz1一样是10呢,这就涉及到一维数组传参的问题了
我们刚刚在讲数组名的时候不是讲了除了sizeof和&里面的数组名以外,其他全是首元素地址。所有这里传参arr本质上就是传的首元素地址

又因为sizeof(arr) 计算的是⼀个地址的⼤⼩(单位字节)⽽不是数组的⼤⼩(单位字节)。正是因为函数的参数部分是本质是指针,所以在函数内部是没办法求的数组元素个数的。
所以首元素地址只有4个字节(int类型),4/4=1

四、指针数组

1.概念

指针数组到底是数组还是指针,指针是形容词数组是名词。所以指针数组本质上还是数组.其次整形数组是存放整形的数组,字符数组是存放字符的数组,那么指针数组实际上就是存放指针的数组
在这里插入图片描述

在这里插入图片描述

实例(模拟二维数组)

int arr1[] = {1,2,3,4,5};
 int arr2[] = {2,3,4,5,6};
 int arr3[] = {3,4,5,6,7};
 //数组名是数组⾸元素的地址,类型是int*的,就可以存放在parr数组中
 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]);
 }
 printf("\n");

在这里插入图片描述
要注意的是,上述代码只是模拟二维数组,实际上并不是真正的二维数组,因为他的行并不是连续存储的。而是通过指针找到每一行的首元素地址来进行访问。

再回忆一下我们之前说的p[i]=(p+i)这是一维数组用指针访问,那么二维数组是不是也可以触类旁通的写成:(*(arr+i)+j)

五、手脑并用

来来来,咱们直接上代码

nt main()
{
  int aa[2][5] = {10,9,8,7,6,5,4,3,2,1};
  int *ptr1 = (int *)(&aa + 1);
  int *ptr2 = (int *)(*(aa + 1));
  printf( "%d,%d", *(ptr1 - 1), *(ptr2 - 1));
  return 0;
}

小提示:这里明显涉及到我们上面讲的&数组面和前几篇文章讲的指针加减整数运算的概念问题。

好了,我们直接上图来看看吧
在这里插入图片描述
这里字有点丑哈,请谅解
那么结果就是:1 6

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值