IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> C语言中关于const关键字的用法及详解 -> 正文阅读

[C++知识库]C语言中关于const关键字的用法及详解

本人在读《C陷阱与缺陷》时遇到了这样一个问题:(a++)++,因为a++的结果不能作为左值,所以不能编译器不会接受a++作为后面的++运算符的操作数。想到左值,不禁难以想起const的用法,又写下了下面一些关于const的用法及详解

前言:C90标准新增了const关键字,用于限定一个变量为只读,const类型限定符声明的是变量,不是常量,使其成为一个只读值,也就是说可以在计算中使用它,也可以打印它,但是不能改变它的值,并且,const推出的初始目的就是为了取代预编译指令,消除它的缺点同时继承它的优点。

目录:1.什么是const?

?2.const与#define指令的对比

3.const与static的对比

4.const的用法

? ? 1.修饰局部变量

? ? 2.修饰全局变量

? ? 3.变量指针,指针变量与指向常量的常指针

? ? 4.拓展到作为函数参数的思考

一.我们先来介绍一下什么是const:

我们通常用类型和存储类别来描述一个变量。C90还新增了两个属性:恒常性(constancy)和易变形(volatility),两个关键字const和volatile,以这两个关键字创建的类型是限定类型(qualified type)今天我们所讲的关键字const就是来声明恒常性的,通常有很多地方也把修饰的变量叫做常变量(即给一个变量赋予恒常性,处理时当常量来看待)。????????

C99标准为类型限定符增加了一个新属性,他们具有幂等性质,意思是在一条声明中多次使用同一个限定符,多余的限定符将被忽略:

const const const int n=6;
//与const int n=6;相同

有了这个新属性,就可以编写类似下面代码:

typedef const int zip;
const zip q=8;

二.const与#define指令相比的优点:

如果一个变量被const修饰,那么他的值就不能再改变,那么有人会提出这样的疑问,C语言中不是有#define嘛?干嘛还要用const呢?所以比较之后又如下优点:

1.预编译指令只是对值进行简单的替换,不能进行类型检查。

2.可以保护被修饰的变量,防止意外修改,增强程序的健壮性。

3.在C++语言中编译器通常不为普通的const常量分配存储空间,而是将它们保存在符号表中,这使得它成为一个编译期间的常量,没有了存储与读内存的操作,使得它的效率也很高。

三.const与static的对比

static修饰的变量为静态变量,存储再全局(静态)区,生命周期从程序编译到运行结束。

const修饰的变量不会存放在全局(静态)区,而是取决于它定义的地方,局部定义的就存在栈区,全局定义的就存放在静态区。

四.const修饰局部变量的用法如下:

1.const修饰过的变量不能直接的改变。

const int nochange;  //限定nochange的值不能改变,系统为其自动分配一个值,大多数情况为0
nochange = 12;   //编译器不允许

2.可以初始化const变量。

初始化后就不能改变他的值了,也就是不能再次重定义或者再次初始化这个变量。

const int nochange = 12;//初始化nochange没问题

3.const关键字创建不允许修改的数组:

const int arr[10]={0,1,2,3,4,5,6,7,8,9}

如果使用C99之后的编译器,还可以创建如下数组:

const int a=10;
int arr[a]={1,2,3,4,5,6,7,8,9};

此时数组内有a=10个元素,这个a我们不能改变它了,但是这个数组我们并没有用const修饰,所以我们可以进行以下操作:

arr[4]=5;

如果我们不希望数组可以改变,那我们得在数组前加一个const限定符:const int arr[a]?

4.const修饰一个常量静态字符串:

const char *str="helloworld"

如果没有const修饰那么可以有意无意的将str[1]='x'这样的操作,但是加上const之后,这个错误就能在程序被编译的时候立即检查出来,这就是const的好处。让逻辑错误能够在编译器发现。

const修饰全局变量的用法如下:

使用全局变量是一种冒险的方法,因为这样做暴露了数据,程序的任何部分都能修改数据。如果把数据设置为const,就可以避免这样的危险,因此使用const限定符声明全局变量很合理。可以创建const变量,const数组,const结构。

当然,在文件之间共享const数据要小心。可以采用两个策略:

第一,遵循外部变量的使用规则,即在一个文件中使用定义式声明。在其他文件中使用引用式声明(即用extern关键字)。

第二,把const变量放在一个头文件中,然后在其他文件中包含此头文件即可。但是这种方案必须要求在头文件中使用关键字static声明全局const变量。因为如果去掉static变量,那么假设两个文件 file1.c 和 file2.c 使用了同一个头文件constant.h? 那么将导致每个文件中都有一个相同的标识符的定义式声明,C标准不允许(虽然有些编译器允许)这么做。加上static关键字实际上是给每个文件都提供了一个单独的数据副本,每个副本只对该文件可用。

两种方案,方案二使用头文件的好处是方便你偷懒,不用惦记着在一个文件中使用定义式声明,另一个文件中使用引用式声明,只需要包含同一个头文件即可,但是缺点也有,就是导致数据是重复的,如果头文件中某个static const修饰的变量过于庞大,就会出现一些问题。

变量指针,指针变量与指向常量的常指针:

常量指针是指针指向的内容是常量,下面两种定义方式是相同的:

const int *n;
int const *n;

常量指针说的是不能通过这个指针改变变量的值(但是可以通过其他方式改变变量的值)。

int a=5;
const int* n=&a;
a=6;
printf("%d",a); //此时打印出来a=6
*n=7;//报错,*n是不可修改的左值
printf(“%d”,a); //通过指针解引用的方式找到a的值去改变,这种方法不可行,因为定义了常量指针

还有一点重要的是常量指针指向的值不能改变,但是这部意味着指针本身不能改变,常量指针也可以指向其他地方的地址。

int a=5;
int b=6;
const int*n=&a;
n=&b;

指针常量是指指针本身是个常量,不能再指向其他的地址,写法如下: int? * const n;

如下是使用的例子

int a=5;
int b=6;
int *const n=&a;
printf("%d",a);
*n=7;
printf("%d",a);  //此时可以打印出来a的值为7,也就是可以通过指针解引用的方式改变指向的值
n=&b; //此时报错,不允许,因为定义了指针常量

我们不难发现指针常量和常量指针的区别就在于星号的位置:

int const *n是常量指针? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?? ? ? ?int * const n是指针常量

指向常量的常指针

是以上两者的结合,写法如下

const int * const ptr;

指针ptr指向的位置不能改变,并且也不能通过指针ptr改变变量的值,但是依然可以通过其他的变量指针(例如再定义一个指针*p指向同一个值a,可以通过指针*p来操作这个值)改变变量的值。

? 拓展到作为函数参数的思考:

根据以上的讨论那么const修饰函数的参数也有三种用法:

1.防止修改指针指向的内容:

int Add(const int *a,const int *b,int sum);

其中a和b是输入的参数,sum是待输出的参数。给a和b加上const修饰后,如果函数体内的语句试图改动a和b的内容,编译器将报错。

2.防止修改指针指向的地址:

int swap(int *const p1,int * const p2);

指针p1和指针p2指向的地址都不能改变。

3.即防止修改指针指向的内容,又防止修改指针指向的地址;

例如 void sort(int const *const p1,int const *const p2?);

拓展到作为函数返回值的思考:

C标准定义了如下规则

把const数据或非const数据的地址初始化为指向const的指针或为其赋值的合法的。

int arr1[3]={0,1,2};
const int arr2[3]={3,4,5};
const int *a=arr1; //合理
a=arr2;  //合理
a=&arr1[2];  //合理

但是只能把非const数据的地址赋给普通指针。

int arr1[3]={0,1,2};
const int arr2[3]={3,4,5};
int *a=arr1; //合理
a=arr2;  //不合理
a=&arr1[2];  //合理

这个规则十分合理,否则,通过指针就能改变const数组中的数据。

总结:const限定符经常常用,学以致用const是变成大佬路上必须要学会的操作!但是众多细节不能忽略,仔细分析const用在哪里,联系它的不同用法。

最后还有一点关于引起我思考问题的解答,(a++)这个操作是创建一个a的副本进行运算,原来的a再自增,所以参加运算的那部分地址是临时创建的,不能作为左值。但是(++a)是直接对a进行自增操作再运用的,所以这个可以用来作为左值。

创作不易,麻烦各位读者点个赞或者关注激励一下作者!

?

?

?

?

?

?

?

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-10-31 11:35:33  更:2022-10-31 11:37:39 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/19 6:00:41-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码