转自zhanjindong越简单越好:数组名和指针的区别

我相信很多人都跟我一样被某些书害的不浅,在C语言中一直还把指针跟数组名混为一谈。其实它们跟本就是两样的东西,指针就是指针,数组就是数组,网上也有很多大牛作过很多非常深入的讨论,但是个人感觉有时候把问题想得太复杂了反而不好,尤其是对于新手,因为我们新手很难搞懂编译器背着我们到底都干了些什么。我们有时候应该透过现象看本质,但有时候也不要太钻牛角尖,一口吃不出个胖子,必要时“难得糊涂”,站在抽象的角度去看事情,很多所谓的“本质”归根到底就是“规则”,让我们返朴归真看看标准是怎么说的,对于新手关于数组和指针的区别和以及什么时候“相同”只要记住《c专家编程》中提到的三个标准和三个例外就可以了:

规则1. 表达式中的数组名被编译器当作一个指向该数组第一个元素的指针。

规则2. 下标总是与指针的偏移量相同。

规则3. 在函数参数的声明中,数组名被编译器当作指向该数组的第一个元素的指针。

在下列的情况下,对数组的引用不能用指向该数组第一个元素的指针来代替:

例外1. 数组作为sizeof()的操作数,显然此时需要的是整个数组的大小,而不是所指向第一个元素的大小

例外2. 使用&操作符取数组的地址

例外3. 数组是一个字符串常量初始化值

一个很简单的例子:

#include <stdio.h>

char ga[]="abcdrfghik";

void method(char ca[])//or char *ca
{
    printf(" addr of arrary param = %#x \n",&ca);
    //规则3
    printf(" (*ca) = %c \n",*ca);
    printf(" addr (ca[0]) = %#x \n",&(ca[0]));
    printf(" addr (ca[1]) = %#x \n",&(ca[1]));
    printf("++ca = %#x \n\n",++ca);
}
int main(void)
{
    //例外2 这个只是数组和指针能够互换的一个例外。这里ga代表数组,这个获取的数组的地址
    printf(" addr of arrary param = %#x \n",&ga);
    //规则1
    printf(" (*ga) = %c \n",*ga);
    printf(" addr (ga[0]) = %#x \n",&(ga[0]));
    printf(" addr (ga[1]) = %#x \n",&(ga[1]));
    //例外1
    printf(" sizeof ga = %d \n\n",sizeof(ga));


    method(ga);

    return 0;
}

另外,

“数组名被改写成一个指针的参数”规则并不是递归定义的。数组的数组会被改写成“数组的指针”而不是“指针的指针”

比如char c[8][10]所被改写对应的形参为char (*)[10],为“数组的指针”。

一个简单的例子:

#include <stdio.h>
#include <malloc.h>

method(int a[3][2])
{
    int i=0;
    int j=0;
    for(i=0;i<=2;i++)
    {
        for(j=0;j<=1;j++)
        {
            printf("%d\n",a[i][j]);
        }

    }

    for(i=0;i<=2;i++)
    {
        for(j=0;j<=1;j++)
        {
            printf("%d\n",*(*(a+i)+j));
        }

    }

    int k=0;
    for(k=0;k<=5;k++)
    {
        //a是指向 int (*)[2] 的行指针,*a即为二位数组的首行首元素的地址
        printf("%d\n",*(*a+k));
    }
}
int main(void)
{

    int a[3][2]={{1, 2}, {3, 4},{5, 6}};
    method(a);

    return 0;
}

至于更深层的知识水到自然渠成。