1.使用指针访问数组
有了前面的知识,我们就可以用指针来访问数组了。但在此之前,我们得知道数组名蕴含的意义。
首先,我们来分析如下代码
#include <stdio.h>
int main()
{
int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
printf("%p\n", arr);//
printf("%p\n", &arr[0]);//数组arr首元素的地址
return 0;
}
上述代码,%p这个占位符是用来打印地址的,我们发现打印arr(数组名)和&arr[0]的地址是一模一样的,我们就得出结论,数组名本身就是地址且是数组首元素的地址。
但是有两个例外:
1)sizeof(数组名) :sizeof里面直接放数组名,这里的数组名表示的是整个数组,计算的整个数组的大小
2)&数组名:这里的数组名表示的也是整个数组,取出的是整个数组的地址。
代码演示:
#include <stdio.h>
int main()
{
int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
printf("%d\n", sizeof(arr[0]));//计算数组首元素的大小
printf("%d\n", sizeof(arr));//计算整个数组的大小
printf("%p\n", &arr[0]);//打印数组首元素的地址
printf("%p\n", &arr);//打印整个数组的地址
return 0;
}
上述代码的结果清晰地解释了第一个例外,但是我们可以看到&arr(整个数组地址)和&arr[0](数组首元素地址)打印出的地址怎么都一样啊,这时我们又纳闷了:&arr和arr有啥区别啊,不急我们做如下测试:
#include <stdio.h>
int main()
{
int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
printf("%p\n", arr);
printf("%p\n", arr + 1);
printf("%p\n", &arr[0]);
printf("%p\n", &arr[0] + 1);
printf("%p\n", &arr);
printf("%p\n", &arr + 1);
return 0;
}
从上述结果可以看出例外一是正确的,arr和&arr[0]都是首元素的地址,+1表示跳过1个元素,也就是跳过4个字节,而&arr取出的是整个数组的地址,+1表示跳过整个数组,也就是跳过40个字节。
总结:数组名表示首元素地址,但是有两个例外,一个是sizeof(arr),另一个是&arr。
数组名了解完,我们就可以使用指针来访问数组了。
代码如下:
#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("%d", p + i);
/*scanf("%d",arr+i);*/
}
for (i = 0; i < sz; i++)
{
printf("%d ", *(p + i));
/*printf("%d ",p[i]);*/
}
printf("\n");
return 0;
}
从上述结果看出,我们成功地使用指针访问了数组,我们再深入分析一下,arr代表 的是数组首元素的地址,它可以赋值给p,那是不是p和arr就等价呢?答案是对的,之前我们学数组的时候,可以通过下标来访问数组,也就是arr[i]来访问数组,那是否可以改成p[i]来访问数组呢?答案也是对的。
代码如下:
#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("%d", p + i);*/
scanf("%d",arr+i);
}
for (i = 0; i < sz; i++)
{
/*printf("%d ", *(p + i));*/
printf("%d ",p[i]);
}
printf("\n");
return 0;
}
2.指向指针的指针 (二级指针)
我们通过指针来访问变量叫做间接访问,由于指针变量直接指向要访问的变量,成为“单级间址”的间接访问,那如果通过指向指针的指针变量来访问要访问的变量,这就是“二级间址”的间接访问,也叫二级指针,也就是指针变量存放的地址。
例子
#include <stdio.h>
int main()
{
int a = 10;
int* p = &a;
int** pp = &p;
return 0;
}
p是指向变量a的指针变量,pp是指向指针p的指针变量。
二级指针里的一些运算:
1)*pp表示的是对pp地址的解引用,相当于指针变量p;
2)**pp表示的是先通过*pp来找到指针变量p,然后再通过解引用*p来找到a
3.指针数组
我们可能一开始看到这个指针数组,不知道它是指针还是数组,我们可以通过类比来判断,之前我们学习了数组,数组里面有整型数组,它是存放整型变量的数组,字符数组是存放字符变量的数组,那么我们可以判断出指针数组是存放指针类型变量的数组。
4.指针数组模拟实现二维数组
上面我们已经知道指针数组的概念,那么我们可以用指针数组来模拟实现一个二维数组,将二维数组打印在屏幕上。
代码如下:
#include <stdio.h>
int main()
{
int arr1[] = { 1,1,1,1 };
int arr2[] = { 2,2,2,2 };
int arr3[] = { 3,3,3,3 };
int *arr[3] = { arr1,arr2,arr3 };//数组名表示首元素的地址,类型为int*,可以存放在指针数组arr中
int i = 0;
int j = 0;
for (i = 0; i < 3; i++)
{
for (j = 0; j < 4; j++)
{
printf("%d ", arr[i][j]);
}
printf("\n");
}
return 0;
}
上述代码成功使用指针数组模拟出了二维数组 ,但由于每行未必连续,所以不一定是二维数组。