当前位置: 首页 > news >正文

C++和C中const的区别详解

const,这个词字面意思为:常数。

这就表示这是一个不可以改变是数。同时,这也是C/C++里面的一个关键字,是一个限定符,但是const在C和C++中的用法是有区别的。

由于本人水平有限,难免会有出错的地方,如果错误,还请指正!

C中的const

const修饰局部变量

在C语言中,const修饰局部变量,那么这个变量就是“常变量”。

1

2

3

4

5

6

7

8

voidtest(){

constintb = 20;

}

intmain() {

constinta = 10;

return0;

}

上面的两个变量,无论是主函数中的a,还是普通的函数中的b,都是被从const修饰的变量,那么就是“常变量”。

“常变量”不可以直接通过变量名来对值进行修改,因为变量名被const修饰后,从原来的“可读可改”的属性,变成了只“可读”,“不可改”的属性。

1

2

3

4

5

6

7

8

9

10

voidtest(){

constintb = 20;

b = 40;//error

}

intmain() {

constinta = 10;

a = 30;//error

return0;

}

上面的行为是错误的。

但是,“常变量”本质上还是一个“变量”,而不是“常量”。

只要是被const修饰的局部变量,都是在程序运行到这一行代码的时候,才会创建这个变量并且分配空间的。

而分配空间是在栈区分配的,栈区的空间都会有对应的地址,栈区的空间是“可读可写”的。

我们可以通过地址,来对值进行修改。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

#include<stdio.h>

voidtest() {

constintb = 20;

int* pb = &b;

*pb = 40;

printf("%d\n", b);

}

intmain() {

constinta = 10;

int* pa = &a;

*pa = 30;

printf("%d\n", a);

test();

return0;

}

上面的代码输出的结果是:30和40

也就是说,不论是main函数中的还是普通函数中的局部变量,只要是被const修饰的局部变量,是可以通过地址来进行修改的。

补充

一般我们在定义一个被const修饰的变量的时候,都应该定义并且初始化,如果像上面的那样,是被const修饰的局部变量,如果我们在定义的时候不进行初始化,那么就是一个随机值,想要修改就只能通过指针了。

const修饰全局变量

const修饰的全局变量,也就是定义在函数体之外的变量,内存空间是在文字常量区的,这个内存区域是只读的,不能通过变量名去修改变量的值,也不能通过指针去修改变量的值!

1

2

3

4

5

6

7

constinta = 10;//全局变量

intmain() {

int* pa = &a;

*pa = 30;

printf("%d\n", a);

return0;

}

上面的代码时错误的,被const修饰的全局变量不能通过变量名和地址对内容进行修改,程序会报错。

const修饰的全局变量有外部链接属性

在C语言中,只要时全局变量,不论有没有被const修饰,都是默认拥有外部链接属性的,也就是说这个全局变量不仅限于在当前文件下使用,只要我们在其他文件中,加上extern的声明,也是可以使用的。

const与指针

当const修饰非指针的普通变量的时候,不论const放在类型关键字前面还是后面,表达的意思都是一样的

1

2

3

4

5

6

7

8

9

10

11

12

13

#include<stdio.h>

constintc = 5;

intconstc = 5;

voidtest() {

constintb = 20;

intconstb = 20;

}

intmain() {

constinta = 10;

intconsta = 10;

return0;

}

上面a,b,c,三个变量的两种写法表达的意思都是一样的,当然同名的变量不能重复定义,我只是演示一下而已。

当const修饰指针的时候,不同的写法会代表不同的意思。

1

2

3

4

5

6

7

8

intmain() {

constinta = 10;

//const int* pa = &a;//与下一行的代码表达的意思一样

intconst* pa = &a;

*pa = 30;

printf("%d\n", a);

return0;

}

上面的代码时有错的,const修饰指针的时候,const在*星号的左边(上面演示的两种情况都可以),那么表示的是,指针pa指向的空间的内容不可以修改,但是指针变量本身的值可以修改,也就是该指针变量可以改变指向的空间。

1

2

3

4

5

6

7

8

9

intmain() {

constinta = 10;

intb = 20;

int*constpa = &a;

*pa = 30;

pa = &b;//error

printf("%d\n", a);

return0;

}

上面的代码是错误的,const在*星号的右边,那么表示的是指针变量pa里面存放的地址不可以被修改,也就是不能修改当前指针变量所指向的空间,但是空间的内容可以通过指针来进行修改。

C++中的const

const修饰普通全局变量

与C一样,当const修饰普通的全局变量的时候,不能通过变量名和地址来修改变量的值。

另外

与C不一样的是,C语言中的const修饰的普通全局变量默认是外部链接属性的,但是在C++中被const修饰的普通全局变量是内部链接属性的。

也就是说当我们在一个文件中定义了一个如下的全局变量

1

2

3

4

constinta = 10;//定义全局变量

intmain() {

return0;

}

我们在另外一个文件中,使用extern来声明,也是不可以的。

1

2

//另外一个文件

externconstinta;//在另外的文件中声明

上面这种做法是不可以的,C++中被const修饰的全局变量默认是内部链接属性,不能直接在另外的文件中使用,如果想要在另外的文件中使用,就需要在定义该全局的变量的文件中用extern来修饰。

1

2

3

4

//定义的文件

externconstinta = 10;

//另外一个文件声明

externconstinta;

const修饰普通局部变量

如果const修饰的局部变量是基础的类型(int char double等等),并且初始化使用字面常量的话,不会给该变量分配空间。

例如:

1

2

3

4

voidtest() {

constinta = 10;//用字面常量10来初始化

a = 20;//error

}

但是,当我们对这个变量进行取地址的操作的时候,系统会为该变量分配空间。

1

2

3

4

5

6

7

8

voidtest() {

constinta = 10;

//a = 20;//error

int* p = (int*)&a;

*p = 20;

cout << a << endl;

cout << *p << endl;

}

上面的结果是:

10和20

这是因为,当我们定义一个被const修饰并且使用字面常量来初始化的局部变量的时候,系统会把这个变量看作是一个符号,放入到符号表中,这么变量名就是一个符号,值就是这个符号的值,类似于#define的作用。

当我们对这个变量取地址的时候,由于原来没有空间,就没有地址,现在需要取地址,所以才被迫分配一块空间,我们通过地址的解引用可以修改这个空间的值,这也就是为什么第二个结果为20的原因,但是如果我们还是通过变量名来访问数据的话,系统会认为这还是一个符号,直接用符号表里面的值替换。

但是!

如果初始化不是用字面常量而是用变量,那么系统会直接分配空间。

1

2

3

4

voidtest() {

intb = 20;

constinta = b;

}

这时候的a是有空间的,不会被放入到符号表中。

const与类

如果是自定义数据类型(结构体、对象)

我们在创建对象(结构体)的时候,如果这个对象是被const修饰的话,那么不管这个对象是全局的还是局部的,系统都会直接分配空间

总结

本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注脚本之家的更多内容!

const,这个词字面意思为:常数。

这就表示这是一个不可以改变是数。同时,这也是C/C++里面的一个关键字,是一个限定符,但是const在C和C++中的用法是有区别的。

由于本人水平有限,难免会有出错的地方,如果错误,还请指正!

C中的const

const修饰局部变量

在C语言中,const修饰局部变量,那么这个变量就是“常变量”。

1

2

3

4

5

6

7

8

voidtest(){

constintb = 20;

}

intmain() {

constinta = 10;

return0;

}

上面的两个变量,无论是主函数中的a,还是普通的函数中的b,都是被从const修饰的变量,那么就是“常变量”。

“常变量”不可以直接通过变量名来对值进行修改,因为变量名被const修饰后,从原来的“可读可改”的属性,变成了只“可读”,“不可改”的属性。

1

2

3

4

5

6

7

8

9

10

voidtest(){

constintb = 20;

b = 40;//error

}

intmain() {

constinta = 10;

a = 30;//error

return0;

}

上面的行为是错误的。

但是,“常变量”本质上还是一个“变量”,而不是“常量”。

只要是被const修饰的局部变量,都是在程序运行到这一行代码的时候,才会创建这个变量并且分配空间的。

而分配空间是在栈区分配的,栈区的空间都会有对应的地址,栈区的空间是“可读可写”的。

我们可以通过地址,来对值进行修改。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

#include<stdio.h>

voidtest() {

constintb = 20;

int* pb = &b;

*pb = 40;

printf("%d\n", b);

}

intmain() {

constinta = 10;

int* pa = &a;

*pa = 30;

printf("%d\n", a);

test();

return0;

}

上面的代码输出的结果是:30和40

也就是说,不论是main函数中的还是普通函数中的局部变量,只要是被const修饰的局部变量,是可以通过地址来进行修改的。

补充

一般我们在定义一个被const修饰的变量的时候,都应该定义并且初始化,如果像上面的那样,是被const修饰的局部变量,如果我们在定义的时候不进行初始化,那么就是一个随机值,想要修改就只能通过指针了。

const修饰全局变量

const修饰的全局变量,也就是定义在函数体之外的变量,内存空间是在文字常量区的,这个内存区域是只读的,不能通过变量名去修改变量的值,也不能通过指针去修改变量的值!

1

2

3

4

5

6

7

constinta = 10;//全局变量

intmain() {

int* pa = &a;

*pa = 30;

printf("%d\n", a);

return0;

}

上面的代码时错误的,被const修饰的全局变量不能通过变量名和地址对内容进行修改,程序会报错。

const修饰的全局变量有外部链接属性

在C语言中,只要时全局变量,不论有没有被const修饰,都是默认拥有外部链接属性的,也就是说这个全局变量不仅限于在当前文件下使用,只要我们在其他文件中,加上extern的声明,也是可以使用的。

const与指针

当const修饰非指针的普通变量的时候,不论const放在类型关键字前面还是后面,表达的意思都是一样的

1

2

3

4

5

6

7

8

9

10

11

12

13

#include<stdio.h>

constintc = 5;

intconstc = 5;

voidtest() {

constintb = 20;

intconstb = 20;

}

intmain() {

constinta = 10;

intconsta = 10;

return0;

}

上面a,b,c,三个变量的两种写法表达的意思都是一样的,当然同名的变量不能重复定义,我只是演示一下而已。

当const修饰指针的时候,不同的写法会代表不同的意思。

1

2

3

4

5

6

7

8

intmain() {

constinta = 10;

//const int* pa = &a;//与下一行的代码表达的意思一样

intconst* pa = &a;

*pa = 30;

printf("%d\n", a);

return0;

}

上面的代码时有错的,const修饰指针的时候,const在*星号的左边(上面演示的两种情况都可以),那么表示的是,指针pa指向的空间的内容不可以修改,但是指针变量本身的值可以修改,也就是该指针变量可以改变指向的空间。

1

2

3

4

5

6

7

8

9

intmain() {

constinta = 10;

intb = 20;

int*constpa = &a;

*pa = 30;

pa = &b;//error

printf("%d\n", a);

return0;

}

上面的代码是错误的,const在*星号的右边,那么表示的是指针变量pa里面存放的地址不可以被修改,也就是不能修改当前指针变量所指向的空间,但是空间的内容可以通过指针来进行修改。

http://www.jsqmd.com/news/1134540/

相关文章:

  • 3款主流SAR舰船检测数据集对比:LS-SSDD-v1.0 vs SSDD vs RSDD-SAR 核心差异与应用选型
  • Linux 进程管理实战:kill -9 与 kill -15 的 3 种场景选择与僵尸进程规避
  • Flask 后端时间处理 3 大场景:datetime、字符串、时间戳与SQL查询实战
  • 详解C++ cout格式化输出完全攻略
  • 手机ROM剩余空间不多时无法查阅和编写短信
  • Windows与Mac系统锁屏密码重置全攻略
  • Excel 2021 + BAT 批处理:3步实现千个文件按规则批量重命名
  • 将 Windows PC 作为网络文件共享(SMB)服务器 V2.1—— 局域网内高速传文件
  • AI设计新范式:用HTML替代Figma,构建可交互网页原型
  • COCOMO II 模型实战:3步估算软件项目工作量,误差控制在15%以内
  • SpringBoot 3 + Vue 3 前后端分离博客系统:从零搭建到部署完整指南
  • 老旧Mac系统重生指南:突破官方限制的硬件兼容方案
  • Windows 11 右键菜单修复:3种方法恢复被折叠的 Git Bash Here 选项
  • 三重降压转换器TPS65263设计与应用全解析
  • 安卓逆向实战:从加壳特征识别到Frida动态脱壳与签名算法还原
  • SpringBoot+Vue高校毕业生就业平台:从零搭建到部署的全栈毕设实战
  • GitLab Webhook 安全配置实战:签名令牌 vs 秘密令牌,3步防重放攻击
  • Codex Skills 安装与配置指南:10个必备技能提升开发效率
  • Servlet 3.0 与 JSP 2.3 实战:5分钟构建一个带登录验证的简易留言板
  • Spring Boot+Vue课程作业管理系统毕业设计实战指南
  • 作为程序员的求职,我想还是有些职业的特殊性的。程序员职业和一般的职业有很大的不同,程序员职业有其鲜明的特点::1、个人劳动 2、产品可复制。这两个特点注定了程序员有很大个人发展的空间。
  • Linux命令行操作:从基础到高效的系统管理
  • 从Harness Engineering到Hermes Agent:构建可靠、可进化AI智能体的工程实践
  • Web应用越权漏洞检测与防护实战指南
  • 锂离子电池过压保护与STM32L031C6系统设计
  • 企业微信第三方应用扫码登录 3 步实战:Spring Boot 后端 + 域名配置避坑
  • 抖音下载终极指南:5分钟搞定无水印批量下载的开源神器
  • 免费开源版图设计工具KLayout:集成电路设计的终极解决方案
  • Hadoop Web控制台安全加固实战:绕过官方Simple认证,实现Nginx反向代理密码验证
  • 深度解析HCL AppScan全场景漏洞检测:从DAST/SAST到DevSecOps实战