【C++】指针与数组
本小节时数组与指针的笔记,主要理解下表运算符的作用、数组名何时退化为指针以及不退化的情况、数组指针和首元素指针的区别、数组指针与数组名之间的关系、字符串数组与其他普通数组的区别等。
1 基础概念理解
- 下表运算符[ ]的理解:下标运算符的根本意义应该就是取出某个指针所存储的地址。因此p[n]的含义就是相对于指针向后移动sizeof(typep)*n,而后取出其中的元素。实际上,p[3]等价于*(p+3)。
2 数组名是否退化为指针
int arr[5] = {1,2,3,4,5};//以此为例
- 数组名不退化为指针的情况
sizeof(arr)
- 初始化
int arr[5] = {1,2,3}
- 取地址
&arr
获得的是数组地址 Alignof
- 数组名退化为指针的情况
- 参数传递:
void func(char arr[5], char *p, char arr1[])
函数中三种形式的数组参数形式上不同,但是实际上是等价的 - 二维数组:二维数组char s[10][8]数组首元素是一维数组,因此退化成
&s[0]
指针
- 参数传递:
3 数组指针与数组引用的定义
数组指针:int (\*p)[5]=&arr;
,指针类型为int(*)[5]
数组引用:int (&s)[5]=arr
,引用类型为int(&)[5]
定义的数组是对象数组的时候,要注意是否存在默认构造函数,因为在数组内部进行的是默认初始化。
4 首元素地址(指针)和数组地址(指针)
4.1 两种指针的异同
int arr[5] = {1,2,3,4,5};
int *p1 = &arr[0];//首元素地址
int (*p2)[5] = &arr; //数组地址
p1为指向首元素地址的指针,而p2是指向整个数组地址的指针。其异同之处是,p1和p2存储的值相同,但是p1和p2指针类型不同,前者为int*
类型,后者为int(*)[5]
类型。此异同之处使得:
- (p1+1)和(p2+1)不同
指针是一个变量,其不仅有保存的地址,还有类型。此类型决定了其占用多大空间,其移动一次走多大步长。

- p2[0]实际上等价于arr退化后的指针。此情况就是上述指针退化的第二种情况。
4.2 如何理解int(\*p)[5]=&arr
?
- 对数组名其地址我们可以将p理解为二级指针。角度有二,首先arr在多种情况话会退化为指针,类型为
int*
,说明两者在某种情况下是相通的,&arr
可看作在一级指针的基础上再次取地址,因此p就作为二级指针;其次看此指针的类型为int (*)[5]
已经是二维数组的形式,在int main(int argc, char* argv[])
中,参数argv实际上就是字符串指针数组char&argv[3]={"123","456","789"}
。 p
与[ ]
的关系。p是数组指针,此时并没有退化,但是p[0]就变成了int*
类型,实际上就是arr
退化后的指针类型。p[0][0]=arr[0]
。int arr[] = {1,2,3,4,5}; int *p1 = *arr[0]; //首元素指针,int* int (*p2)[5] = &arr; //数组指针,int(*)[5] int *p3 = p2[0];//首元素指针,int* cout << p4[1] <<endl; //2 cout << arr[1] <<endl; //2
5 字符串数组与普通数组(int)的区别
与其他普通数组相比,字符串数组多了三个地方:
- 结尾存储
\0
作为字符串结尾标识符,因此申请空间常常要多考虑; - 初始化数组时,字符串数组可以直接使用字面量字符串直接初始化,自动在末尾添加
\0
。因此字符串有效字符的长度要小于数组的长度。 - 字符串数组或指针打印,字符串数组或指针能够直接输出字符串,而其他普通数组只能够输出单个元素,指针只能输出指针的内容。
//初始化 char s[5] = "1234";//正常初始化:1,2,3,4,\0 chars1[5] = "12345";//报错 char*p = "asd"; //打印 cout << s <<endl; cout << p <<endl;
总结:
- p[n]的作用类似与*(p+n)
- 数组名在sizeof、初始化、取地址时不退化,在做函数参数、获取二维数组的首元素(一维数组)时退化
- 数组指针的首元素等价于数组名退化后的指针
- 字符串数组与其他数组最主要的区别在于能够直接用字符串初始化