C中指针和数组引发的探索二

       在上一篇文章中分析了指针与数组的区别,包括编译器内存分配概况:http://www.cnblogs.com/guoyuanwei/archive/2012/06/05/2535413.html 

这篇文章将主要研究下指针和数组间相同点。

在1978年7-8月,The Bell System Technical Journal,57卷,6号,第1991-2019页中提到:“当一个数组名出现在一个表达式中时,它会被转换为一个指向该数组第一个元素的指针

1、“表达式中的数组名就是指针”如下代码

       int a[10], *p, i=2;

       p=a; p[i];

      上面的代码表示取p[i]的值,可以看到这时指针和数组是一样的用法。实际上对数组的引用如a[i]在总是被编译器编译为*(a+1),这个是C语言的标准规定的,因此编译器的设计者,都遵循

了这个规律,因此在一个表达式中数组名也就成了指针。

2、“C语言把数组下标[]作为指针的偏移量”处理

       产生这个现象的根本原因在与硬件机制,指针和偏移量是底层硬件所使用的基本模型

3、 “作为函数参数的数组名等于指针”

      在C标准中规定,在函数形参这个特殊情况下,编译器必须把数组形式改写成指向数组第一个元素的指针形式。编译器只向该函数传递数组的地址,而不是整个数组的拷贝,编译器之所以这样做,主要从效率方面考虑,如果拷贝整个数组,无论在时间上还是在内存空间上开销都比较大。因此C语言标准中规定:“所有数组在作为参数传递时,都转换为指向数组起始地址的指针,而其它参数均采用传值调用”,这样也可以简化编译器的设计。

      同理函数的返回值也不可能是一个数组,只能是指向数组的指针。这里实际上体现出了一个“传值”与“传址”的区别,这在其它编程语言如C++,C#都有这样的区别。在函数内部使用指针,所能进行的对数组的操作几乎跟传递原本的数组没啥差别。但是如果想用sizeof(实参)来获取数组的长度,得到的结果并不是数组的长度。如下面代码:

 void Fun7(char *a);
void Fun8(char a[]);

int main(int argc,char*argv[])
{

char s1[]="abcdef";  
 char *s2="abcdef";
 Fun7(s1);
 Fun8(s1);

void Fun7(char *a)
{
  printf("%d",sizeof(a)) ;
  printf("%s",a);

}

void Fun8(char a[])
{
  printf("%d",sizeof(a)) ;
  printf("%s",a);
}

   函数Fun7和Fun8被调用,执行的结果是一样的,但是里面sizeof(a)值并不是数组的大小6,而为4,因为a代表的是一个指针,指针的大小就是4个字节,这也证明了上面的分析。为了进一步的理解这个问题,输入下面的代码,先分析输出的情况:

#include<stdio.h>
void fun1(char *s);
int main(void)
{
    char a[]="abcdefg";
    fun1(a);
    char c=getchar();
}

void fun1(char *s)
{
    printf("%d\n",s);
    printf("%d\n",&s);
    printf("%d\n",&(s[0]));
    printf("%d\n",&(s[1]));
}

上面的代码将一个字符数组当作参数传入,

printf("%d\n",s)这条语句应该输出的是指针变量s的值,也就是数组元素的首地址;

printf("%d\n",&s);这条语句应该输出的是编译器给实参s分配的地址,是一个栈区域的地址值;

printf("%d\n",&(s[0]));这条语句应该输出的是数组中第一个元素的地址值;与printf("%d\n",s)结果应该相同。

printf("%d\n",&(s[1]));输出的是数组中第2个元素的地址值。比printf("%d\n",s)输出值大1

运行上面的代码,结果如下:

可以看到与分析的一致。

posted @ 2012-06-05 21:40  郭远威  阅读(284)  评论(0编辑  收藏  举报