C++中 const的用法

目录

一.  const修饰类型

1.1const修饰一般数据类型

 1.2const修饰指针类型

1.2.1修饰常量指针

1.2.2修饰指针常量

1.2.3二者都修饰

二.  const在.c和.cpp文件中的区别

三. 常变量和指针

四. 全局变量与局部变量的初始化 

4.1 普通变量的初始化

 4.2 常性变量的初始化

4.3 指针的初始化

4.4例题分析


“const”在C++中用来修饰一个变量变为常量,本篇文章我们来介绍一下const的具体用法。

一.  const修饰类型

1.1const修饰一般数据类型

const int a{ 10 };
int const a{ 10 };              //与上面等价
const int arr[10]{ 1,2,3 };
int const arr[10]{ 1,2,3 };     //与上面等价

其中,const都在a左边,即修饰的是变量a为常量,不可修改其值,即只可读不可写。

注:这里没有a = 10,而是a{10},因为c++对于变量的赋值可以直接用{},

#include<iostream>
typedef struct Stduent
{
	char s_id[20];
	char s_name[20];
	int s_age;
}Student;
int main()
{
	int a{ 10 };
	int* p{ NULL };
	int arr[10]{ 1,2,3 };
	Student s1{ "200409","lihua",18 };

}

 1.2const修饰指针类型

1.2.1修饰常量指针

int a{ 10 };
int b{ 20 };
const int* p = &a;
*p = 20;           //err

p = &b;            //right

指针有两个值,分别为指针本身的值和解引用的值。 

当const在*p的左边时,代表了*p是常量不可改变其值,而*p是解引用的意思,所以不能通过解引用来修改a的值,但是可以修改指针本身的值让其指向b的地址。

1.2.2修饰指针常量

int a{ 10 };
int b{ 20 };
int* const p = &a;
p = &b;              //err

*p = 20;             //right

当const在p的左边,在*右边时,代表p本身是常量不可改变,所以不能修改指针的指向来修改值,但可以通过解引用来修改。

1.2.3二者都修饰

int a{ 10 };
int b{ 20 };
const int* const p = &a;
p = &b;         //err
*p = 20;        //err

当两边都有const时,代表了指针本身不能修改并且也无法通过解引用改变其值。

二.  const在.c和.cpp文件中的区别

 我们知道,在vs2019中 , .c文件运用的是c语言编译政策,.cpp文件运用的是c++编译政策,二者有一些明显区别。

1.

#include<stdio.h>
int main()
{
	const int a = 10;
	int* p = (int*)&a;
	int b = 0;
	*p = 100;
	b = a;
	printf("a=%d  b=%d  *p=%d", a, b, *p);
}

该代码在.c文件下运行结果是

而在.cpp文件下运行的结果却是

 为什么会出现这样的情况呢?

        这是因为我们编写的是源码,而源码是计算机无法直接执行的,而是需要经过预编译、编译、汇编才能生成计算机可以执行的二进制码,而在这个过程中,由于.c和.cpp的编译政策不一样,导致最终的可执行代码也不一样。

当我们将代码运行后转到反汇编时就会发现,

在.cpp中

0A在十六进制中的数值为10,即把10传给b而不是把a传给b,这样就会导致b等于一个确定的值不会改变,而因为编译政策的不同,const  int  a  =  10  在c++中以常量为主,所以a的值也不会变。

在.c中

这里是把a先传递给cpu的寄存器,再将寄存器中的数据传给b,使得b的值为a,而 const  int  a  =  10在c语言中以变量为主,当*p解引用时,a的值也会随之改变。

2.

我们再来看这样一个代码

const int len = 10;
int ar[len] = { 1,2,3,4 };

这个代码在.c文件下编译出现错误,因为c语言中const 还是以变量为主,而数组元素的个数必须为常量。

在 .cpp文件下编译通过,因为c++中const以常量为主。

三. 常变量和指针

在.cpp文件

const int a = 10;
int* p1 = &a;  //err

const int* p2 = &a; //ok

int const* p3 = &a; //ok

int* const p4 = &a; //err

const int * const *p5 = &a; //ok

第一个错误的原因是 p1指针没有进行限定,导致可以解引用改变a的值,而a是常量无法更改其值。

第二个正确,因为const在*p2左边,意思是无法通过解引用改变a的值。

第三个和第二个同理。

第四个错误的原因是const在p4左边,在*右边,表示对指针本身进行了一个常量限定,而仍然可以通过解引用改变值,而a的值是常量无法更改。

第五个与第二个同理。

如果一定要用第一个编译通过,可以进行强转。

int *p1 = (int*) &a;

但是这样并不安全,因为这样可以通过解引用改变a的值,而a是一个常量,二者相矛盾。

安全的做法是

int* p5 = const_cast<int*>(&a);

这样做可以将a变量的常性去掉给*p,这样*p就可以通过解引用来改变a的值。

四. 全局变量与局部变量的初始化 

 在编写代码的过程中,如果没有对全局变量和局部变量进行赋值,那么系统自动给他们的初始值是多少?

4.1 普通变量的初始化

#include<stdio.h>
typedef struct Student
{
	char s_id[2];
	char s_name[2];
	int s_age;
}Student;
int g_max;
double g_dx;
Student s1;
int main()
{
	int a;
	double dx;
	Student s2;
	return 0;
}

我们定义了全局变量g_max,g_dx,s1,局部变量a,dx,s2,程序运行后,对他们的值进行监视

全局变量:

局部变量:

由此得出结论:全局变量未初始化时,系统自动初始化为0;而局部变量未初始化时,系统初始化为随机值。

 4.2 常性变量的初始化

#include<stdio.h>
typedef struct Student
{
	char s_id[2];
	char s_name[2];
	int s_age;
}Student;
const int g_max;
const double g_dx;
const Student s1;
int main()
{
	const int a;
	const double dx;
	const Student s2;
	return 0;
}

程序编译出现错误,原因是没有给一个初始值。

注:对于内置类型,不管是全局变量还是局部变量,只要加了常性修饰,就必须要对其赋值进行初始化。

        但是对于自己设计的类型,如果是全局变量,加了常性修饰后,如果就算不对其进行初始化,系统将自动赋值为0;如果是局部变量,则是随机值。

#include<stdio.h>
typedef struct Student
{
	char s_id[2];
	char s_name[2];
	int s_age;
}Student;
const Student s1;
int main()
{
	const Student* ip = &s1;
	const Student s2;
	return 0;
}

4.3 指针的初始化

const int* ip;  //ok

int* const sp;  //err

第一个是可以编译通过的:虽然对*ip进行常量限定,无法通过解引用改变其值,但是可以给指针本身进行赋值,如 ip = &a。

第二个无法编译通过:对sp本身进行限定,无法指向一个有效的地址空间,定义这样的指针没有任何意义,所以对于这样的指针必须要进行赋值才能编译通过 ( int*  const  sp  =  &a    //ok )

4.4例题分析

int main()
{
	int a = 10, b = 20;
	const int* p = &a;
	int* s1 = p;                   //1   err
	const int* s2 = p;             //2   ok 
	int* const s3 = p;             //3   err
	const int* const s4 = p;       //4   ok
}

1. 由于s1没有加const修饰,可以通过解引用改变,而p不能解引用。

2. p与s2都无法解引用改变其值。

3. s3虽然可以改变自身的指向,但它还是不能解引用与p违背。

4.与2相同。

int main()
{
	int a = 10, b = 20;
	int * const p = &a;
	int* s1 = p;               //1    ok
	const int* s2 = p;         //2    ok
	int* const s3 = p;         //3    ok
	const int* const s4 = p;   //4   ok
}

1. s1可以改变指向指向别的值,如s1=&b,但并不会影响p的改变。

2. s2可以改变指向但不影响p的改变。

3. p和s3都不能改变自身的指向。

4. 与3相同。

  • 29
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

GIN琴

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值