面试经典-C语言之数组名分析
在腾讯春季实习生招聘笔试的时候遇到这么一个问题:
给定一个数组int a[10]; 下面哪些不可以表示a[1]的地址?A. a+sizeof(int)B. &a[0]+1C. (int*)&a+1
D.(int*)((char*)&a+sizeof(int))
对于这个题目,我当时的分析是这样的,对于数组名a,它是一个int*指针常量,指向数组第一个元素的地址,既然是指针常量,a+sizeof(int)即为a+4,肯定是不可以表示a[1]的,B显然是可以的,对于C答案,就出现疑惑了,对一个指针取地址应该是int **类型,那么(int*)&a 应该表示指向存放a指针的区域的指针,看起来好像与a[1]毫不相干,所以C应该是不行的(实际证明是可以的),对于D答案,同样的道理,好像是不行的,因此答案似乎是ACD.
出人意料的是,答案尽然是A而已,这是为什么?
好吧,那是因为&a和a指向的是同一地点,如果有这个结论,得到答案A就不足为奇了。我记起来当初学sizeof函数的时候,向当时教C语言的老曹头问过了一个问题,为什么sizeof(a)的值不是4而是数组的大小呢,比如说这个例子里面就是20而不是4,那么,关于数组名,到底有哪些特性呢?
- 数组名是一个指针常量,指向数组的第一个元素,但是当数组作为参数传入函数时,数组名的这一特性消失,可以做自增自减等操作。
例如,对于下面这段代码:
#include <stdio.h>
int main()
{
int a[5]={1,2,3,4,5};
a++;
}
提示只有左值(lvalue)才能自增。而对于以函数名作为参数输入时,这一常量特性消失,如下面代码运行就没有问题:
#include <stdio.h>
void Func(int a[5]);
int main()
{
int a[5]={1,2,3,4,5};
Func(a);
}
void Func(int a[5])
{
a++;
}
- 数组名和数组名取地址的指向的位置是一样的,但是它们有区别,以上面声明的int a[10]为例,a表示指向整数的指针,而&a表示指向数组的指针,下面这段代码清楚地说明了这一问题:
#include <stdio.h>
void Func(int a[5]);
int main()
{
int a[5]={1,2,3,4,5};
printf("The value of a is %X\n",a );
printf("The value of &a is %X\n", &a);
printf("The value of a+1 is %X\n",a+1 );
printf("The value of &a+1 is %X\n",&a+1 );
int *p1=(int *)(a+4);
printf("%d\n",p1[-1] );
printf("%d\n",((int *)(a+4))[-1] );
int *p2=(int *)(&a+1);
printf("%d\n",p2[-1] );
//printf("%s\n",((int *)(&a))[1] ); //加上这句话会出错
相应的输出如下:
可以看出a和&a数值上是一样的,&a+1相较于a多了20个字节的距离,这正好是一个数组的长度。 - sizeof(a)不是指针所占空间的大小,而是指数组a所占空间的大小。