28.指针数组

28.指针-指针数组


28.1 知识点

知识回顾:数组指针

数组指针是我们在学习指针和数组中,特别是二维数组相关知识时学习的重要概念。数组指针是一个指向整个数组的指针,其本质上是一个指针,指向一个包含 n 个元素的数组。

数组指针的定义规则

  • 定义语法: 变量类型 (*指针名)[元素个数]
    例如:int (*p2)[4] 表示一个指针,指向包含 4 个 int 元素的一维数组。

示例代码

// 定义二维数组
int arr[3][4] = { 1,2,3,4,
                    5,6,7,8,
                    9,10,11,12 };

// 数组指针定义:指向包含4个整数的一维数组
int(*p)[4] = arr;


// 打印数组指针

// 打印数组指针 p 的地址和 p[0] 的地址
cout << "p: " << p << endl;        // 打印p的地址,即指向的数组的起始地址
// 输出: p: 000000F33ACFF5E8
cout << "p[0]: " << p[0] << endl;  // 打印p[0],即第一行数组的地址(arr[0]的地址)
// 输出: p[0]: 000000F33ACFF5E8

// 打印 p+1 和 p[1],它们指向的是第二行数组的地址
cout << "p+1: " << p + 1 << endl;  // p+1:指向 arr[1](第二行数组)的地址
// 输出: p+1: 000000F33ACFF5F8
cout << "p[1]: " << p[1] << endl;  // p[1]:指向 arr[1](第二行数组)的地址
// 输出: p[1]: 000000F33ACFF5F8

// 打印 p+2 和 p[2],它们指向的是第三行数组的地址
cout << "p+2: " << p + 2 << endl;  // p+2:指向 arr[2](第三行数组)的地址
// 输出: p+2: 000000F33ACFF608
cout << "p[2]: " << p[2] << endl;  // p[2]:指向 arr[2](第三行数组)的地址
// 输出: p[2]: 000000F33ACFF608



// 打印结解引用数组指针 (普通指针)

// 解引用数组指针 p
cout << "*p: " << *p << endl;  // *p:解引用数组指针,访问arr[0](第一行数组)的地址
// 输出: *p: 000000F33ACFF5E8

// 解引用 p+1 和 p+2
cout << "*(p+1): " << *(p + 1) << endl;  // 解引用p+1,访问arr[1](第二行数组)的地址
// 输出: *(p+1): 000000F33ACFF5F8
cout << "*(p+2): " << *(p + 2) << endl;  // 解引用p+2,访问arr[2](第三行数组)的地址
// 输出: *(p+2): 000000F33ACFF608


//访问数组元素

// 解引用数组指针并访问元素
cout << "(*p)[1]: " << (*p)[1] << endl;  // 解引用数组指针后,访问第一行数组中的第二个元素(arr[0][1]),输出 2
// 输出: (*p)[1]: 2

// 解引用并偏移后的结果
cout << "*((*p) + 1): " << *((*p) + 1) << endl;  // 解引用数组指针并进行偏移,访问arr[0][1],即值为 2
// 输出: *((*p) + 1): 2

// 访问第二行第三列的元素
cout << "*(*(p + 1) + 2): " << *(*(p + 1) + 2) << endl;  // 访问arr[1][2],输出 7
// 输出: *(*(p + 1) + 2): 7

// 访问第三行第四列的元素
cout << "*(*(p + 2) + 3): " << *(*(p + 2) + 3) << endl;  // 访问arr[2][3],输出 12
// 输出: *(*(p + 2) + 3): 12

指针数组基本概念

指针数组是由多个指针组成的数组,每个指针可以存储一个地址,指向不同的元素。

定义规则

  • 语法: 变量类型* 数组名[数组长度];
  • 要点:
    • 指针数组中的每个元素存储的是地址。
    • 需要通过解引用操作(*)获取存储地址中的值。

示例代码

int* p2[4];  // 定义一个指针数组,包含4个指针元素
int a = 10;   // 定义一个整数变量 a 并赋值为 10
p2[0] = &a;   // 将 p2[0] 指向 a 的地址

// 打印指针数组中第一个元素(存储的是 a 的地址)
cout << "p2[0](地址): " << p2[0] << endl;  // 输出:a 的地址
// 通过解引用 p2[0] 获取存储地址的值,即 a 的值
cout << "p2[0](值): " << *p2[0] << endl;    // 输出:10(a 的值)

指针数组的使用

定义和操作

// 声明多个整型变量
int b = 11, c = 12;

// 定义一个指针数组,p3 存储了 a, b, c 的地址
int* p3[] = { &a, &b, &c };

// 打印指针数组中每个元素存储的地址
cout << "p3[0](地址): " << p3[0] << endl;  // 输出:a 的地址
cout << "p3[1](地址): " << p3[1] << endl;  // 输出:b 的地址
cout << "p3[2](地址): " << p3[2] << endl;  // 输出:c 的地址

// 打印指针数组中每个元素存储的地址所指向的值
cout << "p3[0](值): " << *p3[0] << endl;  // 输出:10
cout << "p3[1](值): " << *p3[1] << endl;  // 输出:11
cout << "p3[2](值): " << *p3[2] << endl;  // 输出:12

// 修改指向的地址
int d = 13;
p3[0] = &d;  // 让 p3[0] 指向 d 的地址

// 打印新的地址和对应的值
cout << "p3[0](修改后地址): " << p3[0] << endl;  // 输出:d 的地址
cout << "p3[0](修改后值): " << *p3[0] << endl;    // 输出:13

// 修改指向的值
*p3[0] = 99;  // 通过 p3[0] 修改 d 的值为 99

// 打印修改后的值
cout << "p3[0](修改后地址): " << p3[0] << endl;  // 输出:d 的地址
cout << "p3[0](修改后值): " << *p3[0] << endl;    // 输出:99
cout << "d(最终值): " << d << endl;                // 输出:99

遍历指针数组

// 输出指针数组总大小和每个元素大小
cout << "得到指针数组一共占多少字节: " << sizeof(p3) << endl;           // 输出:指针数组的总字节数 24
cout << "得到指针中一个元素占多少字节: " << sizeof(p3[0]) << endl;       // 输出:每个指针元素的字节数 8
cout << "得到指针数组的容量: " << sizeof(p3) / sizeof(p3[0]) << endl;   // 输出:指针数组的元素个数(容量)3

// 遍历指针数组并输出每个元素存储的地址和指向的值
for (int i = 0; i < sizeof(p3) / sizeof(p3[0]); i++) {
    cout << "p3[" << i << "](地址): " << p3[i] << endl;  // 输出每个元素的地址
    cout << "p3[" << i << "](值): " << *p3[i] << endl;    // 输出每个元素指向的值
}

地址关系

// 数组名 p3 代表指向指针数组首元素的地址
cout << "p3(指针数组名,表示首地址): " << p3 << endl;
cout << "&p3[0](数组名表示第一个元素的地址): " << &p3[0] << endl;

// 解引用指针数组中的第一个元素
cout << "*p3(指针数组第一个元素存储的地址): " << *p3 << endl;
// 解引用第二次,获得第一个元素存储的地址所指向的值
cout << "**p3(指针数组第一个元素指向的值): " << **p3 << endl;//99

// 指针数组的增减
// 获取指向第二个元素的指针
cout << "p3+1(指向第二个元素的地址): " << p3 + 1 << endl;
cout << "*(p3+1)(指向第二个元素的地址所指向的值): " << *(p3 + 1) << endl;
cout << "**(p3+1)(指向第二个元素的地址所指向的值): " << **(p3 + 1) << endl;//11

// 遍历并展示指针增减的效果
cout << "******遍历并展示指针增减的效果******" << endl;
for (int i = 0; i < sizeof(p3) / sizeof(p3[0]); i++) {
    // 输出指针数组中第 i 个元素的地址
    cout << "p3 + " << i << "(第 " << i << " 个元素的地址): " << p3 + i << endl;
    // 输出指针数组中第 i 个元素存储的值(即地址)
    cout << "*(p3 + " << i << ")(第 " << i << " 个元素的地址所指向的值): " << *(p3 + i) << endl;
    // 输出指针数组中第 i 个元素中存储的地址指向的值
    cout << "**(p3 + " << i << ")(第 " << i << " 个元素中存储的地址指向的值): " << **(p3 + i) << endl;
}

28.2 知识点代码

Lesson28_指针_指针数组.cpp

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

    #pragma region 知识回顾 数组指针

    cout << "******知识回顾 数组指针******" << endl;

    // 数组指针是我们在学习指针和数组中 二维数组相关知识时学习的
    // 数组指针是一个指向整个数组的指针,本质上是一个指针,指向一个包含n个元素的数组

    // 数组指针定义规则:变量类型 (*指针名)[元素个数]    
    // 例如 int (*p2)[4] 表示指向包含4个int元素的一维数组的指针

    // 定义二维数组
    int arr[3][4] = { 1,2,3,4,
                      5,6,7,8,
                      9,10,11,12 };

    // 数组指针定义:指向包含4个整数的一维数组
    int(*p)[4] = arr;


    // 打印数组指针

    // 打印数组指针 p 的地址和 p[0] 的地址
    cout << "p: " << p << endl;        // 打印p的地址,即指向的数组的起始地址
    // 输出: p: 000000F33ACFF5E8
    cout << "p[0]: " << p[0] << endl;  // 打印p[0],即第一行数组的地址(arr[0]的地址)
    // 输出: p[0]: 000000F33ACFF5E8

    // 打印 p+1 和 p[1],它们指向的是第二行数组的地址
    cout << "p+1: " << p + 1 << endl;  // p+1:指向 arr[1](第二行数组)的地址
    // 输出: p+1: 000000F33ACFF5F8
    cout << "p[1]: " << p[1] << endl;  // p[1]:指向 arr[1](第二行数组)的地址
    // 输出: p[1]: 000000F33ACFF5F8

    // 打印 p+2 和 p[2],它们指向的是第三行数组的地址
    cout << "p+2: " << p + 2 << endl;  // p+2:指向 arr[2](第三行数组)的地址
    // 输出: p+2: 000000F33ACFF608
    cout << "p[2]: " << p[2] << endl;  // p[2]:指向 arr[2](第三行数组)的地址
    // 输出: p[2]: 000000F33ACFF608



    // 打印结解引用数组指针 (普通指针)

    // 解引用数组指针 p
    cout << "*p: " << *p << endl;  // *p:解引用数组指针,访问arr[0](第一行数组)的地址
    // 输出: *p: 000000F33ACFF5E8

    // 解引用 p+1 和 p+2
    cout << "*(p+1): " << *(p + 1) << endl;  // 解引用p+1,访问arr[1](第二行数组)的地址
    // 输出: *(p+1): 000000F33ACFF5F8
    cout << "*(p+2): " << *(p + 2) << endl;  // 解引用p+2,访问arr[2](第三行数组)的地址
    // 输出: *(p+2): 000000F33ACFF608


    //访问数组元素

    // 解引用数组指针并访问元素
    cout << "(*p)[1]: " << (*p)[1] << endl;  // 解引用数组指针后,访问第一行数组中的第二个元素(arr[0][1]),输出 2
    // 输出: (*p)[1]: 2

    // 解引用并偏移后的结果
    cout << "*((*p) + 1): " << *((*p) + 1) << endl;  // 解引用数组指针并进行偏移,访问arr[0][1],即值为 2
    // 输出: *((*p) + 1): 2

    // 访问第二行第三列的元素
    cout << "*(*(p + 1) + 2): " << *(*(p + 1) + 2) << endl;  // 访问arr[1][2],输出 7
    // 输出: *(*(p + 1) + 2): 7

    // 访问第三行第四列的元素
    cout << "*(*(p + 2) + 3): " << *(*(p + 2) + 3) << endl;  // 访问arr[2][3],输出 12
    // 输出: *(*(p + 2) + 3): 12

    cout << "******知识回顾 数组指针结束******" << endl;

    #pragma endregion

    #pragma region 知识点一 指针数组基本概念

    // 指针数组是由n个指针组成的数组,每个指针可以指向一个单独的元素地址
    // 定义规则:变量类型* 数组名[数组长度];
    // 重点:
    // 指针数组中每个元素存储的是地址!!!!
    // 想要获取地址中的值,需要加*(解引用操作)

    // 举例:
    int* p2[4];  // 定义一个指针数组,包含4个指针元素
    int a = 10;   // 定义一个整数变量 a 并赋值为 10
    p2[0] = &a;   // 将 p2[0] 指向 a 的地址

    // 打印指针数组中第一个元素(存储的是 a 的地址)
    cout << "p2[0](地址): " << p2[0] << endl;  // 输出:a 的地址
    // 通过解引用 p2[0] 获取存储地址的值,即 a 的值
    cout << "p2[0](值): " << *p2[0] << endl;    // 输出:10(a 的值)

    #pragma endregion

    #pragma region 知识点二 指针数组的使用

    // 声明多个整型变量
    int b = 11, c = 12;

    // 定义一个指针数组,p3 存储了 a, b, c 的地址
    int* p3[] = { &a, &b, &c };

    // 打印指针数组中每个元素存储的地址
    cout << "p3[0](地址): " << p3[0] << endl;  // 输出:a 的地址
    cout << "p3[1](地址): " << p3[1] << endl;  // 输出:b 的地址
    cout << "p3[2](地址): " << p3[2] << endl;  // 输出:c 的地址

    // 打印指针数组中每个元素存储的地址所指向的值
    cout << "p3[0](值): " << *p3[0] << endl;  // 输出:10
    cout << "p3[1](值): " << *p3[1] << endl;  // 输出:11
    cout << "p3[2](值): " << *p3[2] << endl;  // 输出:12

    // 修改指向的地址
    int d = 13;
    p3[0] = &d;  // 让 p3[0] 指向 d 的地址

    // 打印新的地址和对应的值
    cout << "p3[0](修改后地址): " << p3[0] << endl;  // 输出:d 的地址
    cout << "p3[0](修改后值): " << *p3[0] << endl;    // 输出:13

    // 修改指向的值
    *p3[0] = 99;  // 通过 p3[0] 修改 d 的值为 99

    // 打印修改后的值
    cout << "p3[0](修改后地址): " << p3[0] << endl;  // 输出:d 的地址
    cout << "p3[0](修改后值): " << *p3[0] << endl;    // 输出:99
    cout << "d(最终值): " << d << endl;                // 输出:99

    // 遍历指针数组
    // 输出指针数组总大小和每个元素大小
    cout << "得到指针数组一共占多少字节: " << sizeof(p3) << endl;           // 输出:指针数组的总字节数 24
    cout << "得到指针中一个元素占多少字节: " << sizeof(p3[0]) << endl;       // 输出:每个指针元素的字节数 8
    cout << "得到指针数组的容量: " << sizeof(p3) / sizeof(p3[0]) << endl;   // 输出:指针数组的元素个数(容量)3

    // 遍历指针数组并输出每个元素存储的地址和指向的值
    for (int i = 0; i < sizeof(p3) / sizeof(p3[0]); i++) {
        cout << "p3[" << i << "](地址): " << p3[i] << endl;  // 输出每个元素的地址
        cout << "p3[" << i << "](值): " << *p3[i] << endl;    // 输出每个元素指向的值
    }

    // 地址关系
    // 数组名 p3 代表指向指针数组首元素的地址
    cout << "p3(指针数组名,表示首地址): " << p3 << endl;
    cout << "&p3[0](数组名表示第一个元素的地址): " << &p3[0] << endl;

    // 解引用指针数组中的第一个元素
    cout << "*p3(指针数组第一个元素存储的地址): " << *p3 << endl;
    // 解引用第二次,获得第一个元素存储的地址所指向的值
    cout << "**p3(指针数组第一个元素指向的值): " << **p3 << endl;//99

    // 指针数组的增减
    // 获取指向第二个元素的指针
    cout << "p3+1(指向第二个元素的地址): " << p3 + 1 << endl;
    cout << "*(p3+1)(指向第二个元素的地址所指向的值): " << *(p3 + 1) << endl;
    cout << "**(p3+1)(指向第二个元素的地址所指向的值): " << **(p3 + 1) << endl;//11

    // 遍历并展示指针增减的效果
    cout << "******遍历并展示指针增减的效果******" << endl;
    for (int i = 0; i < sizeof(p3) / sizeof(p3[0]); i++) {
        // 输出指针数组中第 i 个元素的地址
        cout << "p3 + " << i << "(第 " << i << " 个元素的地址): " << p3 + i << endl;
        // 输出指针数组中第 i 个元素存储的值(即地址)
        cout << "*(p3 + " << i << ")(第 " << i << " 个元素的地址所指向的值): " << *(p3 + i) << endl;
        // 输出指针数组中第 i 个元素中存储的地址指向的值
        cout << "**(p3 + " << i << ")(第 " << i << " 个元素中存储的地址指向的值): " << **(p3 + i) << endl;
    }

    #pragma endregion

    #pragma region 总结

    // 对于指针数组来说,最重要的是理解指针数组在内存中存储信息的关系
    // 主要理解值和地址的关系
    // 指针数组名和本身地址的关系即可

    #pragma endregion

}

28.3 练习题

编写一个程序,完成以下任务:

定义三个函数,分别实现以下功能:

  • add(int a, int b): 返回 ab 的和。
  • subtract(int a, int b): 返回 ab 的差。
  • multiply(int a, int b): 返回 ab 的积。

创建一个指针数组,存储指向这些函数的指针。

通过指针数组调用每个函数,并打印结果。

// 返回 a 和 b 的和
int add(int a, int b)
{
    return a + b;
}

// 返回 a 和 b 的差
int subtract(int a, int b)
{
    return a - b;
}

// 返回 a 和 b 的积
int multiply(int a, int b)
{
    return a * b;
}

// 创建一个函数指针数组,用于存储指向不同函数的指针
int (*functions[3])(int, int); // 数组大小为3,用于存储函数指针

// 为指针数组赋值,分别指向 add, subtract, multiply 函数
functions[0] = add;
functions[1] = subtract;
functions[2] = multiply;

// 遍历指针数组,调用每个函数并打印结果
for (int i = 0; i < sizeof(functions) / sizeof(functions[0]); i++)
{
    int result = functions[i](10, 5);  // 调用函数,传入 10 和 5 作为参数
    cout << "函数结果: " << result << endl;  // 打印函数返回值
}

// 函数结果: 15
// 函数结果: 5
// 函数结果: 50

编写一个程序,完成以下任务:

创建一个 3x3 的二维整型数组,并初始化如下:

1 2 3
4 5 6
7 8 9

创建一个指针数组,让每个指针指向二维数组的一行。

使用指针数组,输出二维数组中的所有元素。

// 定义一个 3x3 的二维数组,并初始化
int array[3][3] = { {1, 2, 3},
                    {4, 5, 6},
                    {7, 8, 9} };

// 创建一个指针数组,每个元素指向二维数组的每一行
int* p[3] = { array[0], array[1], array[2] };

// 遍历指针数组,输出二维数组的所有元素
for (int i = 0; i < 3; i++) // 遍历每一行
{
    for (int j = 0; j < 3; j++) // 遍历每一列
    {
        // 使用指针数组来访问二维数组中的元素
        // p[i] 是指向第 i 行的指针,p[i][j] 访问第 i 行第 j 列的元素
        cout << "元素[" << i << "][" << j << "]: " << p[i][j] << endl;
    }
}

// 元素[0][0]: 1
// 元素[0][1]: 2
// 元素[0][2]: 3
// 元素[1][0]: 4
// 元素[1][1]: 5
// 元素[1][2]: 6
// 元素[2][0]: 7
// 元素[2][1]: 8
// 元素[2][2]: 9

28.4 练习题代码

Lesson28_练习题.cpp

#include <iostream>
using namespace std;

int add(int a, int b);
int subtract(int a, int b);
int multiply(int a, int b);

int main()
{
    std::cout << "指针数组 练习题!\n";

    #pragma region 练习题一

    // 创建一个函数指针数组,用于存储指向不同函数的指针
    int (*functions[3])(int, int); // 数组大小为3,用于存储函数指针

    // 为指针数组赋值,分别指向 add, subtract, multiply 函数
    functions[0] = add;
    functions[1] = subtract;
    functions[2] = multiply;

    // 遍历指针数组,调用每个函数并打印结果
    for (int i = 0; i < sizeof(functions) / sizeof(functions[0]); i++)
    {
        int result = functions[i](10, 5);  // 调用函数,传入10和5作为参数
        cout << "函数结果: " << result << endl;  // 打印函数返回值
    }

    //函数结果: 15
    //函数结果 : 5
    //函数结果 : 50

    #pragma endregion

    #pragma region 练习题二

    // 定义一个 3x3 的二维数组,并初始化
    int array[3][3] = { {1, 2, 3},
                        {4, 5, 6},
                        {7, 8, 9} };

    // 创建一个指针数组,每个元素指向二维数组的每一行
    int* p[3] = { array[0], array[1], array[2] };

    // 遍历指针数组,输出二维数组的所有元素
    for (int i = 0; i < 3; i++) // 遍历每一行
    {
        for (int j = 0; j < 3; j++) // 遍历每一列
        {
            // 使用指针数组来访问二维数组中的元素
            // p[i] 是指向第 i 行的指针,p[i][j] 访问第 i 行第 j 列的元素
            cout << "元素[" << i << "][" << j << "]: " << p[i][j] << endl;
        }
    }

    //元素[0][0]: 1
    //元素[0][1] : 2
    //元素[0][2] : 3
    //元素[1][0] : 4
    //元素[1][1] : 5
    //元素[1][2] : 6
    //元素[2][0] : 7
    //元素[2][1] : 8
    //元素[2][2] : 9

    #pragma endregion
}

#pragma region 练习题一

/*编写一个程序,完成以下任务:
1.定义三个函数,分别实现以下功能:
add(int a, int b):返回 a 和 b 的和。
subtract(int a, int b):返回 a 和 b 的差。
multiply(int a, int b):返回 a 和 b 的积。
2.创建一个指针数组,存储指向这些函数的指针。
3.通过指针数组调用每个函数,并打印结果。*/

// 返回 a 和 b 的和
int add(int a, int b)
{
    return a + b;
}

// 返回 a 和 b 的差
int subtract(int a, int b)
{
    return a - b;
}

// 返回 a 和 b 的积
int multiply(int a, int b)
{
    return a * b;
}

#pragma endregion

#pragma region 练习题二

/*编写一个程序,完成以下任务:
1.创建一个 3x3 的二维整型数组,并初始化如下:
1 2 3
4 5 6
7 8 9
2.创建一个指针数组,让每个指针指向二维数组的一行。
3.使用指针数组,输出二维数组中的所有元素。*/

#pragma endregion


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

×

喜欢就点赞,疼爱就打赏