声明
- int *a[4]; //指针数组
指针数组就相当于一次声明了多个指针。数组的每一个元素都是一个指针。
[ ]
的优先级高于*
,表示a是一个数组,元素为int * ,个数为4。
- int (*p)[4]; //数组指针
数组指针就相当于一次声明了一个指针。只不过这个指针指向很特别,是一个数组。
()
的优先级高于[]
,表示p是一个数组,类型是为int [4] ,步长为4。
下标区别:指针数组的下标表示数组的元素个数,数组指针的表示指针的步长
指针数组
#include <stdio.h>
int main(){
int a = 16, b = 932, c = 100;
//定义一个指针数组
int *arr[3] = {&a, &b, &c};//也可以不指定长度,直接写作 int *parr[]
//定义一个指向指针数组的指针
int **parr = arr;
printf("%d, %d, %d\n", *arr[0], *arr[1], *arr[2]);
printf("%d, %d, %d\n", **(parr+0), **(parr+1), **(parr+2));
return 0;
}
特别地,字符数组 str 中存放的是字符串的首地址,不是字符串本身,字符串本身位于其他的内存区域,和字符数组是分开的。
故字符串指针数组可以如下赋值:
#include <stdio.h>
int main(){
char *str[3] = {
"c.biancheng.net",
"C语言中文网",
"C Language"
};
printf("%s\n%s\n%s\n", str[0], str[1], str[2]);
return 0;
}
以下代码等价:
#include <stdio.h>
int main(){
char *str0 = "c.biancheng.net";
char *str1 = "C语言中文网";
char *str2 = "C Language";
char *str[3] = {str0, str1, str2};
printf("%s\n%s\n%s\n", str[0], str[1], str[2]);
return 0;
}
数组指针与二维数组
二维数组在概念上是二维的,有行和列,但在内存中所有的数组元素都是连续排列的,它们之间没有“缝隙”。以下面的二维数组 a 为例
int a[3][4] = { {0, 1, 2, 3}, {4, 5, 6, 7}, {8, 9, 10, 11} };
内存排布如下:
数组首地址如下:定义一个指向 a 的指针变量 p:
int (*p)[4] = a;
对指针进行加法(减法)运算时,它前进(后退)的步长与它指向的数据类型有关,p 指向的数据类型是int [4],故 p 指向的是数组的第一行。
*(p+1)单独使用时表示的是第 1 行数据,放在
- 表达式中:因为使用整行数据没有实际的含义,编译器遇到这种情况都会转换为指向该行第 0 个元素的指针 这里是第 1 行第 0 个元素的地址
- 定义时或者和 sizeof、& 一起使用时: 才表示整行,类似地,一维数组的名字这样使用时表示整个数组。
有以下关系
a+i == p+i
a[i] == p[i] == *(a+i) == *(p+i)
a[i][j] == p[i][j] == *(a[i]+j) == *(p[i]+j) == *(*(a+i)+j) == *(*(p+i)+j)
验证如下【Compile and Execute C++11 Online (GNU GCC v7.1.1)】
#include <stdio.h>
int main(){
int a[3][4] = { {0, 1, 2, 3}, {4, 5, 6, 7}, {8, 9, 10, 11} };
int (*p)[4] = a;
printf("sizeof(p): %d\n", sizeof(p));
printf("sizeof(*p): %d\n", sizeof(*p));
printf("p: %d\t==\ta: %d ?\t%d\t\n", p, a, p == a);
printf("p: %d\t==\ta+1: %d ?\t%d\t\n", p, a+1, p == a+1);
printf("*p: %d\t==\t*a: %d ?\t%d\t\n", *p, *a, *p == *a);
printf("*p: %d\t==\t*a+1: %d ?\t%d\t\n", *p, *a+1, *p == *a+1);
printf("*p: %d\t==\t*(a+1): %d ?\t%d\t\n", *p, *(a+1), *p == *(a+1));
printf("*(p+1): %d\t==\t*(a+1): %d ?\t%d\t\n", *(p+1), *(a+1), *(p+1) == *(a+1));
printf("p[1]: %d\t==\ta[1]: %d ?\t%d\t\n", p[1], a[1], p[1] == a[1]);
printf("*a: %d\n", *a+1);
printf("p[1][2]: %d\n", p[1][2]);
printf("%d\n", *(*p+2));
printf("%d\n", sizeof(p));
printf("%x\n", p);
printf("%d\n", sizeof(a[0][0]));
printf("%d\n", sizeof(a+1));
return 0;
}
输出如下:
sizeof(p): 8
sizeof(*p): 16
p: -1938207696 == a: -1938207696 ? 1
p: -1938207696 == a+1: -1938207680 ? 0
*p: -1938207696 == *a: -1938207696 ? 1
*p: -1938207696 == *a+1: -1938207692 ? 0
*p: -1938207696 == *(a+1): -1938207680 ? 0
*(p+1): -1938207680 == *(a+1): -1938207680 ? 1
p[1]: -1938207680 == a[1]: -1938207680 ? 1
*a: -1938207692
p[1][2]: 6
2
8
8c794c30
4
8
占用内存
int *(p1[5]); //指针数组,可以去掉括号直接写作 int *p1[5];
int (*p2)[5]; //二维数组指针,不能去掉括号
指针数组是数组,占用空间为 单个元素字节数 × 元素个数,p1在32位环境下占4×5 = 20个字节;
数组指针是指针,占用空间为指针占用空间,p2在32位环境下占用4个字节。
参考:
#include <typeinfo>
// #include <stdio.h>
// #include <stdlib.h>
#include <iostream>
using namespace std;
int main()
{
int (*num)[2];
cout << typeid( (num+1)[0] ).name() << endl; // 打印: int
cout << typeid( 8.16 ).name() << endl; // 打印: double
return 0;
}