Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >【C++】C 语言 和 C++ 语言中 const 关键字分析 ( const 关键字左数右指原则 | C 语言中常量的原理和缺陷 | C++ 语言中常量原理 - 符号表存储常量 )

【C++】C 语言 和 C++ 语言中 const 关键字分析 ( const 关键字左数右指原则 | C 语言中常量的原理和缺陷 | C++ 语言中常量原理 - 符号表存储常量 )

作者头像
韩曙亮
发布于 2023-10-15 08:29:20
发布于 2023-10-15 08:29:20
65500
代码可运行
举报
运行总次数:0
代码可运行

一、C 语言 const 关键字简介 - 左数右指原则

【C 语言】const 关键字用法 ( 常量指针 - const 在 * 左边 - 修饰数据类型 - 内存不变 | 指针常量 - const 在 * 右边 - 修饰变量 - 指针不变 )

1、const 关键字左数右指原则

普通类型数据的常量定义时 , const 关键字 在 数据类型 的 左边 和 右边 其作用 是相同的 ;

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    // 下面两种 const 用法效果相同
    // 定义普通类型 ( 非指针类型 ) 的常量 const 在 类型左右 都是相同的
    const int a = 10;
    int const b = 20;

指针数据的相关常量类型 :

  • const 关键字在 指针符号 * 左侧 表示该定义的事 常量指针 ( 指向的内存不能修改 )
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    // 左数右指 : const 在指针左边 数据是常量 , const 在指针右边 指针是常量
    // 下面两种情况 const 在指针左边 , 数据是常量 , 内存中的数据不能修改
    //      但是 , c 和 d 指针的指向可以修改
    // 下面两种情况是相同的
    const int* c;
    int const* d;
  • const 关键字在 指针符号 * 右侧是 表示定义的事指针常量 ( 指针本身不能被修改 ) ;
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    // 左数右指 : const 在指针左边 数据是常量 , const 在指针右边 指针是常量
    // 下面的情况 const 在指针右边 , 指针是常量 , 指针地址不能修改 
    //      但是 , 指针指向的内存中的数据可以修改
    int* const e = (int*)malloc(10);

指针常量与常量指针 : 需要查看 const 修饰的是 指针变量 , 还是 修饰 指针变量 指向的内存空间 ;

  • const 在 * 右边 ( 指针常量 | const 修饰的是变量 ) : 如果 const 修饰的是 指针变量 , 如 char * const d , const 修饰的是 char * , 指针不能被修改 ; 这是 指针常量 ;
  • const 在 * 左边 ( 常量指针 | const 修饰的是数据类型 ) : 如果 const 修饰的是 指针变量 指向的内存空间 , 如 const char *c , const 修饰的是 char , char 数据不能被修改 , 这是 常量指针 , 指向常量的指针 ;

2、代码示例 - const 关键字左数右指原则

下面的代码中 , 列出了 const 关键字的所有情况 , 看注释即可理解左数右指原则 ;

代码示例 :

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 导入标准 io 流头文件
// 其中定义了 std 命名空间
//#include <iostream>
// 导入 std 命名空间
//using namespace std;

#include <stdio.h>
#include <malloc.h>

int main() {

    // 下面两种 const 用法效果相同
    // 定义普通类型 ( 非指针类型 ) 的常量 const 在 类型左右 都是相同的
    const int a = 10;
    int const b = 20;

    // 左数右指 : const 在指针左边 数据是常量 , const 在指针右边 指针是常量
    // 下面两种情况 const 在指针左边 , 数据是常量 , 内存中的数据不能修改
    //      但是 , c 和 d 指针的指向可以修改
    // 下面两种情况是相同的
    const int* c;
    int const* d;

    // 左数右指 : const 在指针左边 数据是常量 , const 在指针右边 指针是常量
    // 下面的情况 const 在指针右边 , 指针是常量 , 指针地址不能修改 
    //      但是 , 指针指向的内存中的数据可以修改
    int* const e = (int*)malloc(10);

    // 左数右指 : const 在指针左边 数据是常量 , const 在指针右边 指针是常量
    // 下面两种情况 const 在指针左边和右边 , 数据和指针是常量 , 都不能修改
    // 下面两种情况是相同的
    const int* const f = (int*)malloc(10);
    int const* const g = (int*)malloc(10);

    return 0;
}

3、const 关键字使用场景

const 关键字 一般用于修饰 函数参数 , 给函数传入的参数 如果不想 用户在方法中 修改 数据 或 指针 , 可以使用 const 关键字修饰 形参 ;

定义结构体 :

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
struct Student
{
    char name[64];
    int age;
};

函数接收上述结构体类型变量作为参数 , 如果参数中 const 在 * 左边 , const Student *pS , 根据 左数右指原则 , 指针指向的数据是常量 , 不能被修改 ;

下面是错误示范 :

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 左数右指 , const 在指针左边 , 指针指向的数据不能被修改
int fun0(const Student *pS) {
    pS->age = 20;
    return 0;
}

如果强行修改指针指向的数据值 , 就会在编译时报错 :

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
表达式必须是可修改的左值

函数接收上述结构体类型变量作为参数 , 如果参数中 const 在 * 右边 , Student* const pS , 根据 左数右指原则 , 指针本身是常量 , 指针指向不能被修改 ;

下面是错误示范 :

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 左数右指 , const 在指针右边 , 指针本身的指向不能被修改
int fun2(Student* const pS) {
    pS = NULL;
    return 0;
}

如果强行修改指针指向 , 就会在编译时报错 :

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
表达式必须是可修改的左值

上述完整代码示例 :

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 导入标准 io 流头文件
// 其中定义了 std 命名空间
//#include <iostream>
// 导入 std 命名空间
//using namespace std;

#include <stdio.h>
#include <malloc.h>

struct Student
{
    char name[64];
    int age;
};

// 左数右指 , const 在指针左边 , 指针指向的数据不能被修改
int fun0(const Student *pS) {
    //pS->age = 20;
    return 0;
}

// 左数右指 , const 在指针右边 , 指针本身的指向不能被修改
int fun2(Student* const pS) {
    //pS = NULL;
    return 0;
}


int main() {

    // 下面两种 const 用法效果相同
    // 定义普通类型 ( 非指针类型 ) 的常量 const 在 类型左右 都是相同的
    const int a = 10;
    int const b = 20;

    // 左数右指 : const 在指针左边 数据是常量 , const 在指针右边 指针是常量
    // 下面两种情况 const 在指针左边 , 数据是常量 , 内存中的数据不能修改
    //      但是 , c 和 d 指针的指向可以修改
    // 下面两种情况是相同的
    const int* c;
    int const* d;

    // 左数右指 : const 在指针左边 数据是常量 , const 在指针右边 指针是常量
    // 下面的情况 const 在指针右边 , 指针是常量 , 指针地址不能修改 
    //      但是 , 指针指向的内存中的数据可以修改
    int* const e = (int*)malloc(10);

    // 左数右指 : const 在指针左边 数据是常量 , const 在指针右边 指针是常量
    // 下面两种情况 const 在指针左边和右边 , 数据和指针是常量 , 都不能修改
    // 下面两种情况是相同的
    const int* const f = (int*)malloc(10);
    int const* const g = (int*)malloc(10);


    return 0;
}

二、C 语言 const 关键字原理分析


1、C 语言中常量的原理和缺陷

C 语言中的 const 关键字 并不是 真正的 " 常量 " , 是一个 " 冒牌货 " ;

C 语言中的 const 关键字定义的常量 , 其本质是在 内存 中分配的空间 ;

C 语言 中 , 会为 const 常量 单独分配内存 , 导致 用户可以 通过取地址符 & 获取该内存的地址指针 , 通过该指针可以修改内存中的数据 ;

2、代码示例 - C 语言中直接改变常量值报错

定义一个常量 const int a = 10; , 为该常量值 a 赋值 , 会报错 error: assignment of read-only variable 'a' ;

代码示例 :

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include <stdio.h>

int main() {

    // 定义常量
    const int a = 10;

    // 下面的代码会报错 , 貌似 a 是常量
    a = 20;

    return 0;
}

编译时的报错信息 :

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
C:\Users\octop\Desktop>gcc hello.c
hello.c: In function 'main':
hello.c:9:7: error: assignment of read-only variable 'a'
     a = 20;
       ^

C:\Users\octop\Desktop>

3、代码示例 - C 语言中使用常量地址修改常量值

如果使用 指针 变量 , 接收 常量 a 的地址 , 然后通过该指针修改 指针指向的 内存空间的值 , 然后再打印 常量 a 的值 , 发现 常量 a 的值发生了改变 ;

因此 , C 语言中的常量 , 是可以通过指针进行修改的 ;

代码示例 :

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include <stdio.h>

int main() {

    // 定义常量
    const int a = 10;

    // 下面的代码会报错 , 貌似 a 是常量
    //a = 20;

    // 定义一个指针
    int* p = NULL;
    // 将 常量 a 的地址赋值给指针
    p = (int *)&a;

    // 通过指针修改 常量 a 的值
    *p = 20;

    // 打印 a 的值
    printf("a = %d\n", a);

    return 0;
}

执行结果 :

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
C:\Users\octop\Desktop>gcc hello.c

C:\Users\octop\Desktop>a.exe
a = 20

C:\Users\octop\Desktop>

将相同的代码 , 拷贝到 C++ 环境中 , 编译运行的结果 , 与 C 语言环境中的编译运行结果不同

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
a = 10

Y:\002_WorkSpace\002_VS\HelloWorld\HelloWorld\Debug\HelloWorld.exe (进程 18604)已退出,代码为 0。
要在调试停止时自动关闭控制台,请启用“工具”->“选项”->“调试”->“调试停止时自动关闭控制台”。
按任意键关闭此窗口. . .

出现上述问题 , 是因为 C 语言 中 , 会为 const 常量 单独分配内存 , 导致 用户可以 通过取地址符 & 获取该内存的地址指针 , 通过该指针可以修改内存中的数据 ;

三、C++ 语言 const 关键字 - 符号表存储常量


1、C++ 语言中常量原理

C++ 语言中 使用 const 关键字 定义的常量 , 是真正的 " 常量 " ;

C++ 编译器 对 const 关键字 修饰 的常量 , 进行了 特殊处理 ;

C++ 编译器 扫描到 const int a = 10; 代码后 , 发现 const 常量 , 不会为其单独分配内存 , 而是 将 常量 a 放在 符号表 中 ,

符号表 中的数据是以 " 键值对 " 的形式存在的 , 一个 键 Key , 对应一个值 Value ;

反映到 const int a = 10; 代码中 , 键 Key 是 a , 值 Value 是 10 , 在之后的代码 使用 常量 a 时 , 会直 从 符号表 中取出 10 ;

在下面的代码中 , 使用指针 p 获取 常量 a 的地址 , 获取的并不是 符号表 中 常量 a 的地址 , 而是 从 符号表中 取出常量 const int a = 10 , 为其 分配一个内存空间 , 将 10 存进去 , 然后将首地址返回 赋值给指针 p ;

实际上 指针 p 指向的是一个内存空间 , 内存空间中的值是 常量 a 的值 , 但是此时与常量 a 没有关系了 , 该值可以被修改 ;

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    // 定义常量
    const int a = 10;

    // 下面的代码会报错 , 貌似 a 是常量
    //a = 20;

    // 定义一个指针
    int* p = NULL;
    // 将 常量 a 的地址赋值给指针
    p = (int *)&a;

    // 通过指针修改 常量 a 的值
    *p = 20;

对比 C 语言 中 , 会为 const 常量 单独分配内存 , 导致 用户可以 通过取地址符 & 获取该内存的地址指针 , 通过该指针可以修改内存中的数据 ;

2、代码示例 - 分析指针指向的值和实际常量值

修改上述代码 , 在不同的时间获取 *p 指向的内存空间值 和 常量 a 的值 ;

发现 使用指针 接收 常量 a 的地址 , 是在内存中重新分配内存并赋值为 10 , 并没有获取到符号表的内存地址 ;

修改内存中的值 , 不会影响到 符号表 中常量 a 的值 ;

代码示例 :

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include <stdio.h>

int main() {

    // 定义常量
    // 该常量定义在了 符号表 中
    // 符号表 不在内存四区中 , 是另外一种机制
    const int a = 10;

    // 下面的代码会报错 , 貌似 a 是常量
    //a = 20;

    // 定义一个指针
    int* p = NULL;
    // 将 常量 a 的地址赋值给指针
    // 在 堆内存中重新 分配一个 4 字节的空间 
    // 将 常量 a 的值 10 存储进去
    p = (int *)&a;

    // 打印 a 和 *p 的值
    // 此时 还没有修改 *p 的值 , 两个值都是 10
    printf("a = %d , *p = %d\n", a, *p);

    // 通过指针修改 常量 a 的值
    *p = 20;

    // 打印 a 和 *p 的值
    // 此时 通过你指针修改了 *p 的值 , *p 是 20 , 常量 a 仍为 10
    printf("a = %d , *p = %d\n", a, *p);

    return 0;
}

执行结果 :

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2023-08-20,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
【C++】const关键字
实际上和const修饰结构体一样,当需要打印数据时,并且当数据量太大,不想复制一份数据到内存空间时,就传一个地址或者引用,此时形参改变,实参也会跟着改变,所以此时需要防止实参被修改!
后端码匠
2023/02/27
5010
【C++】const关键字
AboutCPlusPlus之const关键字
const 是 constant 的缩写,本意是不变的,不易改变的意思。在 C++ 中用来修饰内置类型变量、自定义对象、成员函数、返回值、函数参数。
王强
2021/04/29
5780
【专业技术第二讲】c语言中const的使用
这里对const的使用做一个大致的总结。 C语言的const关键字与指针搭配使用,const是C语言中保留的一个关键字,它用来限定一个变量是只读的,即不可变的。程序中使用const可以在一定程度上提高
程序员互动联盟
2018/03/14
7970
【专业技术第二讲】c语言中const的使用
【C 语言】const 关键字用法 ( 常量指针 - const 在 * 左边 - 修饰数据类型 - 内存不变 | 指针常量 - const 在 * 右边 - 修饰变量 - 指针不变 )
const 关键字 在 C 和 C++ 中的表现不同 , 本篇博客主要介绍 C 语言中的 const 用法 ;
韩曙亮
2023/03/29
3.3K0
C++基础语法重点总结
函数重载指的是在同一个作用域中,声明了具有相同函数名的函数,它们的参数列表不同,也就是说参数类型不同,参数个数不同,参数顺序不同,返回值同不同都可以。
二肥是只大懒蓝猫
2023/10/13
2430
c++中的const和volatile知识自我总结
1、const限制一个变量不能修改其内容,如果强行修改的话,如下面代码这样子,编译就会报错,“表达式必须是可修改的左值”。
chenjx85
2019/05/06
6270
C语言中const关键字的妙用总结
学习了多年的C语言,你对const关键字的使用全都掌握了吗?在编程实践中你对const的使用是否有困惑呢?今天就给大家一起来探讨总结,期望能够大家解惑并提供参考。
狼啸风云
2021/03/23
1.4K0
C++ const详解
常量在C++中经常用到,用关键字const表示,它是常数变量,也就是说,它仍然是变量,而不是常数。什么区别呢?编译器会为变量在内存中分配地址空间,而常数是编译器在编译过程中记录在内存表里一个实体。
猫叔Rex
2020/06/29
6620
初识C++
最近颓废了很多,不想深入去学习,直接开始摆烂,但是好在瘦了10斤,还是不错的,也不是所有的事情下降了都是坏事。
是小张啊喂
2022/08/18
1770
define与const关键字的多种用法
这将创建一个名为 SQUARE 的宏,它接受一个参数 x,并返回 x * x 的结果。比如可以在代码中使用 SQUARE(5) 来得到 5 的平方。
SarPro
2024/02/20
1530
C++ 面试必备:常见 C++ 面试题汇总及详细解析
C++是C的超集,也就是说,C++包括了C的所有基础特性,并且还增加了一些新的特性。下面列举一些C和C++之间的主要区别:
小万哥
2023/03/31
2.3K0
C++ 面试必备:常见 C++ 面试题汇总及详细解析
C++必知必会之基础知识-常用关键字(1)
Hello,大家好!我是木荣。温故而知新,可以为师矣。作为一名攻城狮,扎实的基本功是解决问题及完成工作中任务的重要前提。没有良好的基本功作为铺垫,一味的追求知识的宽度是毫无意义,知其然更要知其所以然。因此,在平时和小伙伴们聊天时,在谈到学习技术方面的问题,我会告诉他们注重基本功。所以,最近文章会总结一些日常编程工作中常用的重要基本知识点,根据平时工作中常用的也是重要的知识点逐步展开。
Linux兵工厂
2023/09/15
2310
C++必知必会之基础知识-常用关键字(1)
指针(二) - (const)指针与常量
const使用 声明一个常量 关键字const用来告诉编译器一个一旦被初始化过的变量就不能被修改 int a; const int n; 一 常量指针 指针指向一个常量 修饰指针指向 #include int main() { //常量指针 const int num = 10; // num = 100; int* p1 = &num; *p1 = 100; printf("%d\n", num); // 可以通过p1修改num (c语言可以c++不可以) // 不可以通过p2,p3修
木杉乀
2021/04/02
4280
【C++】类型转换 ⑤ ( 常量和非常量之间的类型转换 - 常量类型转换 const_cast | const 左数右指原则 | 代码示例 )
在之前写过一篇 C++ 类型转换的博客 【C++ 语言】类型转换 ( 转换操作符 | const_cast | static_cast | dynamic_cast | reinterpret_cast | 字符串转换 ) , 简单介绍了 C++ 类型转换 ;
韩曙亮
2023/11/29
5360
【C++】类型转换 ⑤ ( 常量和非常量之间的类型转换 - 常量类型转换 const_cast | const 左数右指原则 | 代码示例 )
【C语言】const 关键字详解
const关键字在C语言中用于定义常量,提供只读的变量。这意味着一旦初始化,const变量的值不能再被修改。下面详细介绍const关键字的用法、作用以及其在不同上下文中的应用。
LuckiBit
2024/12/07
3280
【C语言】const 关键字详解
【C++】C++ 类中的 this 指针用法 ② ( 常量成员函数 | const 修饰成员函数分析 )
在 C++ 类中 , 普通的非静态成员函数 , 可以使用 const 进行修饰 ,
韩曙亮
2023/10/15
4010
【C++】C++ 类中的 this 指针用法 ② ( 常量成员函数 | const 修饰成员函数分析 )
C++中Const常量机制分析
const为C/C++常用的修饰符,表示该变量是一个常量,不可被修改等含义。那么在实际使用中会存在如下疑问:
洛杉矶
2018/06/08
2.5K0
C/C++关键字详解-----`const`的使用
作为一个关键词,你可以将 const 视为对数据的权限控制机制之一,它主要用于限制数据的可变性,从而提高代码的安全性和可靠性。通过使用 const,可以缩小对数据的修改权限,确保数据在某些情况下不被意外修改。
薄荷冰
2024/03/11
2220
C++:18---const关键字(附常量指针、指针常量、常量指针常量)
一、const变量的一些基本特点 ①const修饰的变量不能被修改 const int a=10;a=20;//错误 ②因为const修饰的变量不能被修改,所以必须被初始化 int a=10;const int b=a; //正确const int c=10; //正确 ③const修饰的变量可以赋值给其他值 const int a=10;int b=a;//正确 ④可以有常量引用 int a=10;const int &b=a; 二、在其他文件中使用const常量(extern) const常量默
用户3479834
2021/02/03
1.4K0
C++ 中 const 和 constexpr关键字解析:常量、函数和指针
这是最基本的一种用法,顾名思义,就是将该变量修饰为常量,从而不可以修改。很多的全局变量都是通过常量来进行修饰,需要注意的是,使用const关键字修饰的变量需要立刻初始化
小万哥
2023/02/24
1.1K0
C++ 中 const 和 constexpr关键字解析:常量、函数和指针
推荐阅读
相关推荐
【C++】const关键字
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验