指针引导:掌握C++内存操控的艺术2

简介: 指针引导:掌握C++内存操控的艺术

5.3 指针与数组

5.3.1 使用指针处理数组

在C++中,指针与数组有着密切的关联。指针可以用来处理数组的元素。下面是一个例子,展示如何使用指针输出数组中的所有元素。


【例5-5】使用指针输出数组中的所有元素

#include <iostream>
using namespace std;
int main() 
{
    int arr[] = {1, 2, 3, 4, 5};
    int *ptr = arr;
    cout << "数组中的元素:";
    for(int i = 0; i < sizeof(arr)/sizeof(arr[0]); i++) 
    {
        cout << *(ptr + i) << " ";
    }
    return 0;
}

输出

数组中的元素:1 2 3 4 5

在上面的示例中,我们先定义了一个整型数组 arr,然后创建了一个指向数组首元素的指针 ptr,将其初始化为 arr。然后我们使用指针进行遍历,通过 *(ptr + i) 来访问数组中的每个元素,并输出到控制台。


5.3.2 指针数组

指针数组是数组元素为指针类型的数组。我们可以使用指针数组来处理二维数组中的元素。下面是一个例子,展示如何用指针数组处理二维数组的元素。


【例5-6】用指针数组处理二维数组的元素

#include <iostream>
using namespace std;
int main() 
{
    int arr[3][4] = {{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}};
    int *ptr[3];
    for(int i = 0; i < 3; i++) 
    {
        ptr[i] = arr[i];
    }
    cout << "二维数组中的元素:";
    for(int i = 0; i < 3; i++) 
    {
        for(int j = 0; j < 4; j++) 
        {
            cout << *(ptr[i] + j) << " ";
        }
    }
    return 0;
}

输出

二维数组中的元素:1 2 3 4 5 6 7 8 9 10 11 12

在上面的示例中,我们定义了一个二维整型数组 arr,然后创建了一个指针数组 ptr。然后,我们使用一个循环将每行的首元素地址赋值给指针数组中的元素。最后,我们使用指针数组来遍历二维数组的元素,并输出到控制台。


5.3.3 多级指针

在C++中,我们还可以使用多级指针,即指针的指针,来进行更灵活的操作。下面是两个例子,展示了多级指针的应用。


【例5-7】二级指针的应用

#include <iostream>
using namespace std;
int main() 
{
    int num = 10;
    int *ptr = &num;
    int **pptr = &ptr;
    cout << "变量num的值:" << num << endl;
    cout << "一级指针ptr的值:" << *ptr << endl;
    cout << "二级指针pptr的值:" << **pptr << endl;
    return 0;
}

输出

变量num的值:10
一级指针ptr的值:10
二级指针pptr的值:10

在上面的示例中,我们首先定义了一个整型变量 num,然后创建了一个指向 num 的指针 ptr,最后创建了一个指向 ptr 的指针 pptr。通过多级指针,我们可以访问到 num 的值。


【例5-8】二维数组的地址

#include <iostream>
using namespace std;
int main() 
{
    int arr[3][4] = {{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}};
    int (*ptr)[4] = arr;
    cout << "二维数组的地址:" << ptr << endl;
    return 0;
}

输出

二维数组的地址:008FF978

在上面的示例中,我们定义了一个二维整型数组 arr,然后创建了一个指针 ptr,将其初始化为 arr。通过输出指针的值,我们可以获取到二维数组的地址。


5.3.4 数组指

数组指针是指向数组的指针类型。通过使用数组指针,我们可以方便地访问二维数组中的元素。下面是一个例子,展示了如何使用数组指针访问二维数组。


【例5-9】使用数组指针访问二维数组

#include <iostream>
using namespace std;
int main() 
{
    int arr[3][4] = {{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}};
    int (*ptr)[4];
    ptr = arr;
    cout << "二维数组的第二个元素:" << *(*ptr + 1) << endl;
    return 0;
}

输出

二维数组的第二个元素:2

在上面的示例中,我们定义了一个二维整型数组 arr,然后创建了一个二维数组指针 ptr。然后,我们将指针 ptr 指向二维数组 arr,通过 *(*ptr + 1) 来访问二维数组的第二个元素。


5.4 常量指针与指针常量

5.4.1 常量指针

常量指针是指指针指向的对象的值不能被修改,但指针本身可以改变指向其他对象。


【例5-10】常量指针的使用:

#include <iostream>
using namespace std;
int main() 
{
    int num = 10;
    const int *ptr = &num;   // 使用常量指针声明并指向num
    cout << "num的值为:" << *ptr << endl;   // 输出num的值
    // *ptr = 20;   // 错误,不能通过指针修改num的值
    int anotherNum = 20;
    ptr = &anotherNum;   // 指针指向另一个对象
    cout << "anotherNum的值为:" << *ptr << endl;   // 输出anotherNum的值
    return 0;
}

输出

num的值为:10
anotherNum的值为:20

在上述代码中,我们通过使用常量指针const int *ptr,声明了一个指向num的常量指针,并输出了num的值。然后尝试修改num的值,但由于ptr是常量指针,所以无法修改。接着,我们声明了另一个变量anotherNum并将ptr指向它,并输出了anotherNum的值。


5.4.2 指针常量

指针常量是指指针本身的值不能被修改,但指针指向的对象可以被修改。


【例5-11】指针常量的使用:

#include <iostream>
using namespace std;
int main() 
{
    int num = 10;
    int *const ptr = &num;   // 使用指针常量声明,且指向num
    cout << "num的值为:" << *ptr << endl;   // 输出num的值
    *ptr = 20;   // 允许通过指针修改num的值
    cout << "num的新值为:" << *ptr << endl;   // 输出新的num的值
    // ptr = nullptr;   // 错误,指针常量的值不能被修改
    return 0;
}

输出

num的值为:10
num的新值为:20

在上述代码中,我们通过使用指针常量int *const ptr,声明了一个指向num的指针常量,并输出了num的值。然后我们修改了num的值,由于ptr是指针常量,所以可以通过指针修改num的值并输出新的值。但尝试修改ptr的值则会报错。


5.5 动态内存分配

在C++中,动态内存分配是一种在程序运行时分配和释放内存的方法。与静态内存分配不同,动态内存分配可以根据程序的需要动态地请求和释放内存。这在一些情况下非常有用,例如在数组大小未知、对象数量不确定或需要在堆上分配内存的情况下。


5.5.1 分配单个存储空间

要在C++中分配单个存储空间,我们可以使用new关键字。下面是一个分配单个整数存储空间的例子:


int* p = new int;

在上面的例子中,我们使用new int来请求分配存储空间,并将返回的地址赋给指针变量p。然后,我们可以使用指针变量p来访问分配的内存空间。


在使用完动态分配的内存后,我们需要使用delete关键字来释放这块内存,以免造成内存泄漏。释放内存的方法如下:

delete p;

在上面的例子中,我们使用delete p来释放指针变量p指向的内存空间。


5.5.2 分配多个连续的存储空间

除了分配单个存储空间外,我们还可以使用new关键字来分配多个连续的存储空间,例如数组。下面是一个分配包含5个整数的数组的例子:

int* arr = new int[5];

在上面的例子中,我们使用new int[5]来请求分配包含5个整数的数组,并将返回的数组的首地址赋给指针变量arr。然后,我们可以使用指针变量arr来访问分配的数组。


同样地,当我们使用完动态分配的数组后,我们需要使用delete[]关键字来释放这块内存,以免造成内存泄漏。释放数组内存的方法如下:

delete[] arr;

在上面的例子中,我们使用delete[] arr来释放指针变量arr指向的数组的所有内存空间。


【例5-12】动态内存分配的使用


以下是一个关于动态内存分配的实际代码案例:

#include <iostream>
using namespace std;
int main() 
{
    // 分配单个存储空间
    int* p = new int;
    *p = 42;
    cout << "Value of p: " << *p << endl;
    delete p;
    // 分配多个连续的存储空间
    int size;
    cout << "Enter the size of the array: ";
    cin >> size;
    int* arr = new int[size];
    cout << "Enter " << size << " integers:" << endl;
    for (int i = 0; i < size; i++) 
    {
        cin >> arr[i];
    }
    cout << "You entered:" << endl;
    for (int i = 0; i < size; i++) 
    {
        cout << arr[i] << " ";
    }
    cout << endl;
    delete[] arr;
    return 0;
}

上面的代码演示了如何使用动态内存分配来分别分配单个存储空间和多个连续的存储空间,并通过输出来展示了动态内存分配的使用方法。

C++学习笔记


5.6 综合实例

【例 5-13】使用二级指针指向指针数组


问题描述:我们需要使用一个二级指针指向一个动态分配的指针数组,并对该数组进行操作。


解决方案:

#include <iostream>
using namespace std;
int main() 
{
    int length;
    cout << "请输入数组长度:";
    cin >> length;    
    int **ptrArr = new int*[length];  // 动态分配指针数组
    // 给指针数组中的每个指针分配内存空间
    for (int i = 0; i < length; i++) 
    {
        ptrArr[i] = new int;
        *ptrArr[i] = i;
    }
    // 输出指针数组中的值
    for (int i = 0; i < length; i++) 
    {
        cout << *ptrArr[i] << " ";
    }
    cout << endl;
    // 释放内存空间
    for (int i = 0; i < length; i++) 
    {
        delete ptrArr[i];
    }
    delete[] ptrArr;
    return 0;
}

输出

请输入数组长度:10
0 1 2 3 4 5 6 7 8 9

【例5-14】使用选择排序对字符串排序


问题描述:给定一个字符串数组,我们需要使用选择排序来对字符串进行排序。


解决方案:

#include <iostream>
#include <string>
using namespace std;
void selectionSort(string arr[], int length) 
{
    for (int i = 0; i < length - 1; i++) 
    {
        int minIndex = i;
        for (int j = i + 1; j < length; j++) 
        {
            if (arr[j] < arr[minIndex]) 
            {
                minIndex = j;
            }
        }
        swap(arr[i], arr[minIndex]);
    }
}
int main() 
{
    int length;
    cout << "请输入数组长度:";
    cin >> length;
    string *arr = new string[length];    
    for (int i = 0; i < length; i++) 
    {
        cout << "请输入第" << i + 1 << "个字符串:";
        cin >> arr[i];
    }
    selectionSort(arr, length);
    cout << "排序后的字符串数组为:";
    for (int i = 0; i < length; i++) 
    {
        cout << arr[i] << " ";
    }
    cout << endl;
    delete[] arr;
    return 0;
}

输出

请输入数组的长度:10
请输入第1个字符串:w
请输入第2个字符串:e
请输入第3个字符串:r
请输入第4个字符串:t
请输入第5个字符串:y
请输入第6个字符串:u
请输入第7个字符串:i
请输入第8个字符串:o
请输入第9个字符串:p
请输入第10个字符串:a
排序后的字符串数组为:a e i o p r t u w y

【例5-15】报数出圈问题


问题描述:有n个人围成一圈,从第一个人开始报数,报到m的人出圈,然后从出圈的下一个人开始重新报数,直到剩下最后一个人。我们需要找到最后剩下的那个人。


解决方案:

#include <iostream>
using namespace std;
int josephusProblem(int n, int m) 
{
    int lastPerson = 0;
    for (int i = 2; i <= n; i++) 
    {
        lastPerson = (lastPerson + m) % i;
    }
    return lastPerson + 1;
}
int main() 
{
    int n, m;
    cout << "请输入总人数:";
    cin >> n;
    cout << "请输入报数的数字:";
    cin >> m;    
    int lastPerson = josephusProblem(n, m);
    cout << "最后剩下的人是第" << lastPerson << "个人" << endl;
    return 0;
}

输出

请输入总人数:5
请输入报数的数字:4
最后剩下的人是第1个人
相关文章
|
6天前
|
存储 编译器 C语言
【C++】C\C++内存管理
【C++】C\C++内存管理
【C++】C\C++内存管理
|
1天前
|
安全 NoSQL Redis
C++新特性-智能指针
C++新特性-智能指针
|
4天前
|
编译器 C++
virtual类的使用方法问题之C++类中的非静态数据成员是进行内存对齐的如何解决
virtual类的使用方法问题之C++类中的非静态数据成员是进行内存对齐的如何解决
|
4天前
|
编译器 C++
virtual类的使用方法问题之在C++中获取对象的vptr(虚拟表指针)如何解决
virtual类的使用方法问题之在C++中获取对象的vptr(虚拟表指针)如何解决
|
4天前
|
安全 编译器 容器
C++STL容器和智能指针
C++STL容器和智能指针
|
6天前
|
C++
C++通过文件指针获取文件大小
C++通过文件指针获取文件大小
10 0
|
6天前
|
编译器 C语言 C++
【C++关键字】指针空值nullptr(C++11)
【C++关键字】指针空值nullptr(C++11)
|
6天前
|
算法 C++ 容器
【C++算法】双指针
【C++算法】双指针
|
6天前
|
C++ 容器
C++中自定义结构体或类作为关联容器的键
C++中自定义结构体或类作为关联容器的键
13 0
|
6天前
|
存储 算法 搜索推荐
【C++】类的默认成员函数
【C++】类的默认成员函数