数组名和指针之间,经常会交替使用这两个变量,
可以把一个指针当成数组来使用,或者是把数组名赋值给指针,通过指针来访问数组成员变量,
代码示例 :
#include
int main()
{
int array[] = {1,2,3,4,5};
int *p_array = array;
int len = sizeof(array) / sizeof(array[0]);
printf("数组方式输出:\n");
for (int i = 0; i < len; i++)
{
printf("%d ", array[i]);
}
printf("\n\n指针当成数组来使用:\n");
for (int i = 0; i < len; i++)
{
printf("%d ", p_array[i]);
}
printf("\n\n以指针的方式访问:\n");
int *temp_ptr = p_array;
for (int i = 0; i < len; i++)
{
printf("%d ", *temp_ptr++);
}
}
运行结果:
示例代码:
#include
using namespace std;
int main()
{
int array[] = {1,2,3,4,5};
int a = 0;
int *p_array = array;
//printf("%p", array++); //编译器报错,不能更改array
printf("%p", p_array++); //正确,指针可修改
}
假设为int数组
对数组名取&:类型变为int[num]*,即指向数组的指针,为整个数组的首地址
对指针名取&:类型变为int**,即指向指针的指针,为指针变量自身的地址
示例代码:
#include
using namespace std;
int main()
{
int array[] = {1,2,3,4,5};
int a = 0;
int *p_array = array;
//重新定义一个用指针定义的数组
int len = sizeof(array) / sizeof(array[0]);
//打印每个数组元素的地址
for (int i = 0; i < len; i++)
{
printf("&p_array[%d] =%p\n", i, &array[i]);
}
//打印a的地址
printf("&a =%p\n", &a);
printf("&p_array =%p\n",&p_array); //打印指针变量p_array的在内存中的地址
printf("p_array =%p\n", p_array); //打印p_array存储的值
printf("\n");
printf("&array =%p\n", &array); //打印的是数组的首地址,&array的类型是int[5]*,即指向数组的指针
printf("&array+1 =%p\n", &array+1); //因为它本身是指向int[5]*,所以该指针+1,就加了4*5=20个字节
printf("&array[0] =%p\n", &array[0]); //打印的是数组第一个元素的首地址,&array[0]的类型是int*,即指向int的指针
printf("&array[0]+1 =%p\n", &array[0]+1);//因为它本身是指向int*,所以该指针+1,就加了4个字节
printf("array =%p\n", array); //打印的是数组第一个元素的首地址,array的类型是int*,即指向int的指针
printf("array+1 =%p\n", array+1); //因为它本身是指向int*,所以该指针+1,就加了4个字节
}
运行结果:
VS2017下:
Ubuntu的g++下:
示例代码:
#include
using namespace std;
int main()
{
int array[] = {1,2,3,4,5};
int a = 0;
int *p_array = array;
printf("sizeof(array) = %d",sizeof(array));
printf("\nsizeof(p_array) = %d", sizeof(p_array));
}
运行结果:
总结:可以发现,对于数组名在不同场景下其实有两种语义:
1.直接使用数组名,数组名代表的是指向数组第一个元素的指针,所以在+1之后也只是加了一个元素类型的字节
2.对数组名取&或取sizeof,数组名代表的是整个数组,而取地址之后就变成了指向数组的指针,所以在+1之后是加了一整个数组的字节
定义 int (*p)[n];
()优先级高,首先说明p是一个指针,指向一个整型的一维数组,这个一维数组的长度是n,也可以说是p的步长。也就是说执行p+1时,p要跨过n个int数据的长度。
示例代码:
#include
using namespace std;
void test_array_pointer()
{
printf("数组指针\n");
int(*p)[3]; //定义一个数组指针,指向含有三个元素的一维数组
int a[2][3]; //定义一个二维数组
printf("sizeof(p) = %d\n",sizeof(p)); //打印的是指针的大小,为4个字节
p = a;
printf("a = %p\n",a); //输出第一个元素的地址
printf("a+1 = %p\n", a+1); //第一个元素的类型是int[3],所以+1加的是4*3=12个字节
printf("p = %p\n", p); //p是一个指向int[3]的指针,p=a的时候,a是指向第一个元素的指针,
//即为指向int[3]的指针,即p指向数组a的第一个元素
printf("p+1 = %p\n", p+1); //p指向的类型为int[3],+1即跳过int[3]所代表的字节数,即4*3=12个字节
}
int main()
{
test_array_pointer();
}
运行结果:
定义 int *p[n];
[]优先级高,先与p结合成为一个数组,再由int*说明这是一个整型指针数组,它有n个指针类型的数组元素。这里执行p+1时,则p指向下一个数组元素,这样赋值是错误的:p=a;因为p是指向p数组的第一个元素的常量指针(类型为int** const),不可以进行赋值,p[0]、p[1]、p[2]...p[n-1](类型为int*),它们分别为指针变量可以被赋值存放变量地址。但可以这样 *p=a;
这里*p表示指针数组第一个元素的值,a为数组a的第一个元素的地址,即&a[0]
示例代码:
#include
using namespace std;
void test_pointer_array()
{
printf("指针数组\n");
int *p[2]; //定义一个指针数组,有两个元素
int a[2][3] = { {11,12,13}, {21,22,23} }; //定义一个二维数组,定义了2行3列
printf("sizeof(p) = %d\n",sizeof(p)); //打印的是数组的大小,为8个字节
for (int i = 0; i < 2; i++)
{
p[i] = a[i]; //a[i]本身是一个int[3]*,值是每一行的首地址
}
printf("a = %p\n", a); //&a[0]
printf("a+1 = %p\n", a + 1); //&a[1]
printf("p = %p\n", p); //指向数组p的第一个元素的地址,p的类型为int**
printf("p+1 = %p\n", p + 1); //指向数组p的第一个元素的地址,给p+1相当于加p所指向元素的类型的大小,
//即int*,即4个字节
printf("*p = %p\n", *p); // 等价于p[0] 指向a的第一行起始位置
printf("*(p + 1) = %p\n", *(p + 1));// 等价于p[1] 指向a的第二行的起始位置
for (int i = 0; i < 3; i++)
{
printf("%d ", *(*p + i)); //*p即p[0]是int*,即指针,给指针+1,表示加它所指向的类型的大小,
//这里即加int的大小,即4个字节,每一次迭代都4个字节然后解引用即取到第一行的每一个值
}
printf("\n");
for (int i = 0; i < 3; i++)
{
printf("%d ", *(*(p + 1) + i));
}
printf("\n\n");
for (int i = 0; i < 3; i++)
{
printf("%d ", *(p[0] + i));
}
printf("\n");
for (int i = 0; i < 3; i++)
{
printf("%d ", *(p[1] + i));
}
}
int main()
{
test_pointer_array();
}
运行结果:
上述代码图解:
优先级:()> [] > *