本节的目的是说明这种方法的本质,来为接下来的几个例子打好基础。下面的代码片段声明一个整数指针的数组,为每个元素分配内存,然后把内存的内容初始化为元素的索引值:
int* arr[5];
for(int i=0; i<5; i++) {
arr[i] = (int*)malloc(sizeof(int));
*arr[i] = i;
}
如果把数组打印出来,得到的是数字0到4。我们用arr[i]
引用指针,用*arr[i]
把值赋给指针引用的位置。别被数组表示法搞糊涂了,因为arr
声明为指针数组,arr[i]
返回的是一个地址,当我们用*arr[i]
解引指针时,得到是这个地址的内容。
我们也可以在循环体中使用下面这种等价的指针表示法:
*(arr+i) = (int*)malloc(sizeof(int));
**(arr+i) = i;
这种表示法更难理解,但是理解以后能加强你的C技能。在第二个语句中我们用了两层间接引用,掌握这种表示法将让你和初级C程序员有本质区别。
子表达式(arr+i)
表示数组的第i
个元素的地址,我们需要修改这个地址中的内容,所以用了子表达式*(arr+i)
。在第一条语句中我们将已分配的内存赋给这个位置。对(arr+i)
子表达式做两次解引(如第二条语句所示),会返回所分配内存的位置,然后我们把i
赋给它。下图说明了内存的分配情况。
比如说,arr[1]
位于地址104,表达式(arr+1)
为我们返回104,用*(arr+1)
则让我们得到其内容,在本例中,就是指针504。再用**(arr+1)
解引它就得到了504的内容,就是1。
下表列出了一些示例表达式。从左到右读指针表达式且不要忽略括号,这样会更容易理解其工作方式。
表达式 | 值 |
---|---|
*arr[0] |
0 |
**arr |
0 |
**(arr+1) |
1 |
arr[0][0] |
0 |
arr[3][0] |
3 |
前三个表达式和前面解释的差不多,最后两个则有所不同。用指针的指针表示法能让我们知道正在处理的是指针数组,实际上我们的示例中也用到了。假设arr
的每个元素指向一个长度为1的数组,那么最后两个表达式就能说通了,我们得到的是一个有5个元素的指针数组,这些指针指向一系列有1个元素的数组。
表达式arr[3][0]
引用arr
的第4个元素,然后是这个元素所指向的数组的第1个元素。表达式arr[3][1]
有错误,因为第4个元素所指向的数组只有一个元素。