C++中数组真的存在吗 🤔?
深入理解C++二维数组
提问:定义一个3 * 3的数组arr,值分别为1~9,问arr[0][5]的值为多少?
首先定义一个二维数组,然后获取其地址:
int arr[3][3] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
std::cout << "arr[" << i << "][" << j << "] = " << arr[i][j] << ", address = " << &arr[i][j] << std::endl;
}
}
通过打印地址发现每个元素地址之间差4,也就是一个int的长度(一般情况下int型变量为4个字节),而且地址也是连续的,说明申请了一个二维数组,然后申请了一段连续的地址空间来存放这些数据。
然后我们打印一下arr、arr[0]、arr[0][0]的地址:
std::cout << "Address of arr: " << &arr << std::endl;
std::cout << "Address of arr[0]: " << &arr[0] << std::endl;
std::cout << "Address of arr[0][0]: " << &arr[0][0] << std::endl;
可以看出,三者地址是一样的,这说明三者都指向数组起始地址,变量名arr
也就是数组的起始地址,那么arr是什么数据类型呢?
打印一下arr、arr + 1、 arr + 2、arr[0]、arr[1]、arr[2]的地址:
// 打印arr的地址
std::cout << "Address of arr: " << arr << std::endl;
// 打印arr + 1的地址
std::cout << "Address of arr + 1: " << arr + 1 << std::endl;
// 打印arr + 2的地址
std::cout << "Address of arr + 2: " << arr + 2 << std::endl;
// 打印arr[0]的地址
std::cout << "Address of arr[0]: " << arr[0] << std::endl;
// 打印arr[1]的地址
std::cout << "Address of arr[1]: " << arr[1] << std::endl;
// 打印arr[2]的地址
std::cout << "Address of arr[2]: " << arr[2] << std::endl;
显而易见,arr + n 等价于 arr[n],arr[n]是指针类型,那么arr就是比arr[n]多一维的维指针
再来看一下arr[0][0]、arr[1][0]、arr[2][0]的地址和值(前面已经打印出来):
// 打印arr[0][0]、arr[1][0]、arr[2][0]的地址和值
std::cout << "Address of arr[0][0]: " << &arr[0][0] << ", value = " << arr[0][0] << std::endl;
std::cout << "Address of arr[1][0]: " << &arr[1][0] << ", value = " << arr[1][0] << std::endl;
std::cout << "Address of arr[2][0]: " << &arr[2][0] << ", value = " << arr[2][0] << std::endl;
可以看到和上述arr[n]地址一样,表示的每一行第一列的值,显而易见arr[n]指向的就是每行首元素的地址,也就是一维指针,那么arr就是二维指针,来验证一下:
int *p = a; // 不通过
实验发现报错,继续看
int* p = *arr;
std::cout << "Address of p: " << p << ", Address of arr: " << arr << std::endl;
std::cout << "the value of p is: " << p << std::endl;
std::cout << "the value of *p is: " << *p << std::endl;
std::cout << "the value of p+1 is: " << p+1 << std::endl;
std::cout << "the value of *(p+1) is: " << *(p+1) << std::endl;
std::cout << "a[1][1] inferred from p : " << *(p+1*3+1) << std::endl;
对a解引用后确实是一个地址,所以可以定义指针,并且可以用加偏移量的方式得到a[1][1]
对于二维数组arr[i][j],a[m][n]表示其中的一个值:
- arr[m][n] == *(*(arr + m) + n) == *(*arr + m * i + j)
总的来说数组的本质还是由指针封装起来的数据类型,所以从根本上来说可以从地址上解决,遇到一些奇奇怪怪的问题也可以由地址来解决,比如本文的问题:
另外,数组可以越界,这是C++所决定的,想要不越界只能人为的去限制