const数据和const指针

1. 要讨论的问题

在C/C++中有个const关键字,本文通过例子来说明const数据和const指针的含义。


通常会有如下几种表示方法:

char greeting[] = "Hello";
char* p1 = greeting;
const char* p2 = greeting; // const data
char* const p3 = greeting; // const pointer
const char* const p4 = greeting; // const data & const pointer

2. 原则&简单的类比例子

具体const针对的是数据还是指针,则以*为分界线。左边的const,是针对数据的;右边的const,是针对指针的。一个辅助理解的声明可以是:

const size_t BUFFER_SIZE = 1024;

显然在这里没有指针的概念,这里的const就是表示:变量BUFFER_SIZE是1024,不能改变这个变量的值。或者进一步地说,不能改变这个变量BUFFER_SIZE所指向的内存的值,就称为const数据好了。

对于const数据,如果修改该变量的值,会有error:

const size_t BUFFER_SIZE = 1024;
BUFFER_SIZE = 4096; //error: assignment of read-only variable 'BUFFER_SIZE'    

注释部分即为编译器的输出。本文用到编译器如下:

D:\examples\cpp\const>gcc --version
gcc (GCC) 4.8.1
Copyright (C) 2013 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.


D:\examples\cpp\const>g++ --version
g++ (GCC) 4.8.1
Copyright (C) 2013 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

另外一点,const size_t和size_t const是完全等价的,只是写法不一样。


3. const数据和const指针

在有了const变量(或简单称为const数据)的类比之后,我们就比较容易区分const数据和const指针了。

为便于阅读,把前面的代码拷贝过来:

char greeting[] = "Hello";
char* p1 = greeting;
const char* p2 = greeting; // const data
char* const p3 = greeting; // const pointer
const char* const p4 = greeting; // const data & const pointer

结论:

  • p1: 因为没有const,所以p1这个变量可以再指向其他的字符串(修改指针),并且,还可以修改p1指向的这个字符串的值(修改数据)。
  • p2:这里是const 数据,即p2所指向的数据是不能修改的,不能用p2[i]=c这种形式(不能修改数据)。但p2这个指针不是const,即可以修改p2这个指针,让它指向别的char*(修改变量)。
  • p3:数据不是const的,但指针是const的。所以,可以修改p3指向的字符串,比如p3[i]=c。但这个指针是常量,不能让它指向其他的指针,比如p3=p1是不允许的。
  • p4:const数据 && const指针。

下面的示例代码尝试修改数据和尝试修改指针,注释部分是编译的error信息:

#include <iostream>

int main()
{
    char greeting[] = "Hello";
    char another_greeting[] = "Hello, world!";
    char* p1 = greeting;
    const char* p2 = greeting; // const data
    char* const p3 = greeting; // const pointer
    const char* const p4 = greeting; // const data & const pointer

    p1 = another_greeting; //ok
    p1[0] = 'h'; //ok
    
    p2 = "test"; //ok
    //p2[0] = 'T'; //error: assignment of read-only location '* p2'
    
    //p3 = "test"; //error: assignment of read-only variable 'p3'
    p3[0] = 'h'; //ok
    
    //p4 = "test"; //error: assignment of read-only variable 'p4'
    //p4[0] = 'x'; //error: assignment of read-only location '*(const char*)p4'
    
    // The cout is only used to remove all the warnings.
    // e.g.: variable 'p2' set but not used [-Wunused-but-set-variable]
    std::cout<<p1<<std::endl;
    std::cout<<p2<<std::endl;
    std::cout<<p3<<std::endl;
    std::cout<<p4<<std::endl;
    
    return 0;
}

4. 参考资料

在《C++程序设计语言特别版》5.4节,详细介绍了const的语法。

<think>好的,我现在需要帮助用户理解C++中const指针常量const常量指针区别及使用场景。首先,我得回忆一下const指针中的应用规则。根据用户提供的引用,特别是引用1提到的“左数右指原则”,也就是const在*左边还是右边,这会影响指针的性质。 用户提到的引用中有几个关键点需要整合。比如,引用2解释了顶层const底层const的概念,顶层const表示指针本身是常量,而底层const表示指针指向的数据常量。然后引用3引用4进一步说明了常量指针指针常量的不同声明方式以及使用场景。例如,常量指针const int *p)用于函数参数,确保不修改指向的数据,而指针常量(int *const p)用于指针本身不能改变的情况,比如引用中的例子类似于引用的行为。 我需要先明确两者的定义。指针常量是指指针本身的值(即指向的地址)不可变,但可以通过指针修改所指向的内容。而常量指针则是不能通过指针修改所指向的内容,但指针可以指向其他地址。然后,当两者结合时,比如const int *const p,就既不能修改指针的指向,也不能修改指向的内容。 接下来要考虑如何将这些概念清晰地传达给用户。可能需要用例子来对比说明。例如,指针常量的声明是int *const p = &a;,这里const在*右边,所以p的地址不能变,但*p可以修改。而常量指针const int *p = &a;,这里const在*左边,所以p可以指向不同的地址,但不能通过p修改a的值。 同时,引用5提到当指向常量时,必须使用指向常量指针,否则会编译错误,比如用非常量指针指向常量变量是不允许的。这也需要注意在例子中说明,避免用户犯错。 最后,总结使用场景:常量指针适合用于函数参数,保护数据不被修改;指针常量用于需要固定指针指向的情况,比如引用。而两者的结合则用于需要完全不可变的场合。需要确保这些例子解释符合用户提供的引用内容,并且正确无误。</think>### C++ const 指针常量 vs const 常量指针 区别与使用场景 #### 一、核心区别(左数右指原则) 1. **常量指针(底层const)** - **定义**:`const int* p` 或 `int const* p`(`const` 在 `*` 左侧) - **特性**:指针指向的内容不可修改,但指针本身可以指向其他地址 - **示例**: ```cpp int a = 10, b = 20; const int* p = &a; // ✅ p可以指向a p = &b; // ✅ 允许修改指针指向 // *p = 30; // ❌ 禁止通过p修改内容 ``` 2. **指针常量(顶层const)** - **定义**:`int* const p`(`const` 在 `*` 右侧) - **特性**:指针本身不可修改(固定指向一个地址),但可以通过指针修改内容 - **示例**: ```cpp int a = 10; int* const p = &a; // ✅ 初始化后p固定指向a *p = 20; // ✅ 允许修改内容 // p = &b; // ❌ 禁止修改指针指向 ``` 3. **双重const(顶层+底层)** - **定义**:`const int* const p` - **特性**:指针指向的地址内容均不可修改 - **示例**: ```cpp const int x = 5; const int* const p = &x; // ✅ 指向常量常量指针 // *p = 10; // ❌ 禁止修改内容 // p = &y; // ❌ 禁止修改指向 ``` #### 二、使用场景对比 | 类型 | 典型场景 | 类似行为 | |--------------------|------------------------------------------------------------------------|-------------------| | 常量指针 (`const int*`) | 函数参数保护数据:`void print(const int* arr)`[^3] | 类似 `const int&` | | 指针常量 (`int* const`) | 固定内存管理:`char* const buffer = malloc(1024)`[^4] | 类似引用 (`int&`) | | 双重const | 硬件寄存器访问:`volatile const uint32_t* const REG = 0xFFFF0000;`[^5] | 完全只读操作 | #### 三、易错点与编译规则 1. **常量指针与变量混用** ```cpp const int x = 10; int* p = &x; // ❌ 错误:非常量指针指向常量 const int* p2 = &x; // ✅ 正确 ``` 2. **指针常量的初始化** ```cpp int a = 5; // int* const p; // ❌ 错误:必须初始化 int* const p = &a; // ✅ 正确 ``` 3. **类型转换规则** - 常量指针可隐式转换为非常量指针(需显式强制转换) - 指针常量无法隐式转换类型(地址绑定固定类型)[^2] #### 四、底层实现视角 1. **引用与指针常量的关系** ```cpp int a = 10; int& ref = a; // 等价于 int* const ptr = &a; ref = 20; // 等价于 *ptr = 20; [^4] ``` 2. **内存访问保护** - 常量指针通过编译器检查阻止写入操作 - 指针常量通过固定地址实现稳定的内存访问[^1]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值