《c和指针》笔记7
除了优先级不同以外,下标表达式array[index]和间接访问表达式*(array + (value))是一样的。原因就如前一篇文章提到的,数组名是指向数组第一个元素的指针常量,所以下标既可以用于数组名,也可以用于指针表达式,但是当下标用于指针表达式的时候,编译器将失去检查下标有效性的能力,因此在程序可维护性和运行效率上还是要多斟酌。
指针有时会比下标更有效率,下标绝对不会比指针更有效率,前提是他们必须被正确的使用。
虽然下标表达式和间接表达是可以是相同的,但是数组和指针并不相等。除非当数组作为形参时,数组和指针才是相等的,因为实际传递的都是指向数组第一个元素的指针的一份拷贝。但是如果对该指针进行间接访问操作并进行修改的话,那么函数将会修改那个对应的标量了,除非对函数参数添加关键字const。
对于数组形参我们可以使用如下原型(它们是相等的):
int strlen(cahr *string); int strlen(char string[]);
除了以上情况以外,如下代码,它们是不相等的:
char *string = "Hello"; char string[] = "Hello" // 等于{"H", "e", "l", "l", "o", 0};
前者是初始化一个字符数组,而后者是一个真正的字符串常量。
数组在声明的时候会分配一些空间用于容纳数组元素,但是声明指针的时候,只会分配用于容纳指针的内存。
在对数组进行初始化的时候,如果初始化的个数少于数组元素的个数,那么数组最后的几个元素将会用缺省值进行初始化(默认值)。
如果数组在初始化的时候长度未给出,那么编译器将使这个数组的长度设置为刚好能容纳初始值列表所有元素的长度。
数组可以用一种很像字符串常量的快速方法进行初始化。
多维数组实际是一维数组的一种特型,因为元素本身也是数组。对于多维数组的初始化我们可以使用如下方式:
int arr[2][3][4] = { { {1, 2, 3, 4}, {2, 3, 4, 5}, {3, 4, 5, 6} }, { {1, 2, 3, 4}, {2, 3, 4, 5}, {3, 4, 5, 6} } }; //或者 int arr[2][3][4] = { { {1}, {2} }, { {1, 2, 3, 4} } }; //或者 int arr[2][3][4] = { 1, 2, 3, 4, 2, 3, 4, 5, 3, 4, 5, 6, 1, 2, 3, 4, 2, 3, 4, 5, 3, 4, 5, 6 };
如上面代码所示,我们可以在初始化的时候,给出所有元素的值,也可以给出部分元素的值,但是对于使用多个{进行初始化以及只是用一个{进行初始化的区别就是,如果我们想使用第三种方式对部分元素进行初始化,那么我们就必须给出前面元素的默认值,如:
int array[2][3][4] = { 0, 0, 0, 0, 0, 0, 0, 0, 3, 4, 5, 6 };
而且在代码可读性方面,使用单个{声明的方式是很难读懂的,我们必须自己一个个的去计算元素所对应的位置。
以上的多维数组我们也可以声明为指针数组。
对于字符串列表我们可以使用矩阵进行存储,也可以以指向字符串常量的指针数组来存储。它们的区别在于,矩阵每行必须与最长字符串的长度一样长,但是它不需要任何指针,而指针数组本身需要占用空间,但是每个指针所指向的字符串所占用的空间就是字符串本身的长度。在使用过程中,如果长度差不多,我们可以使用矩阵来存储,但是如果字符串列表中大多数字符串都差不多,但是唯独有几个特别长或者特别短的情况下,我们则可以选择使用指针数组,相对会紧凑一些,它取决于指针所占用的空间是否小于每个字符串都存储与固定长度的行所浪费的空间,但是实际上差别并不大。