21.指针和二维数组

21.指针-指针和数组-指针和二维数组


21.1 知识点

指针和二维数组的关系

二维数组在内存中也是连续存储的,因此我们只要利用指针获取到二维数组一开始的位置,就可以通过指针的增减获取到二维数组中的所有信息。

建立关系

指针类型需要和二维数组类型一致

int arr[2][4] = {1, 2, 3, 4, 5, 6, 7, 8};

按元素建立关系

int* p = &arr[0][0];  // 得到的是第一行第一列的元素地址
int* ptr = arr[0];     // 得到的是第一行的地址 = 第一行第一列的元素地址

数组指针按行数组建立关系

  • 利用数组指针,获取二维数组中一行的一维数组起始地址。数组指针是一个指向整个数组的指针,本质上是一个指针,指向一个包含n个元素的数组。

  • 数组指针定义规则:变量类型 (*指针名)[元素个数]

int (*p2)[4] = arr;
  • 数组指针每次使用++-- 偏移是偏移一行的。例如,int类型数组包含四个元素,那么一次偏移为 4x4=16个字节。

利用指针获取二维数组元素

由于二维数组的存储序列也是连续的,因此利用指针增减也可以获取到所有元素。

按元素获取的指针

cout << "******按元素获取的指针********" << endl;
cout << *p << endl;    // 1
cout << *(p + 1) << endl; // 2
cout << *++p << endl;   // 2
cout << *--p << endl;   // 1
cout << *(p += 3) << endl; // 4
cout << *++p << endl;   // 5
cout << *(p + 3) << endl; // 8

注意: 要在范围内访问 0 <= i < 行 * 列 之间,不要越界。

用数组指针获取元素

  • p2是什么?
    类型是:数组指针 int (*)[4]
    指向的内容:指向二维数组中的第一个一维数组
    每次增减 偏移位置为:元素字节数 * 容量
cout << "p2: " << p2 << endl;//数组指针 第一行数组首地址
cout << "p2 + 1: " << p2 + 1 << endl;//数组指针 第二行数组首地址 偏移元素*容量 16个字节
cout << "p2 的类型: " << typeid(p2).name() << endl;   //  int (* __ptr64)[4]
  • *p2是什么?
    类型是:指向一维数组指针 int*
    指向的内容:指向二维数组中的第一个一维数组中的第一个元素
    每次增减 偏移位置为:元素字节数
cout << "*p2: " << *p2 << endl;//指针 指向二维数组中的第一个一维数组中的第一个元素
cout << "*p2 + 1: " << *p2 + 1 << endl;//指针 指向二维数组中的第一个一维数组中的第二个元素 偏移元素的 4个字节
cout << "*p2 的类型: " << typeid(*p2).name() << endl; // int [4] *p2 的解引用操作返回的是数组本身,所以它的类型是 int[4]。

以下是几种获取元素的方法:

对数组指针偏移一个数组长度后去取值
//对数组int (*)[4]指针类型变量 使用*取值 取出来的是类型是int*的指针
cout << "*(p2): " << *(p2) << endl;//指针 第一行数组首地址 也是第以行数组首元素的地址
cout << "*(p2 + 1) : " << *(p2 + 1) << endl;//指针 第二行数组首地址 也是第二行数组首元素的地址
cout << "**(p2 + 1) : " << **(p2 + 1) << endl;//5 取值
对数组指针先偏移一个数组长度后得到指针,再偏移元素个数,再去取值
//(p2 + 1)得到的还是数组指针
//*(p2 + 1)得到的是指针 指向第二行数组首地址 
//在指针的基础上偏移 int偏移一次是4个单位 每次向后拿元素
cout << "*(*(p2 + 1) + 1): " << *(*(p2 + 1) + 1) << endl;//6 
cout << "*(*(p2 + 1) + 2): " << *(*(p2 + 1) + 2) << endl;//7
cout << "*(*(p2 + 1) + 3): " << *(*(p2 + 1) + 3) << endl;//8
对数组指针取值得到指针,再偏移元素个数,再去取值
//一维数组第一个元素地址中存储的值 *p2得到指针 指针偏移x个单位还是指针 *指针得到值
cout << **p2 << endl;//1
cout << *(*p2 + 1) << endl;//2 往后移动元素n个字节数
cout << *(*p2 + 2) << endl;//3
cout << *(*p2 + 3) << endl;//4
cout << *(*p2 + 4) << endl;//5
cout << *(*p2 + 5) << endl;//6
cout << *(*p2 + 6) << endl;//7
cout << *(*p2 + 7) << endl;//8
对数组指针取值得到指针,使用 [x] 得到对应数组的元素
//结合数组指针 利用数组思维去获取元素内容
//(*p2)得到的是指针 指向第一行首元素 传入索引得到值
cout << (*p2)[0] << endl;
cout << (*p2)[1] << endl;//2 往后移动元素n个字节数
cout << (*p2)[2] << endl;//3
cout << (*p2)[3] << endl;//4
//(*(p2 + 1)得到的是指针 指向第二行首元素 传入索引也可以得到值
cout << (*(p2 + 1))[0] << endl;//5
cout << (*(p2 + 1))[1] << endl;//6
cout << (*(p2 + 1))[2] << endl;//7
cout << (*(p2 + 1))[3] << endl;//8

数组当做指针变量使用

cout << arr[0][0] << endl;   // 1
cout << arr[0] << endl;      // 第一个数组的地址

利用行地址来获取元素

先得到行首地址,再通过加减来获取某行某元素。

cout << *arr[0] << endl;      // 1
cout << *p2[0] << endl;       // 1
cout << *(arr[0] + 1) << endl;  // 2
cout << *(p2[0] + 1) << endl;  // 2
cout << *(arr[0] + 2) << endl;  // 3
cout << *(arr[0] + 3) << endl;  // 4
cout << *(arr[0] + 4) << endl;  // 5, 但是最好不要这样,逻辑上看是越界了
cout << *arr[1] << endl;      // 5
cout << *(arr[1] + 1) << endl;  // 6
cout << *(arr[1] + 2) << endl;  // 7
cout << *(arr[1] + 3) << endl;  // 8

利用二维数组名来获取元素

二维数组名可以理解为一个 int (*)[4] 类型的指针。arr和*arr的区别就像p2 和 *p2 的区别。

cout << arr << endl;//第一行数组地址
cout << *arr << endl;//第一行数组的第一个元素地址 其实和arr一样

对于我们来说,需要知道的是,arr + 1 会按行偏移,偏移后得到的地址是当前行的首地址。arr的使用规则,和数组指针p2使用规则是一样的。

//数组指针
cout << arr + 1 << endl;//第二行数组地址
cout << *(arr + 1) << endl;//第二行数组首元素的地址 其实和arr + 1一样
cout << **(arr + 1) << endl;//5
cout << *(*(arr + 1) + 1) << endl;//6
cout << *(*(arr + 1) + 2) << endl;//7
cout << *(*(arr + 1) + 3) << endl;//8

注意: 数组指针与二维数组名有区别,获取数组容量时,二维数组名占用的是实际字节数,而数组指针占用的内存空间是8个字节。

cout << sizeof(p2) << endl;//8 只要是指针都是8字节
cout << sizeof(arr) << endl;//32 4x8

利用指针遍历数组

int array[2][4] = { 1,2,3,4,
                    5,6,7,8 };

//按元素 int指针
int* p3 = &array[0][0];//array[0];

//按行 int数组指针
int(*ptr3)[4] = array;

for (int i = 0; i < sizeof(array) / sizeof(array[0]); i++)
{
    // 外层循环:遍历二维数组的每一行
    // sizeof(array) / sizeof(array[0]) 计算二维数组的行数

    // 列
    for (int j = 0; j < sizeof(array[0]) / sizeof(int); j++)
    {
        // 内层循环:遍历当前行中的每一列
        // sizeof(array[0]) / sizeof(int) 计算每行中的列数

        // 方法 1:直接通过二维数组下标访问
        cout << array[i][j] << endl;
        // 解释:通过 `array[i][j]` 访问二维数组第 i 行、第 j 列的元素

        // 方法 2:通过一维指针 `p3` 访问
        cout << *p3++ << endl;
        // 解释:`p3` 是指向数组首地址的一维指针,`*p3` 取当前指针位置的值,并自增指针(移动到下一个元素)

        // 方法 3:通过指针偏移访问
        cout << *(*(ptr3 + i) + j) << endl;
        // 解释:`ptr3` 是一个指针,指向二维数组的行指针
        //       `*(ptr3 + i)` 取第 i 行的行首指针
        //       `+ j` 是列偏移,`*(...)` 解引用后得到元素值

        // 方法 4:通过二维数组指针 `array` 偏移访问
        cout << *(*(array + i) + j) << endl;
        // 解释:`array` 是二维数组,`array + i` 是第 i 行数组首地址
        //       `+ j` 是列偏移,`*(...)` 解引用后得到元素值

        // 方法 5:通过行指针 `array[i]` 偏移访问
        cout << *(array[i] + j) << endl;
        // 解释:`array[i]` 是指向第 i 行的行首指针
        //       `+ j` 是列偏移,`*(...)` 解引用后得到元素值

        // 方法 6:通过行指针数组 `ptr3[i]` 偏移访问
        cout << *(ptr3[i] + j) << endl;
        // 解释:`ptr3[i]` 是指向第 i 行的行首指针
        //       `+ j` 是列偏移,`*(...)` 解引用后得到元素值
    }
}

输出五次 1234

总结

  • 理解二维数组中,数组指针怎么用,以及array*array 的区别。
    • array => 数组指针变量。类型是类型 (*指针名)[列容量]。指向的是第一行一维数组的首地址(数组为单位去偏移)。
    • *array => 对应类型的指针变量。类型是 类型* 指针名。指向的是第一行一维数组的第一个元素的首地址(元素为单位去偏移)。

21.2 知识点代码

Lesson21_指针_指针和数组_指针和二维数组.cpp

#include <iostream>
using namespace std;
int main()
{
    std::cout << "指针和二维数组\n";

    #pragma region 知识点一 指针和二维数组的关系

    //二维数组在内存中也是连续存储的
    //因此我们只要利用指针获取到二维数组一开始的位置
    //就可以通过指针的 增减 获取到二维数组中的所有信息

    #pragma endregion

    #pragma region 知识点二 建立关系

    //关键点:
    //1.指针类型需要和二维数组类型一致
    int arr[2][4] = { 1,2,3,4,
                      5,6,7,8 };

    //2.按元素建立关系
    int* p = &arr[0][0];//得到的是第一行第一列的元素地址
    int* ptr = arr[0];//得到的是第一行的地址 = 第一行第一列的元素地址

    //3.数组指针 按行数组建立关系
    //利用数组指针,获取二维数组中一行的一维数组起始地址
    //数组指针是一个指向整个数组的指针
    //本质上是一个指针,指向一个包含n个元素的数组
    //数组指针定义规则:变量类型 (*指针名)[元素个数]
    //          
    //int (*p2)[4] 表示指向包含4个int元素的一维数组的指针
    //int:数组中元素的类型
    //*p:指针变量
    //[4]:表示这个指针指向的数组包含4个int元素
    //指向二维数组中第一个一维数组的指针
    int(*p2)[4] = arr;
    //数组指针每次使用++ -- 偏移是偏移一行的 
    //例如int类型数组包含四个元素 那么一次偏移4x4=16个字节

    #pragma endregion

    #pragma region 知识点三 利用指针获取二维数组元素

    //由于二维数组的存储序列也是连续的
    //因此利用指针增减也可以获取到所有元素

    //1.按元素获取的指针
    cout << "******按元素获取的指针********" << endl;
    cout << *p << endl;//1
    cout << *(p + 1) << endl;//2
    cout << *++p << endl;//2
    cout << *--p << endl;//1
    cout << *(p += 3) << endl;//4
    cout << *++p << endl;//5
    cout << *(p + 3) << endl;//8
    //注意:
    //要在范围内访问0<= i < 行*列 之间
    //不要越界,不要越界,不要越界

    //2.用数组指针获取元素
    cout << "******用数组指针获取元素********" << endl;

    // p2是什么?
    // 类型是:数组指针 int (*)[4]
    // 指向的内容:指向二维数组中的第一个一维数组
    // 每次增减 偏移位置为:元素字节数 * 容量
    cout << "p2: " << p2 << endl;//数组指针 第一行数组首地址
    cout << "p2 + 1: " << p2 + 1 << endl;//数组指针 第二行数组首地址 偏移元素*容量 16个字节
    cout << "p2 的类型: " << typeid(p2).name() << endl;   //  int (* __ptr64)[4]

    // *p2是什么?
    // 类型是:指向一维数组指针 int*
    // 指向的内容:指向二维数组中的第一个一维数组中的第一个元素
    // 每次增减 偏移位置为:元素字节数
    cout << "*p2: " << *p2 << endl;//指针 指向二维数组中的第一个一维数组中的第一个元素
    cout << "*p2 + 1: " << *p2 + 1 << endl;//指针 指向二维数组中的第一个一维数组中的第二个元素 偏移元素的 4个字节
    cout << "*p2 的类型: " << typeid(*p2).name() << endl; // int [4] *p2 的解引用操作返回的是数组本身,所以它的类型是 int[4]。


    //以下是几种获取元素方法


    //对数组指针 偏移一个数组长度后 去取值 
    //对数组int (*)[4]指针类型变量 使用*取值 取出来的是类型是int*的指针
    cout << "*(p2): " << *(p2) << endl;//指针 第一行数组首地址 也是第以行数组首元素的地址
    cout << "*(p2 + 1) : " << *(p2 + 1) << endl;//指针 第二行数组首地址 也是第二行数组首元素的地址
    cout << "**(p2 + 1) : " << **(p2 + 1) << endl;//5 取值


    //对数组指针 先偏移一个数组长度后 得到指针 再偏移元素个数 再去取值 
    //(p2 + 1)得到的还是数组指针
    //*(p2 + 1)得到的是指针 指向第二行数组首地址 
    //在指针的基础上偏移 int偏移一次是4个单位 每次向后拿元素
    cout << "*(*(p2 + 1) + 1): " << *(*(p2 + 1) + 1) << endl;//6 
    cout << "*(*(p2 + 1) + 2): " << *(*(p2 + 1) + 2) << endl;//7
    cout << "*(*(p2 + 1) + 3): " << *(*(p2 + 1) + 3) << endl;//8


    //对数组指针取值得到指针 再偏移元素个数 再去取值 
    //一维数组第一个元素地址中存储的值 *p2得到指针 指针偏移x个单位还是指针 *指针得到值
    cout << **p2 << endl;//1
    cout << *(*p2 + 1) << endl;//2 往后移动元素n个字节数
    cout << *(*p2 + 2) << endl;//3
    cout << *(*p2 + 3) << endl;//4
    cout << *(*p2 + 4) << endl;//5
    cout << *(*p2 + 5) << endl;//6
    cout << *(*p2 + 6) << endl;//7
    cout << *(*p2 + 7) << endl;//8


    //对数组指针取值得到指针 使用[x] 得到对应数组的元素
    //结合数组指针 利用数组思维去获取元素内容
    //(*p2)得到的是指针 指向第一行首元素 传入索引得到值
    cout << (*p2)[0] << endl;
    cout << (*p2)[1] << endl;//2 往后移动元素n个字节数
    cout << (*p2)[2] << endl;//3
    cout << (*p2)[3] << endl;//4
    //(*(p2 + 1)得到的是指针 指向第二行首元素 传入索引也可以得到值
    cout << (*(p2 + 1))[0] << endl;//5
    cout << (*(p2 + 1))[1] << endl;//6
    cout << (*(p2 + 1))[2] << endl;//7
    cout << (*(p2 + 1))[3] << endl;//8

    #pragma endregion

    #pragma region 知识点四 数组当做指针变量使用

    cout << "******数组当做指针变量使用*******" << endl;
    cout << arr[0][0] << endl;//1
    cout << arr[0] << endl;//第一个数组的地址

    //1.利用行地址来获取元素
    cout << "******利用行地址来获取元素*******" << endl;
    //  先得到行首地址,在通过加减来获取某行某元素
    cout << *arr[0] << endl;//1
    cout << *p2[0] << endl;//1
    cout << *(arr[0] + 1) << endl;//2
    cout << *(p2[0] + 1) << endl;//2
    cout << *(arr[0] + 2) << endl;//3
    cout << *(arr[0] + 3) << endl;//4
    cout << *(arr[0] + 4) << endl;//5 但是最好不要这样 逻辑上看是越界了
    cout << *arr[1] << endl;//5
    cout << *(arr[1] + 1) << endl;//6
    cout << *(arr[1] + 2) << endl;//7
    cout << *(arr[1] + 3) << endl;//8

    //2.利用二维数组名来获取元素
    cout << "******利用二维数组名来获取元素*******" << endl;
    //关键知识:
    // 二维数组名 可以理解为一个 int (*)[4] 类型的指针
    //arr和*arr的区别
    //就像前面讲解的 p2 和 *p2 的区别
    cout << arr << endl;//第一行数组地址
    cout << *arr << endl;//第一行数组的第一个元素地址 其实和arr一样

    //对于我们来说,需要知道的是
    //arr + 1 会按行偏移
    //偏移后得到的地址是当前行的首地址
    //arr的使用规则,和数组指针p2使用规则是一样的
    //数组指针
    cout << arr + 1 << endl;//第二行数组地址
    cout << *(arr + 1) << endl;//第二行数组首元素的地址 其实和arr + 1一样
    cout << **(arr + 1) << endl;//5
    cout << *(*(arr + 1) + 1) << endl;//6
    cout << *(*(arr + 1) + 2) << endl;//7
    cout << *(*(arr + 1) + 3) << endl;//8

    //二维数组名和数组指针有什么区别?
    //他们通过sizeof获取容量时
    //二维数组名得到的是实实在在的这个二维数组占用了多少个字节
    //数组指针(只要是指针)占用的内存空间是8个字节
    cout << sizeof(p2) << endl;//8 只要是指针都是8字节
    cout << sizeof(arr) << endl;//32 4x8

    #pragma endregion

    #pragma region 知识点五 利用指针遍历数组

    cout << "遍历二维数组" << endl;
    int array[2][4] = { 1,2,3,4,
                        5,6,7,8 };
    //按元素 int指针
    int* p3 = &array[0][0];//array[0];
    //按行 int数组指针
    int(*ptr3)[4] = array;
    for (int i = 0; i < sizeof(array) / sizeof(array[0]); i++)
    {
        // 外层循环:遍历二维数组的每一行
        // sizeof(array) / sizeof(array[0]) 计算二维数组的行数

        // 列
        for (int j = 0; j < sizeof(array[0]) / sizeof(int); j++)
        {
            // 内层循环:遍历当前行中的每一列
            // sizeof(array[0]) / sizeof(int) 计算每行中的列数

            // 方法 1:直接通过二维数组下标访问
            cout << array[i][j] << endl;
            // 解释:通过 `array[i][j]` 访问二维数组第 i 行、第 j 列的元素

            // 方法 2:通过一维指针 `p3` 访问
            cout << *p3++ << endl;
            // 解释:`p3` 是指向数组首地址的一维指针,`*p3` 取当前指针位置的值,并自增指针(移动到下一个元素)

            // 方法 3:通过指针偏移访问
            cout << *(*(ptr3 + i) + j) << endl;
            // 解释:`ptr3` 是一个指针,指向二维数组的行指针
            //       `*(ptr3 + i)` 取第 i 行的行首指针
            //       `+ j` 是列偏移,`*(...)` 解引用后得到元素值

            // 方法 4:通过二维数组指针 `array` 偏移访问
            cout << *(*(array + i) + j) << endl;
            // 解释:`array` 是二维数组,`array + i` 是第 i 行数组首地址
            //       `+ j` 是列偏移,`*(...)` 解引用后得到元素值

            // 方法 5:通过行指针 `array[i]` 偏移访问
            cout << *(array[i] + j) << endl;
            // 解释:`array[i]` 是指向第 i 行的行首指针
            //       `+ j` 是列偏移,`*(...)` 解引用后得到元素值

            // 方法 6:通过行指针数组 `ptr3[i]` 偏移访问
            cout << *(ptr3[i] + j) << endl;
            // 解释:`ptr3[i]` 是指向第 i 行的行首指针
            //       `+ j` 是列偏移,`*(...)` 解引用后得到元素值
        }
    }

    //输出5次1234

    #pragma endregion

    #pragma region 总结

    //理解数组指针怎么用
    //array和*array
    //array => 数组指针变量 指向的是第一行一维数组的首地址(数组为单位去偏移)
    //         类型 (*指针名)[列容量]
    //*array => 对应类型的指针变量 指向的是第一行一维数组的第一个元素的首地址(元素为单位去偏移)
    //         类型* 指针名

    #pragma endregion
}

21.3 练习题

有一个二维数组array,请说明array、array[0]、&array[0][0]的作用和区别

  • 假设二维数组类型是 int
  1. array

    • 作用:是获取到二维数组的首地址,二维数组中第一个一维数组的首地址。
    • 偏移规则:使用它进行加减偏移时,是以元素所占字节数*列数来决定偏移多少的。
    • 偏移单元:它的偏移最小单元是一个一维数组的容量。
    • 偏移方向:因此它是按照行去偏移的。
    • 本质:是一个数组指针 int (*)[列数]
  2. array[0]

    • 作用:是获取到二维数组中第一行的一维数组首地址。
    • 偏移规则:使用它进行加减偏移时,是以元素所占字节数进行偏移的。
    • 偏移单元:它的偏移最小单元是一个int(具体是什么类型由二维数组的类型决定)。
    • 偏移方向:因此它是按照元素去偏移的。
    • 本质:是一个int指针 int*
  3. &array[0][0]

    • 作用:是获取二维数组中第一行第一列元素的地址。
    • 偏移规则:使用它进行加减偏移时,是以元素所占字节数进行偏移的。
    • 偏移单元:它的偏移最小单元是一个int(具体是什么类型由二维数组的类型决定)。
    • 偏移方向:因此它是按照元素去偏移的。
    • 本质:是一个int指针 int*

有一个二维数组array,请说明一下表达式代表什么

&array[n][m]、array[n] + m、*(array + n) + m、代表什么?
以及
array[n][m]、*(array[n] + m)、*(*(array + n) + m) 又代表什么?

int array[2][3] = { 1, 2, 3, 4, 5, 6 };

// &array[n][m] => 第n行第m列元素的地址
// array[n] + m => 第n行一维数组地址,在该行的首地址基础上偏移m个元素单位 = 第n行第m列元素的地址
// *(array + n) + m => 先偏移n行地址,然后取出第n行一维数组的地址,在该行的首地址基础上偏移m个元素单位 = 第n行m列元素的地址
cout << &array[1][1] << endl;  // 00000024504FF8A8
cout << array[1] + 1 << endl;  // 00000024504FF8A8
cout << *(array + 1) + 1 << endl;  // 00000024504FF8A8

// array[n][m] => 第n行第m列元素的值
// *(array[n] + m) => 第n行第m列元素的值
// *(*(array + n) + m) => 第n行第m列元素的值
cout << array[1][1] << endl;  // 5
cout << *(array[1] + 1) << endl;  // 5
cout << *(*(array + 1) + 1) << endl;  // 5

声明一个 2x3 的二维数组 arr 并初始化为 123456。编写代码输出每个元素的值,使用指针访问二维数组中的每个元素。注意:禁止使用下标运算符 []

// int* p = &array[0][0];
// int (*ptr)[3] = array;

for (int i = 0; i < sizeof(array) / sizeof(array[0]); i++)
{
    // 外层循环:用于遍历二维数组的行
    // sizeof(array) / sizeof(array[0]) 计算二维数组的行数
    // sizeof(array): 获取整个二维数组的总字节大小
    // sizeof(array[0]): 获取二维数组中一行的字节大小
    // 整个数组大小 / 每行大小 = 行数

    for (int j = 0; j < sizeof(array[0]) / sizeof(int); j++)
    {
        // 内层循环:用于遍历当前行的列
        // sizeof(array[0]) / sizeof(int): 计算当前行的列数
        // sizeof(array[0]): 获取二维数组中第一行的字节大小
        // sizeof(int): 一个元素的字节大小
        // 第一行字节大小 / 单个元素大小 = 列数

        cout << *(*(array + i) + j) << endl;
        // **访问二维数组中的元素**
        // *(array + i): 计算第 i 行的地址
        // *(array + i) 相当于 array[i],是第 i 行的首地址
        // *(array + i) + j: 在第 i 行的首地址基础上,偏移 j 个元素
        // *(*(array + i) + j): 访问偏移后位置的值,相当于 array[i][j]
    }
}

21.4 练习题代码

Lesson21_练习题.cpp

#include <iostream>
using namespace std;
int main()
{
    std::cout << "指针和二维数组 练习题\n";

    #pragma region 练习题一

    /*有一个二维数组array
    请说明array、array[0]、&array[0][0]的作用和区别*/

    //假设 二维数组类型是 int
    //array
    //作用:是获取到二维数组的首地址,二维数组中第一个一维数组的首地址
    //     使用它进行 加减 偏移时  是以 元素所占字节数*列数 来决定偏移多少的
    //     它的偏移最小单元 是一个一维数组的容量
    //     因此 它是按照行去偏移的
    //本质:是一个数组指针 int (*)[列数] 

    //array[0]
    //作用:是获取到二维数组中第一行的一维数组首地址
    //     使用它进行 加减 偏移时 是以 元素所占字节数进行偏移的 
    //     它的偏移最小单元 是一个int(具体是什么类型 由二维数组的类型决定)
    //     因此 它是按照元素去偏移的
    //本质:是一个int指针 int*

    //&array[0][0]
    //作用:是获取二维数组中第一行第一列元素的地址
    //     使用它进行 加减 偏移时 是以 元素所占字节数进行偏移的 
    //     它的偏移最小单元 是一个int(具体是什么类型 由二维数组的类型决定)
    //     因此 它是按照元素去偏移的
    //本质:是一个int指针 int*

    #pragma endregion

    #pragma region 练习题二

    /*有一个二维数组array
    请说明
    &array[n][m]、
    array[n] + m、
    *(array + n) + m、
    代表什么?
    以及
    array[n][m]、
    *(array[n] + m)、
    *(*(array + n) + m)
    又代表什么*/


    int array[2][3] = { 1,2,3,
                        4,5,6 };
    // &array[n][m] =>  第n行第m列元素的地址
    // array[n] + m、=> 第n行一维数组地址, 在该行的首地址基础上偏移m个元素单位 = n行m列元素的地址
    // *(array + n) + m、先偏移n行地址,然后取出第n行一维数组的地址,在该行的首地址基础上偏移m个元素单位
    //                   =  第n行m列元素的地址
    cout << &array[1][1] << endl;//00000024504FF8A8
    cout << array[1] + 1 << endl;//00000024504FF8A8
    cout << *(array + 1) + 1 << endl;//00000024504FF8A8

    //array[n][m]、=> 第n行第m列元素的值
    //*(array[n] + m)、=> 第n行第m列元素的值
    //*(*(array + n) + m) => 第n行第m列元素的值
    cout << array[1][1] << endl;//5
    cout << *(array[1] + 1) << endl;//5
    cout << *(*(array + 1) + 1) << endl;//5

    #pragma endregion

    #pragma region 练习题三

    //声明一个 2x3 的二维数组 arr 并初始化为{ {1, 2, 3}, {4, 5, 6} }。
    //编写代码输出每个元素的值,要求使用指针访问二维数组中的每个元素
    //(禁止使用下标运算符[])
    //int* p = &array[0][0];
    //int (*ptr)[3] = array;

    for (int i = 0; i < sizeof(array) / sizeof(array[0]); i++)
    {
        // 外层循环:用于遍历二维数组的行
        // sizeof(array) / sizeof(array[0]) 计算二维数组的行数
        // sizeof(array): 获取整个二维数组的总字节大小
        // sizeof(array[0]): 获取二维数组中一行的字节大小
        // 整个数组大小 / 每行大小 = 行数

        for (int j = 0; j < sizeof(array[0]) / sizeof(int); j++)
        {
            // 内层循环:用于遍历当前行的列
            // sizeof(array[0]) / sizeof(int): 计算当前行的列数
            // sizeof(array[0]): 获取二维数组中第一行的字节大小
            // sizeof(int): 一个元素的字节大小
            // 第一行字节大小 / 单个元素大小 = 列数

            cout << *(*(array + i) + j) << endl;
            // **访问二维数组中的元素**
            // *(array + i): 计算第 i 行的地址
            // *(array + i) 相当于 array[i],是第 i 行的首地址
            // *(array + i) + j: 在第 i 行的首地址基础上,偏移 j 个元素
            // *(*(array + i) + j): 访问偏移后位置的值,相当于 array[i][j]
        }
    }


    #pragma endregion

}


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 785293209@qq.com

×

喜欢就点赞,疼爱就打赏