第十章 再论指针
10.1 多维数组的内存布局
char pea[4][6]的内存布局。单个元素的存储和引用是以线性形式排列在内存中的。
首先找到pea[i]的位置,然后根据偏移量[j]取得字符。因此,pea[i][j]将被编译器解析为:*( *(pea + i) + j)。
10.2 指针数组就是Iliffe向量
可以通过声明一个一维指针数组,其中每个指针指向一个字符串来取得类似二维字符数组的效果。这样的声明如下:
char *pea[4];
用于实现多维数组的指针数组有多种名字,如“Iliffe”向量、“display”或者“dope”向量。
这种数组必须用指向为字符串而分配的内存的指针进行初始化,可以在编译时用一个常量初始值,也可以在运行时用下面这样的代码进行初始化。
for ( j = 0; j <= 4; j++) { pea[j] = malloc(6); }
另一种方法是一次性地用malloc分配整个x×y个数据的数组,
malloc( row_size * column*size * sizeof(char));
然后,使用一个循环,用指针指向这块内存的各个区域。整个素组保证能够存储在连续的内存中,即按C用于分配静态数组的次序。它减少了malloc的维护性开销,但缺点是当处处理完一个字符串时无法单独将其释放。
当看见squash[i][j]这样的形式时,并不知道它是怎样被声明的。有可能是以下几种
int squash[23][12]; /*int类型的二维数组*/
int *squash[23]; /*int类型指针的Iliffe向量*/
int **squash; /*int类型的指针的指针*/
int (*squash)[12]; /*类型为int数组(长度为12)的指针*/
数组的数组 与 字符串指针数组 的区别
10.3 在锯齿状数组上使用指针
创建一个锯齿状数组
char *turnip[UMPTEEN];
char my_string[] = “your message here”;
/*共享字符串*/
turnip[i]= &my_string[0];
/*拷贝字符串*/
turnip[j] = malloc (strlen (my_string) + 1);
strcpy(turnip[j], my_string);
只要有可能,尽量不要选择拷贝整个字符串的方法。如果需要从两个不同的数据结构访问它,拷贝一个指针比拷贝整个数组快得多,空间也节省很多。另一个可能影响性能的因素是Iliffe向量可能会使字符串分配于内存中不同的页面中。
“数组名被改写成一个指针参数”规则并不是递归定义的。数组的数组会被改写为“数组的指针”,而不是“指针的指针”。
my_function_1( int fruit[2][3][5]) {;}
my_function_2( int fruit[][3][5]) {;}
my_function_3( int (*fruit)[3][5]) {;}
int apricot[2][3][5];
my_function_1(apricot);
my_function_2(apricot);
my_function_3(apricot);
int (*p)[3][5]=apricot;
my_function_1(p);
my_function_2(p);
my_function_3(p);
int (*q)[2]][3][5] = &apricot;
my_function_1(*q);
my_function_2(*q);
my_function_3(*q);
10.4 向参数传递一个一维数组
10.5 使用指针向函数传递一个多维数组
能够采取的最好方法是放弃传递一个二维数组,把array[x][y]这样的形式改写为一个一维数组array[x+1],它的元素类型是指向array[y]的指针。在数组最后的那个元素array[x+1]里存储一个NULL指针,提示数组的结束。
实参限制为除最左边一维外所有维都必须与形参匹配的数组。
my_function ( int my_array[10][20]);
它迫使函数只处理10行20列的int型数组。
my_function ( int my_array[][20]);或者
my_function ( int (*my_array)[20]);/* (*my_array)周围的括号是绝对必须的,这样可以确保它被翻译为一个指向(20个元素的int数组)的指针,而不是一个20个int指针的数组*/
每行必须是20个整数的长度。
Iliffe向量这种数据结构的美感在于:它允许任意的字符串指针数组,但必须是指针数组,而且必须是指向字符串的指针数组。这是因为字符串和指针都有一个显式的越界值(分别为NUL和NULL),可以作为结束标记。
10.6 使用指针从函数返回一个数组
严格来说,无法直接从函数返回一个数组,但是,可以让函数返回一个指向任何数据结构的指针,当然也可以是一个指向数组的指针。
int ( *paf())[20];
paf是一个函数,它返回一个指向20个int元素的数组的指针。
10.7 使用指针创建和使用动态数组
const int limit= 10;
charplum[limit];/*错误,const int不能被当做一个整型常量表达式*/