C语言const关键字详解

C语言const关键字详解const 在实际编程中用得并不多 const 是 constant 的缩写 意思是 恒定不变的 它是定义只读变量的关键字 或者说 const 是定义常变量的关键字 说 const 定义的是变量 但又相当于常量 说它定义的是常量 但又有变量的属性 所以叫常变量 用 const 定义常变量的方法很简单 就在通常定义变量时前面加 const 即可 如 constinta 10 con

C语言的const关键字

const 在实际编程中用得并不多,const 是 constant 的缩写,意思是“恒定不变的”!它是定义只读变量的关键字,或者说 const 是定义常变量的关键字。

说 const 定义的是变量,但又相当于常量;说它定义的是常量,但又有变量的属性,所以叫常变量。用 const 定义常变量的方法很简单,就在通常定义变量时前面加 const 即可,如:

const int a = 10; 

const 和变量类型 int 可以互换位置,二者是等价的,即上条语句等价于:

int const a = 10; 

那么用 const 修饰后和未修饰前有什么区别呢?它们不都等于 10 吗?

用 const 定义的变量的值是不允许改变的,即不允许给它重新赋值,即使是赋相同的值也不可以。所以说它定义的是只读变量。这也就意味着必须在定义的时候就给它赋初值。

如果定义的时候未初始化,我们知道,对于未初始化的局部变量,程序在执行的时候会自动把一个很小的负数存放进去。这样后面再给它赋初值的话就是“改变它的值”了,即发生语法错误。

用 const 修饰的变量,无论是全局变量还是局部变量,生存周期都是程序运行的整个过程。全局变量的生存周期为程序运行的整个过程这个是理所当然的。而使用 const 修饰过的局部变量就有了静态特性,它的生存周期也是程序运行的整个过程。我们知道全局变量是静态的,静态的生存周期就是程序运行的整个过程。但是用const修饰过的局部变量只是有了静态特性,并没有说它变成了静态变量。

我们知道,局部变量存储在栈中,静态变量存储在静态存储区中,而经过 const 修饰过的变量存储在内存中的“只读数据段”中。只读数据段中存放着常量和只读变量等不可修改的量。

数组的长度不能是变量: 虽然 const 定义的是只读变量,就相当于是定义一个常量。但是只读变量也是变量,所以 const 定义的变量仍然不能作为数组的长度。C++ 扩展了 const 的含义,在 C++ 中用 const 定义的变量也可作为数组的长度。

const 和指针

const 也可以和指针变量一起使用,这样可以限制指针变量本身,也可以限制指针指向的数据。const 和指针一起使用会有几种不同的顺序,如下所示:

int a = 1; int b = 2; // 情况一 const int *p1 = &a; int const *p2 = &a; // 指针所指向的数据是只读的,也就是 p1、p2 本身的值可以修改(指向不同的数据),但它们指向的数据不能被修改。 // 即:  // *p1 = 3; 报错,不能修改指向的数据 // p1 = &b; 有效,可以修改变量的指向 // 情况二 int * const p3 = &a; // 指针是只读的,也就是 p3 本身的值不能被修改; // 即: // p3 = &b; 报错,不能修改指向的地址 // *p3 = 3; 有效,可以修改指向地址的值 // 情况三 // 指针本身和它指向的数据都是只读的 const int * const p4; int const * const p5; 

const 离变量名近就是用来修饰指针变量的,离变量名远就是用来修饰指针指向的数据,如果近的和远的都有,那么就同时修饰指针变量以及它指向的数据。

const 和函数形参

const 通常用在函数形参中,如果形参是一个指针,为了防止在函数内部修改指针指向的数据,就可以用 const 来限制。例如c语言标准库中的函数

size_t strlen ( const char * str ); int strcmp ( const char * str1, const char * str2 ); char * strcat ( char * destination, const char * source ); char * strcpy ( char * destination, const char * source ); 

使用 const 限制函数参数,不但可以防止数据被修改,还可以在调用的时候给予提示。

const 和非 const 类型转换

const char *char *是不同的类型,不能将const char *类型的数据赋值给char *类型的变量。但反过来是可以的,编译器允许将char *类型的数据赋值给const char *类型的变量。

char *指向的数据有读取和写入权限,而const char *指向的数据只有读取权限,降低数据的权限不会带来任何问题,但提升数据的权限就有可能发生危险。

所以下面操作行不通:

#include  
     int main(){ 
    const char *str1 = "a"; char *str2 = str1; // 报错,不能给const变量增加权限 return 0; } 

const 和 define

很多人在学习 const 的时候都会混淆它与 define 的区别。从功能上说它们确实很像,但它们又有明显的不同:

  1. define是预编译指令,而const是普通变量的定义。define定义的宏是在预处理阶段展开的,而const定义的只读变量是在编译运行阶段使用的。
  2. const定义的是变量,而define定义的是常量。define定义的宏在编译后就不存在了,它不占用内存,因为它不是变量,系统只会给变量分配内存。但const定义的常变量本质上仍然是一个变量,具有变量的基本属性,有类型、占用存储单元。
  3. const定义的是变量,而宏定义的是常量,所以const定义的对象有数据类型,而宏定义的对象没有数据类型。所以编译器可以对前者进行类型安全检查,而对后者只是机械地进行字符替换,没有类型安全检查。这样就很容易出问题,即“边际问题”或者说是“括号问题”。

与C++区别

在c++中,一个const不必创建内存空间,而在c中,一个const总是需要一块内存空间。

c++中用const定义了一个常量后,将其写入符号表(symbol table),这使得它成为一个编译期间的常量,没有给变量分配内存,也没有了存储与读内存的操作,使得它的效率也很高。

int main(){ const int a = 2; int* p = (int*)(&a); *p = 30; // 直接修改const常量对应的内存空间中的值 cout<<&a< 
  

运行结果:

0x7fffc 0x7fffc 2 30 

通过指针修改const常量对应的内存空间中的值,这种修改不会影响到常量本身的值,因为编译器根本不会去进行内存空间的读取。这就是c++的常量折叠(constant folding),即将const常量放在符号表中,而并不给其分配内存。编译器直接进行替换优化。

除非需要用到const常量的存储空间,编译器迫不得已才会分配一个空间,但之后const常量的值仍旧从符号表中读取,所以不会影响const常量的值。

而在C语言中

int main() { 
    const int a = 2; int* p = (int*)(&a); *p = 30; printf("%x\n",&a); printf("%x\n",p); printf("%i\n",a); printf("%i\n",*p); return 0; } 

运行结果

18b1c0e4 18b1c0e4 30 30 

c语言通过指针引用可以修改const修饰变量的值。

c 与 c++ 的 const 异同总结

  • c语言全局const会被存储到只读数据段。c++中全局const当声明extern或者对变量取地址时,编译器会分配存储地址,变量存储在只读数据段。两个都受到了只读数据段的保护,不可修改。
  • c语言中局部const存储在堆栈区,只是不能通过变量直接修改const只读变量的值,但是可以跳过编译器的检查,通过指针间接修改const值。而c++则是:
    • 对于基础数据类型,把它放到符号表中,不分配内存,当对其取地址时,会分配内存。
    • 对于基础数据类型,如果用一个已经初始化的变量初始化const变量,会分配内存。
    • 对于自定数据类型,比如类对象,那么也会分配内存。
  • c中const默认为外部连接,c++中const默认为内部连接。当c语言两个文件中都有const int a的时候,编译器会报重定义的错误。而在c++中,则不会,因为c++中的const默认是内部连接的。

参考资料

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/224084.html原文链接:https://javaforall.net

(0)
上一篇 2026年3月17日 下午12:43
下一篇 2026年3月17日 下午12:44


相关推荐

  • GG修改器免root下载安装最新_安卓修改器免root版本

    GG修改器免root下载安装最新_安卓修改器免root版本gg修改器免root下载gg修改器官方网址https://gameguardian.net/官网服务器在国外访问速度有点慢,而且页面是英文,有时甚至打不开推荐中文网站,里面有最新的gg修改器下载,脚本分享,gg修改器教程,框架下载等等直达链接:竹子学习网gg修改器全名GameGuardian,是歪果仁开发的一款内存修改软件,所以可以修改有关游戏内存数据达到破坏游戏平衡的目的。被称为手游…

    2025年9月14日
    7
  • 视频 | 一步步教你操作websocket通知案例「建议收藏」

    视频 | 一步步教你操作websocket通知案例

    2022年2月13日
    47
  • 分布式系列——分布系统的一些技术

    这一个系列会总结和整理自己在公司使用的技术和一些比较流行的分布式系统用的技术! 这一个系列的学习会一直持续,让自己成长,让自己走出舒适区!看过这一句话:大部分的害怕是多数是因为懒惰!!!在路上,少年,不卑不亢!

    2022年2月25日
    57
  • 虚拟机vmware安装教程_红帽系统安装步骤

    虚拟机vmware安装教程_红帽系统安装步骤虚拟机VMware的详细安装步骤,下载

    2022年8月5日
    6
  • Symantec赛门铁克安全软件免密卸载方式[通俗易懂]

    Symantec赛门铁克安全软件免密卸载方式[通俗易懂]装了Symantec后,后面希望卸载他,结果发现卸载需要卸载口令,查了一堆资料,总结有如下几种:1、卸载口令可能是symantec,反正没成本可以简单试试看。不过我是没有通过,这个口令不对我的Symantec。2、使用cleanwipe进行卸载,这是官方的用于卸载Symantec软件的工具。工具很小,应该有版本要求,旧版的不能完成卸载。推荐使用这个方式。我用的是CleanWipe_14.3.558.1000,选中下图中框出来的三个勾,直接下一步即可完成卸载。链接:https://pan.baidu.

    2022年5月1日
    192
  • UVA 1396_UVC和UVA

    UVA 1396_UVC和UVA书上的题目,开始跟着新的大神了==#include#include#include#includeusingnamespacestd;//精度控制constdoubleeps=1e-10;intdcmp(doublex){if(fabs(x)

    2022年8月12日
    9

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号