zoukankan      html  css  js  c++  java
  • 娓娓道来c指针 (3)指针和数组

                                (3)指针和数组

    在c中指针和数组似乎有着千丝万缕的关系。事实上它们不是一回事:指针是指针,数组是数组。两者不同样。

    说它们有关系,只是是由于常见这种代码:

    int main()
    {
    	int array[] = {1,2,3,4,5};
    	int n = sizeof(array) / sizeof(int);
    	int *p = array;
    	int i;
    	for (i = 0; i < n; i++)
    		printf("p[%d]...%d
    ", i, p[i]);
    	system("pause");
    	return 0;
    }
    执行


    在上面的代码中,指针和下标运算符的结合使用,给人一种指针和数组是一样的感觉。

    本质是:数组名是一个指向数组起始元素的常量指针。这也是数组和指针的唯一联系!

    之所以能够使用 p[i] 来訪问数组中的元素,是由于在编译器中 p[i] 被解释为 *(p+i),这仍然是指针的功能。

    对编译器而言,用p[i]表达*(p+i)的含义是没有意义的。它仅仅是为了让人看着舒服。用着方便。这是语法糖

        p[i]是*(p+i)的简单写法,实际上。至少对于编译器来说,[]这种运算符全然能够不存在。

        但是对于人类来说。*(p+i)的写法在解读上比較困难,写起来也麻烦(键入量大)。因此,c语言引入[]运算符。

        就像这样。这些不过为了让人类easy理解而引入的功能,的确能够让我们感受到编程语言的甜蜜味道(easy着手),有时我们称这些功能为语法糖(syntax sugar 或者 syntactic sugar)。

    以上摘自《征服c指针》。借此推荐这本书。书中一针见血地指出:仅仅有在声明语句中。[]才表达数组的含义。在表达式中,[]与数组无关!

    总结起来就是。看似数组的使用方法:p[i],事实上是*(p+i)的语法糖。p仍然是指针,与数组并无关系。


    指针和数组的不同之处,还能够从以下的样例看出

    void fun(int array[5])
    {
    	printf("  sizeof(array)...%d
    ", sizeof(array));
    }
    int main()
    {
    	int array[] = { 1, 2, 3, 4, 5 };
    	printf("  sizeof(array)...%d
    ", sizeof(array));
    	fun(array);
    	return 0;
    }
    执行


    从执行结果看,函数形參尽管用数组的方式进行了声明,但仍然被当做指针。这揭示了c语言中传递数组时的规则:传递过去的是地址,是指向数组起始元素的地址。之所以这样,基于两点;

    1. 从效率上考虑。若是把整个数组赋值过去,太耗时,也耗空间。还不如传地址过去,使用同一份内容。
    2. 在c语言设计之初,赋值操作就仅限于基本类型(char、int、float……),而数组是聚合类型。
    这给我们的编程启发是:传递数组时,不要忘了把数组大小也传递过去。否则,函数那边因为不知道数组大小,极易越界。

    应这样设计函数 void fun(int *array, int n),n是数组大小。

    另一点须要指出。即使函数被设计成void fun(int array[5], int n),array依旧被看成是指针。

    也就是说即使数组带了长度。该长度也会被编译器忽略掉。一句话:形參中的数组统统看成指针。

    既然如此,还不如直接写成void fun(int *array, int n)。指针的形式。更能表达本意。


    再思考:假设p[i]是*(p+i)的意思。因为加法具有交换律:p+i=i+p,那么i[p]相同能够表达p[i]的意思,是这种吗?实验验证:
    int main()
    {
    	int array[] = { 1, 2, 3, 4, 5 };
    	int n = sizeof(array) / sizeof(int);
    	int *p = array;
    	int i;
    	for (i = 0; i < n; i++)
    		printf("  %d[p]...%d
    ", i, i[p]);
    	return 0;
    }
    执行

    实验证明,我们的猜想是正确的:p[i]确实是*(p+i)的语法糖。i[p]这种写法是否非常逆天呢!

    总结:仅仅有在函数形參中,仅有这一种情况,声明的数组。如 int array[]会被看作是指针。其他情况下,指针与数组并无联系。

    &array的含义
    另一点,对于 int array[5];array表示指向数组起始元素的指针,那么&array又是什么呢?实验下:
    int main()
    {
    	int array[] = { 1, 2};
    	printf("   array...%p
    ", array);
    	printf("  &array...%p
    ", &array);
    	printf("&array+1...%p
    ", &array+1);
    	return 0;
    }
    执行

    分析实验结果:0031FCEC与0031FCE4相差8。而sizeof(array)就是8。
    结论就是:array和&array都是指针。但类型不同。array的类型是int*。而&array的类型是int(*)[2]。

    array是指向普通int类型的指针;&array是数组指针,该数组元素是int类型的,且数组大小是2。

    至于array和&array两者的值是一样的,应该非常好理解。

    补充
    标量(scalar):简单讲,标量就是指char、int、double和枚举类型等数值类型,再加上指针。

    至于数组、结构体和共用体这样将多个标量进行组合的类型,我们称之为聚合类型(aggregate)。

    那么为什么int(*)[2]表示的是数组指针呢?这须要透彻理解c的声明语法。又比方。二维数组(更甚者,多维数组)的数组名又是什么类型的指针呢?这须要了解c中数组的实际含义,后序解说。

    很多其它指针和数组的内容见(5)c数组本质


    专栏文件夹:


  • 相关阅读:
    python走起之第十七话
    python走起之第十五话
    python走起之第十四话
    python走起之第十三话
    python走起之第十二话
    python走起之第十一话
    python走起之第九话
    python走起之第九话
    python走起之第八话
    python走起之第六话
  • 原文地址:https://www.cnblogs.com/yxwkf/p/5320030.html
Copyright © 2011-2022 走看看