您的位置:

理解C++中的双重指针

一、双重指针的基本概念

在C++中,我们已知的指针可以理解成指向某个内存地址的普通变量。而双重指针也就是指向指针的指针,简而言之,就是指向指针的地址的指针。这种概念在C++中不同于其他编程语言,需要我们深入理解。

举个例子,如果我们要传递一个指针的值,在函数中就需要将这个指针作为参数传递进来。但是如果我们想要修改指针本身所指向的内存地址,我们就需要传递这个指针的地址,也就是双重指针。

void ModifyPointer(int** ptr){
    *ptr = new int;
}
int main(){
    int* ptr = nullptr;
    ModifyPointer(&ptr);
    *ptr = 666;
    return 0;
}

在上面的代码中,我们将int型指针的地址作为参数传递到ModifyPointer函数中,然后在函数中通过修改指针的指针将其指向了一个新的内存地址,最后在main函数中就可以使用指针指向的内存地址进行赋值操作。

二、双重指针的应用场景

双重指针在C++中应用非常广泛,比如动态分配二维数组,链表逆序,树结构的操作等。

在使用动态分配二维数组的时候,我们可以使用双重指针方便地实现:

int** Allocate2DArray(int rows, int cols){
    int** arr = new int*[rows];
    for(int i = 0; i < rows; ++i){
        arr[i] = new int[cols];
    }
    return arr;
}
int main(){
    int rows = 10;
    int cols = 10;
    int** arr = Allocate2DArray(rows, cols);
    arr[0][0] = 666;
    return 0;
}

在上面的代码中,我们使用了双重指针来动态分配二维数组。首先我们将行数组new出来,然后再通过循环的方式new出列数组。最后返回的是一个二维数组指针,就可以通过索引的方式进行数据的存储和访问了。

三、指向指针的引用

在C++中,我们还可以使用指向指针的引用来进行双重指针的操作。指向指针的引用就是指针所指向的内存地址的别名,可以用来简化代码的书写。

void ModifyPointer(int*& ptr){
    ptr = new int;
}
int main(){
    int* ptr = nullptr;
    ModifyPointer(ptr);
    *ptr = 666;
    return 0;
}

在上面的代码中,我们使用指向指针的引用来进行指针的重新赋值。这种写法可以让我们在传递参数的时候不需要使用&符号来获取指针的地址。

四、双重指针的常见问题

在使用双重指针的时候,如果我们没有很好地掌握语言特性,就可能会带来一些问题。其中最常见的就是指针悬挂和指针泄漏。

指针悬挂是指程序在使用完一个指针后没有及时将其置空,导致这个指针成为了野指针,可能会指向程序中的任意内存地址,从而引发问题。

指针泄漏则是指程序在动态分配内存后没有及时释放,从而导致内存泄露的问题。

在使用双重指针的时候,我们一定要注意这些问题,避免程序出现错误和异常。

五、总结

双重指针是C++中一个非常强大的概念,掌握它能够让我们更加灵活地运用指针进行编程。同时,我们还需要注意使用双重指针时可能存在的问题,以免引发程序出现问题。

在实际的编程过程中,我们需要不断练习和深入理解,才能更好地应对各种情况,并编写出高质量的程序。

#include 
void ModifyPointer(int** ptr){
    *ptr = new int;
}
int** Allocate2DArray(int rows, int cols){
    int** arr = new int*[rows];
    for(int i = 0; i < rows; ++i){
        arr[i] = new int[cols];
    }
    return arr;
}
void Recursion(int** arr, int pos, int len){
    if(pos >= len){
        return;
    }
    int* temp = arr[pos];
    Recursion(arr, pos + 1, len);
    if(pos < len - 1){
        arr[pos + 1][0] = temp[pos];
    }
}
int main(){
    //双重指针的基本使用
    int* ptr = nullptr;
    ModifyPointer(&ptr);
    *ptr = 666;

    //动态分配二维数组
    int rows = 10;
    int cols = 10;
    int** arr = Allocate2DArray(rows, cols);
    arr[0][0] = 666;
    
    //链表逆序
    struct Node{
        int val;
        Node* next;
    };
    void ReverseLinkedList(Node** head){
        Node* pre = nullptr;
        Node* curr = *head;
        while(curr != nullptr){
            Node* next = curr->next;
            curr->next = pre;
            pre = curr;
            curr = next;
        }
        *head = pre;
    }
    
    //树的相关操作
    struct TreeNode{
        int val;
        TreeNode* left;
        TreeNode* right;
    };
    void InorderTraversal(TreeNode* root){
        if(root == nullptr){
            return;
        }
        InorderTraversal(root->left);
        std::cout << root->val << " ";
        InorderTraversal(root->right);
    }
    void ConstructTree(TreeNode** root){
        int val;
        std::cin >> val;
        if(val == -1){
            *root = nullptr;
        }else{
            *root = new TreeNode;
            (*root)->val = val;
            ConstructTree(&((*root)->left));
            ConstructTree(&((*root)->right));
        }
    }
    TreeNode* root = nullptr;
    ConstructTree(&root);
    InorderTraversal(root);
    
    return 0;
}