面试经典-C语言之数组名分析

在腾讯春季实习生招聘笔试的时候遇到这么一个问题:

给定一个数组int a[10]; 下面哪些不可以表示a[1]的地址?
A. a+sizeof(int)
B. &a[0]+1
C. (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,那么,关于数组名,到底有哪些特性呢?

  1. 数组名是一个指针常量,指向数组的第一个元素,但是当数组作为参数传入函数时,数组名的这一特性消失,可以做自增自减等操作。
    例如,对于下面这段代码:
    #include <stdio.h>
    
    int main()
    
    {
    
    	int a[5]={1,2,3,4,5};
    
    	a++;
    
    }

    image
    提示只有左值(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++;
    
    }
    
  2. 数组名和数组名取地址的指向的位置是一样的,但是它们有区别,以上面声明的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] ); //加上这句话会出错
    

    相应的输出如下:
    image
    可以看出a和&a数值上是一样的,&a+1相较于a多了20个字节的距离,这正好是一个数组的长度。
  3. sizeof(a)不是指针所占空间的大小,而是指数组a所占空间的大小。
posted @ 2013-04-17 20:59  曾见绝美的阳光  阅读(615)  评论(0编辑  收藏  举报