int a[10]; // array of int of size 10, aka int [10]
int * pa; // pointer-to-int
pa = a; // same as: pa = &a[0]
在大多数语境下,C和C++把数组名解读为数组首元素的地址,所以a
和&a[0]
都等价于数组首元素地址。
1. 数组名转化为指针
数组名和指针的一个区别是:指针是变量,pa = a
和pa++
是合法的;然而数组名不是变量,而是常量constant,a = pa
和a++
是非法的。当数组名传入函数时,传入的实际上是数组首元素的地址,所以数组名参数是指针,即包含地址的变量。数组名转化为指针后,类型也由int [10]
即array of int
转变为pointer-to-int
,转变前后sizeof
函数返回不同数值(见如下代码示例),即为二者之间的第二个不同点:对数组名执行sizeof
运算得到的是数组的大小,而对指针执行sizeof
运算得到的是指针变量的大小。
#include <stdio.h>
void func(int a[]); // function prototype
int main(int argc, char const *argv[]) {
int a[10]; // array of int of size 10
int * pa; // pointer-to-int
pa = a;
printf("size of an array : %lu\n", sizeof(a));
printf("size of a pointer: %lu\n", sizeof(pa));
printf("Enter a function...\n");
func(a);
return 0;
}
void func(int *a) {
printf("size of a pointer: %lu\n", sizeof(a));
}
输出
size of an array : 40
size of a pointer: 8
Enter a function...
size of a pointer: 8
作为形参,int a[]
和int *a
是等价的,后者明确说明变量是一个指针。
2. 数组下标访问与指针访问
数组下标表达式a[i]
和指针加偏移*(a + i)
表达式是等价的,指针版本的通常更快。在评估a[i]
时,C和C++立即将其转化为*(a + i)
。a[i]
的意思是从指针a
所指位置开始,向后移动i
个位置,将该位置元素读出。
3. 数组地址与数组首元素地址
虽然通常将数组名解读为数组首元素地址,但是对数组名执行地址运算&
得到的是整个数组的地址1(见以下代码示例)。
#include <stdio.h>
int main(int argc, char const *argv[]) {
int a[10]; // array of int of size 10, aka int [10]
int * pa; // pointer-to-int
pa = a; // same as: pa = &a[0]
printf("size of int: %lu\n", sizeof(int));
printf("Address of the first element of an array a or &a[0]: %p\n", a);
printf("Address of an array &a : %p\n", &a);
printf(" a + 1: %p\n", a + 1);
printf("&a + 1: %p\n", &a + 1);
return 0;
}
输出
size of int: 4
Address of the first element of an array a or &a[0]: 0x7ffeeb62b9b0
Address of an array &a : 0x7ffeeb62b9b0
a + 1: 0x7ffeeb62b9b4
&a + 1: 0x7ffeeb62b9d8
数字上二者是相同的,但是概念上,a
或者&a[0]
是4B大小内存块的地址,而&a
是40B大小内存块的地址。所以,表达式a + 1
将地址数值加4,表达式&a + 1
将地址数值加40。换句话说,a
或者&a[0]
的类型是pointer-to-int
或int *
,而&a
的类型是pointer-to-array-of-10-int
或int (*) [10]
,这种类型指针的声明和初始化举例如下:
// operator [] has higher precedence than operator *
int (*pa1)[10]; // pa1 pointer-to-int[10]
int *pa2[10]; // pa2 pointer-to-int*
typedef int * pint;
pint pa3[10]; // same as pa2
C++ Primer Plus 6th Edition by Stephen Prata ↩︎