C++系列十二:指针数组

简介: C++系列十二:指针数组


**指针数组(Array of Pointers)**是一种特殊的数组,它存储的是指针,而不是实际的数据值。每个元素都是一个指针,可以指向一个同类型的内存地址。通过指针数组,我们可以灵活地操作和访问动态分配的内存空间。

1. 指针数组的声明与初始化

(1) 指针数组的声明

在C++中,声明一个指针数组需要指定数组的大小和指针所指向的数据类型。例如:

int* ptrArray[10]; // 声明一个包含10个整型指针的数组

(2)指针数组的初始化

可以通过以下方式初始化指针数组:

int values[] = {1, 2, 3, 4, 5};
int* ptrArray[5] = {values[0], values[1], values[2], values[3], values[4]}; // 将数组的值赋给指针数组

或者使用动态内存分配:

int* ptrArray[10];
for(int i = 0; i < 10; i++) {
    ptrArray[i] = new int; // 为每个指针分配内存空间
}

2. 指针数组的应用场景

(1)动态内存分配

通过指针数组,可以方便地进行动态内存分配和释放,实现更加灵活的内存管理。例如,可以根据需要动态地创建和销毁数组。以下是一个使用指针数组进行动态内存分配的示例:

#include <iostream>
#include <cstdlib> // 包含new和delete操作符的头文件
int main() {
    int size = 5; // 定义数组大小为5
    int* ptrArray[size]; // 声明一个包含5个整型指针的数组
    for(int i = 0; i < size; i++) {
        ptrArray[i] = new int; // 为每个指针分配内存空间并初始化为0
    }
    // 使用指针数组进行操作,例如访问和修改元素的值
    for(int i = 0; i < size; i++) {
        std::cout << "ptrArray[" << i << "] = " << *ptrArray[i] << std::endl; // 输出每个指针所指向的值
        *ptrArray[i] = i; // 修改每个指针所指向的值
    }
    // 释放动态分配的内存空间
    for(int i = 0; i < size; i++) {
        delete ptrArray[i]; // 释放每个指针所指向的内存空间
    }
    return 0;
}

(2)函数参数传递

通过指针数组作为函数参数,可以实现向函数传递可变数量的参数。例如,使用指针数组作为函数的参数,可以实现类似于C语言中变参函数的功能。以下是一个使用指针数组作为函数参数的示例:

#include <iostream>
#include <cstdarg> // 包含stdarg.h头文件以使用变参函数功能
void printArray(int count, ...) { // 使用变参函数,接受可变数量的参数
    va_list args; // 定义va_list类型的变量args,用于遍历可变参数列表
    va_start(args, count); // 初始化args并定位到第一个可变参数的位置上
    for(int i = 0; i < count; i++) { // 遍历可变参数列表并输出每个参数的值
        std::cout << "Argument " << i << " = " << va_arg(args, int) << std::endl; // 使用va_arg宏获取下一个参数的值并更新args的位置到下一个参数上
    }
    va_end(args); // 清理可变参数列表并释放相关资源
}
int main() {
    printArray(3, 1, 2, 3); // 调用printArray函数并传递3个整数参数1、2和3
    return 0;
}

(3)多维数组的模拟

通过指针的算术运算,可以使用指针数组模拟多维数组的操作。这对于编写通用算法或实现矩阵运算等场景非常有用。以下是一个使用指针数组模拟二维数组的示例:

#include <iostream>
int main() {
    const int rows = 3;
    const int cols = 4;
    int** ptrArray = new int*[rows]; // 声明一个指向指针的指针,用于模拟二维数组的行指针
    for(int i = 0; i < rows; i++) {
        ptrArray[i] = new int[cols]; // 为每一行分配内存空间并初始化为0
    }
    // 使用指针数组模拟二维数组的操作,例如访问和修改元素的值
    for(int i = 0; i < rows; i++) {
        for(int j = 0; j < cols; j++) {
            std::cout << "ptrArray[" << i << "][" << j << "] = " << ptrArray[i][j] << std::endl; // 输出每个元素的值
            ptrArray[i][j] = i + j; // 修改每个元素的值
        }
    }
    // 释放动态分配的内存空间
    for(int i = 0; i < rows; i++) {
        delete[] ptrArray[i]; // 释放每一行的内存空间
    }
    delete[] ptrArray; // 释放整个二维数组的内存空间
    return 0;
}

(4)字符串处理

使用字符型指针数组可以方便地处理字符串,实现字符串的拼接、分割等操作。以下是一个使用字符型指针数组处理字符串的示例:

#include <iostream>
#include <cstring> // 包含strlen函数和strcpy函数等字符串处理函数的头文件
int main() {
    char str1[] = "Hello"; // 声明一个字符数组并初始化为"Hello"
    char str2[] = " World"; // 声明另一个字符数组并初始化为" World"
    char* ptrArray[2] = {str1, str2}; // 声明一个包含两个字符指针的数组,分别指向str1和str2的起始位置
    // 使用指针数组拼接字符串并输出结果
    std::cout << "Concatenated string: " << ptrArray[0] << ptrArray[1] << std::endl; // 输出"Hello World"
    // 使用指针数组分割字符串并输出结果
    char* token = strtok(str1, " "); // 使用strtok函数在str1中查找分隔符并将分隔符替换为空字符('\0')
    while(token != NULL) { // 遍历分割后的字符串并输出每个子串的值
        std::cout << "Token: " << token << std::endl; // 输出每个子串的值,例如"Token: Hello"和"Token: World"等
        token = strtok(NULL, " "); // 使用strtok函数继续查找下一个分隔符并将分隔符替换为空字符('\0')
    }
    return 0;
}

除了上述的应用场景,指针数组还可以用于实现其他一些功能,例如:

  • 动态数组增长:使用指针数组可以方便地实现动态数组的增长。通过重新分配内存并移动指针,可以在运行时动态地增加数组的大小。
  • 回调函数实现:通过将函数指针存储在指针数组中,可以在运行时动态地调用不同的函数。这在实现事件驱动的系统或游戏逻辑中非常有用。
  • 模拟栈和队列:通过使用指针数组,可以模拟实现栈和队列的数据结构。通过指针的算术运算,可以方便地实现元素的入栈、出栈和入队、出队等操作。
  • 多线程编程:在多线程编程中,可以使用指针数组来共享和同步数据。通过将数据存储在指针数组中,多个线程可以访问和修改这些数据,从而实现多线程之间的协作。
  • 插件系统:使用指针数组可以方便地实现插件系统。通过将插件的实现作为函数指针存储在指针数组中,可以在运行时动态地加载和卸载插件。

总之,C++中的指针数组是一种非常强大和灵活的工具,它提供了动态内存管理、多维数组模拟、字符串处理等方面的强大功能。掌握指针数组的使用,可以让你的C++程序更加灵活、高效和强大。

相关文章
|
20天前
|
存储 Java C++
C++ 引用和指针:内存地址、创建方法及应用解析
C++中的引用是现有变量的别名,创建时需用`&`运算符,如`string &meal = food;`。指针存储变量的内存地址,使用`*`创建,如`string* ptr = &food;`。引用必须初始化且不可为空,而指针可初始化为空。引用在函数参数传递和提高效率时有用,指针适用于动态内存分配和复杂数据结构操作。选择使用取决于具体需求。
38 9
|
20天前
|
存储 编译器 C语言
函数指针&&数组指针&&数组传参的本质&&字符指针(进阶篇)
函数指针&&数组指针&&数组传参的本质&&字符指针(进阶篇)
|
21天前
|
存储 安全 编译器
【C++专栏】C++入门 | auto关键字、范围for、指针空值nullptr
【C++专栏】C++入门 | auto关键字、范围for、指针空值nullptr
27 0
|
3天前
|
存储 C++
【C++模板】模板实现通用的数组
【C++模板】模板实现通用的数组
|
8天前
|
C++
【C++11(三)】智能指针详解--RAII思想&循环引用问题
【C++11(三)】智能指针详解--RAII思想&循环引用问题
|
8天前
|
人工智能 C++
【重学C++】【指针】轻松理解常量指针和指针常量
【重学C++】【指针】轻松理解常量指针和指针常量
10 0
|
8天前
|
存储 人工智能 C++
【重学C++】【指针】详解让人迷茫的指针数组和数组指针
【重学C++】【指针】详解让人迷茫的指针数组和数组指针
28 1
|
8天前
|
存储 人工智能 编译器
【重学C++】【指针】一文看透:指针中容易混淆的四个概念、算数运算以及使用场景中容易忽视的细节
【重学C++】【指针】一文看透:指针中容易混淆的四个概念、算数运算以及使用场景中容易忽视的细节
19 1
|
8天前
|
存储 C语言
指针数组作为main函数的形参
指针数组作为main函数的形参
13 0
|
15天前
|
存储 编译器 C++
【C++成长记】C++入门 | 类和对象(上) |类的作用域、类的实例化、类的对象大小的计算、类成员函数的this指针
【C++成长记】C++入门 | 类和对象(上) |类的作用域、类的实例化、类的对象大小的计算、类成员函数的this指针