banner
cells

cells

为美好的世界献上 code

关于指针常量与常量指针

指针常量#

int *const ptr = nullptr;

const 修饰的是指针 ptr 的值,ptr 本身不能被修改,所以指针常量必须初始化,同时我们无法对 ptr 的值进行修改。

int a = 10;
int *const ptr = &a;
ptr = nullptr; // error

指针常量的应用场景#

例如:需要编写一个函数,实现使用传参指针的形式交换两个整形的值。

下面是实现代码:

void swap(int *a, int *b) {
    int tmp = *a;
    *a = *b;
    *b = tmp;
}

上述代码可以实现功能,但是存在一定的问题,因为我们可以在函数体内可以修改指针的所指向的值,同时也可以修改指针的值(这并不是我们所希望的),为了使代码更为健壮,我们可以使用指针常量,使得传入指针的值不会被无意修改。

下面是修改后的代码:

void swap(int *const a, int *const b) { ... }

常量指针#

const int *ptr;
// 或
int const *ptr;

const 修饰的 *ptr 的值,也就是指针所指向的值,ptr 指向的值是不可修改的。同时在不进行常量类型转换的情况下我们无法对 *ptr 进行修改。

int a = 10;
int const *ptr = &a;
*ptr = 20; // error

常量指针的应用场景#

例如:需要编写一个函数,实现打印一个数组。

下面是实现代码:

void printArray(int const* arr, size_t len) {
    for (size_t i = 0; i < len; ++i) {
        std::cout << arr[i] << " ";
    }
}

这里你可能会认为使用 const 修饰数组退化而来的指针所指向的值就可以了,但是这仍存在的问题,因为我们仍可以在函数体内修改指针的值,这并不是我们希望的,因此在此基础上还需要 const 修饰指针的值。

下面是修改后的代码:

void printArray(int const *const arr, size_t len) { ... }

指针常量与常量指针的关系#

我们会发现常量指针有两种写法:int const *const int *

对于第一种形式的理解:const向左修饰的,例如:int const *ptr;const 修饰的是 int 值类型,所以指针指向的值不可以修改;int *const ptr = nullptr;const 修饰 int * 指针类型,所以指针指向不能修改。这种理解需要遵守的代码规范,因为如果将常量指针写成 const int * 就需要我们进行转换了。(也可以理解为如果左侧没有对象,则转为修饰右侧对象。)

常量指针指针常量的命名则是与 const int *int *const 的代码规范相对应。

观察以下代码:

#include <iostream>

struct A {
    void foo() { std::cout << "non const" << std::endl; }
    void foo() const { std::cout << "const" << std::endl; }
};

int main() {
    A a;
    A *const ptr1 = &a;
    ptr1->foo();
    A const *ptr2 = &a;
    ptr2->foo();
}

int *const ptr1 = &aconst 修饰的是 ptr1 指针的值,没有修饰指针所指向的对象,所以 ptr1->foo() 调用非 const 版本。

int const *ptr2 = &aconst 修饰的是 ptr2 指针指向的值 a,意思是指向的值不可修改,所以 ptr2->foo() 调用 const 版本。

如有纰漏,欢迎指正。

加载中...
此文章数据所有权由区块链加密技术和智能合约保障仅归创作者所有。