数组名可以当作常量指针使用,那么指针是否也可以当作数组名来使用呢?
1.不同形式访问元素
以下标的形式访问数组的元素
int a[5]={0};
a[1]=3;
以指针的形式访问数组的元素
int a[5]={0};
*(a+1) = 3;
下标形式与指针形式的转换:
现代编译器的生成代码优化率已大大提高,在固定增量时,下标形式的效率已经和指针形式相当﹔但从可读性和代码维护的角度来看,下标形式更优。
是否可以使用指针当数组名使用,编程来看结果
#include <stdio.h>
int main()
{
int a[5] = {0};
int* p = a;
int i = 0;
for(i=0; i<5; i++)
{
p[i] = i + 1;//把指针当作数组名来使用
}
for(i=0; i<5; i++)
{
printf("a[%d] = %d\n", i, *(a + i));
}
printf("\n");
for(i=0; i<5; i++)
{
i[a] = i + 10;
}
for(i=0; i<5; i++)
{
printf("p[%d] = %d\n", i, p[i]);
}
return 0;
}
数组名可以当作常量指针使用,那么指针是否也可以当作数组名来使用呢?
从结果来看,是可行的。
2.数组和指针不同
两个文件,一个test.c,一个ext.c
#include <stdio.h>
int main()
{
extern int* a;
//打印出数组首地址的地址值
printf("&a = %p\n", &a);
//打印指针变量a所存的地址,a=1;
//打印指针的值就是到自己的地址去取四个字节,而此处存的是0x01;
printf("a = %p\n", a);
//到a所保存的地址值0x01低地址去取数据,会产生段错误,该低地址是保留给操作系统使用的
printf("*a = %d\n", *a);
return 0;
}
int a[]={1,2,3,4,5};
编译运行 :
可以得知,extern int* a;
和extern int a[];
是不同的,如果是声明为a[],那么打印出来的&a和a是同个地址,即数组的首地址,*a是第一个元素的值。所以我们知道,数组名只是可以看成常量指针,而不是真的是指针。
3.a和&a的区别
a为数组首元素的地址,&a为整个数组的地址,a和&a的区别在于指针运算。
+1增加的步长所示不一样的,上面的是增加一个元素的大小,下面的是增加的是整个数组地址的大小。
4.指针运算经典问题
下面的程序输出什么,为什么?
#include <stdio.h>
int main()
{
int a[5] = {1, 2, 3, 4, 5};
int* p1 = (int*)(&a + 1); //数组的地址+1,移动一整个数组大的长度大小,即a[5]
int* p2 = (int*)((int)a + 1);//把a转整型+1,得到一个数组内的地址,已经不是指针运算
int* p3 = (int*)(a + 1);//指向第二个元素
printf("%d, %d, %d\n", p1[-1], p2[0], p3[1]);
//x 2 2
return 0;
}
// A. 数组下标不能是负数,程序无法运行
// B. p1[-1]将输出随机数,p2[0]输出2, p3[1]输出3
// C. p1[-1]将输出乱码, p2[0]和p3[1]输出2
编译运行的答案是:
p1[-1]输出了5,p1相当于a[5],p1[-1] ==>*(p1-1)
,a[5]指针-1运算,得到a[4],也就是5。
p2[0]已经不是指针运算,得到的是一个数组地址内的值,在小端系统下,示例如下图所示,十进制33554432。
p3[1]输出3,原因在于,p3[0]指向的就是a[1],所以开始算的位置是2是p3[0],3是p3[1]。
5.数组参数
数组作为函数参数时,编译器将其编译成对应的指针。
结论:
一般情况下,当定义的函数中有数组参数时,需要定义另一个参数来标示数组的大小。
虚幻的数组参数
实例分析,说明数组参数会退化为指针
#include <stdio.h>
void func1(char a[5])
{
printf("In func1: sizeof(a) = %d\n", sizeof(a));//打印数组的大小,5*1=5
*a = 'a';
a = NULL;//如果是数组,这里是错误的,数组名不可被赋值
}
//这个函数同上,只是传进去的数组大小没有写
void func2(char b[])
{
printf("In func2: sizeof(b) = %d\n", sizeof(b));
*b = 'b';
b = NULL;
}
int main()
{
char array[10] = {0};
func1(array);
printf("array[0] = %c\n", array[0]);
func2(array);
printf("array[0] = %c\n", array[0]);
return 0;
}
编译通过,说明了传进去的char a[5]
参数和char b[]
参数已经被转为了指针,因为可以运行 a= NULL;和 b = NULL;
而且打印出来的参数的大小为8(64位系统),且 * a和* b可以修改array数组里的值,很明显是指针类型。
6.小结
1.数组名和指针仅使用方式相同
2.数组名的本质不是指针
3.指针的本质不是数组
4.数组名并不是数组的地址,而是数组首元素的地址
5.函数的数组参数退化为指针