索引指针
在C/C++中,指针和数组是紧密相连的.正如我们说过的.数组名去掉索引部分就是一个指向数组第一个元素的指针.例如,我们看下面的例子:
char p[10];
下面的写法意义是一样的:
p&p[0]
换言之:
p == &p[0]
这是因为数组的地址就是数组的第一个元素的地址.
正如说过的,数组的名字去掉索引方括号部分则代表一个指针,指向数组的第一个元素.反过来说,指针也可以加上索引部分,仿佛它就是一个数组一样.看下面的例子:
int *p, i[10];p = i;p[5] = 100; /* assign using index */*(p+5) = 100; /* assign using pointer arithmetic */
两个赋值语句都起到了把100赋值给i数组的第六个元素的作用.第一个赋值语句对指针p进行了索引.第二个赋值语句则采用了指针运算的方式.它们的结果是相同的.指针运算将在第五章进行讨论.
类似的概念也适用于二维和多维数组.例如,假定a是一个10*10的整型数组.下面的两个语句是等价的:
a&a[0][0]
另外,数组a中的0,4项可以用两种方式访问:一是用数组索引a[0][4],二是用指针运算的方式*((int*)a+4).类似的,1,2项可以用a[1][2]访问,也可以用*((int*)a+12)访问.综合起来,任何二维数组的项可以用如下方式访问:
a[j][k] 等价于 *((base-type*)a+(j*row-length)+k)
对指向数组的指针进行强制数据类型转换,将其转换为数组的基类型是很必要的,这样才能确保指针算术运算能正确进行.我们常用指针来访问数组,因为指针的算术运算要比数组的索引速度快.一个二维数组也可以减少为使用一个指向一维数组的指针来访问.另外,用单独的指针来访问二维数组的同一个行中的元素是个简易的方式.下面的例子展示了这个技巧.它会显示全局整型数组num的特定行.
int num[10][10];..void pr_row( int j ){ int *p, t;
p = (int*) &num[j][0]; /* get address of first element in row j */ for( t=0; t<10; t++ ) printf( "%d ", *(p+t) );}
可以通过给函数传递行号,行宽度(每一行的元素个数),和数组首地址指针这三个参数来使得这个函数能够变得通用.
void pr_row( int j, int row row_dimension, int *p ){ int t;
p = p + (j * row_dimension);
for( t=0; t<row_dimension; t++ ) printf( "%d ", *(p+t) );}...void f( void ){ int num[10][10];
pr_row( 0, 10, (int*)num ); /* print first row */}
二维以上的数组也可以用类似的方式降低维数访问.例如,三维数组可以看做一个指向二维数组的指针,进一步又可以降为指向一维数组的指针.概括的说,一个n维数组可以降低为一个指向n-1维数组的指针和一个n-1维数组.这个数组可以进一步降低维数.最终可以把n维数组转换成一个指向一维数组的指针.