浅谈C/C++的常量const、指针和引用问题

今天我们来探讨C/C++中const、指针和引用的相关问题。这些概念是编程中的重要组成部分,它们的正确使用对于代码的可读性和可维护性至关重要。通过深入了解const的不可变性、指针的灵活性以及引用的简洁性,我们能够更好地掌握编程的精髓,并写出更加健壮和高效的代码😊😊😊

浅谈C/C++

    • (1)const + 一级指针
    • (2)const + 二级(多级)指针
    • (3)引用操作符 &

先来看看对const的描述,C/C++中的const关键字用于声明一个常变量,即一个“不可修改的值”,通过使用关键字const,我们可以明确地指定一个变量、函数参数、函数返回值或类成员函数为只读,从而禁止对其进行修改,增强程序的健壮性。可见我们对于 const 的描述,常见为一个不可修改!!!,但在C和C++中,编译器对于 const 的反应也是 有差异的

1、我们先来看看.c文件 -》 C语言中的const,猜猜有何问题?

#include<stdio.h>
int main()
{
	const int a;
	int array[a] = { 0 };

	const int b = 0;
	b = 5;

	int* p = (int*)&a; 
	*p = 30;

	printf("%d %d %d\n", a, *p, *(&a));
}

我们不难想到

  • array[a] 会报错,因为a没有被初始化,定义数组需要有一个常量值作为数组的长度,而a不可推测;
  • b = 5,变量b为常变量,不可被修改
  • 然而,对于涉及到变量p的语句,朋友是否有些疑惑🤔🤔🤔,p是指向变量a地址的普通指针,而*p = 30就是将它指向的地址上对应的值改为30,即分配给变量a的地址空间中的值 被改了🤣🤣🤣,我们去掉错误语句,加上a = 20后,看看执行的结果
    在这里插入图片描述

由此可见,我们可以归纳出 C语言编译器 下有关const的特性

		在C语言编译器中
a) const修饰可以不进行初始化,被看作常变量
b) 被const修饰的变量只是不能作为左值被修改,通过指针或引用的方式能够修改


2、我们再来看看.cpp文件 -》C++语言中的const,猜猜有何问题?

int main()
{
	const int b;

	int c = 5;

	const int a = c;
	//const int a = 20;
	int array[a] = { 0 };

	int before = a;

	int* p = (int*)&a; 
	*p = 30; 

	int after = *(int*) & a;

	cout << before << endl << after << endl; 

	cout << a << " " << *p << " " << *(&a) << endl;

	return 0;
}

不难想到

  • const int b;会报错,因为在C++中const修饰的变量被看作常量,不能够不对它进行初始化
  • array[a]报错,变量a为变量c赋值而来,而c是一个变量,赋给变量a后,变量a也作为变量,而array[]里需要一个常量,所以出现错误,如下图
    在这里插入图片描述
    除去错误语句,把const int a = 20后的执行结果在这里插入图片描述

由此我们可以了解到

		在C++语言编译器中
a) const修饰的变量必须初始化,不能作为左值
b) 被const修饰的变量只是不能作为左值被修改,通过指针或引用的方式能够修改
c) 被const修饰的变量被叫做常量,若直接赋值一个变量,不能直接作为数组的长度
c) 在C++编译器中,执行程序遇到const变量的时候,会直接被看作是常量,直接用初值替换,即*(&a)  ->   20

本来我们使用const修饰变量的目的就是保证变量不被修改,然上面我们能够看到,如果我们把一个常量的地址泄露给了一个普通指针或者引用,那么就会有被修改的风险,因此我们需要对此问题做相应的处理,也就是下面我们将要介绍的 const + 指针的结合

📢📢📢注意:在C++语言规范中,const修饰的类型是离它最近的类型

(1)const + 一级指针

我们先来看看一级指针 + const的情况,如下:

//根据上面的注意项,有
const int *p; -> const修饰int,即值*p不可修改,指针可以任意指向p = &a
int const *p; -> const修饰int,同上
int* const p; -> const修饰int*,即指针指向p不可修改,值*p可以任意
int* const *p; -> const同时修饰int*int,都不能修改

在这里插入图片描述
看到这,我们就能够自己解决:当泄露了常量的指针或引用时,常量可能被修改的问题。但是对于const指针的各种组合类型中,也并非都能够相互进行强制转化的。

📢📢📢这里又需要注意一点:const右边如果没有指针*的话,const是不会参与进推测的类型

int* q1 = nullptr;
int* const q2 = nullptr;
const int* q3 = nullptr;
int const* q4 = nullptr;
int* const* q5 = nullptr;
cout << typeid(q1).name() << endl; //  -> int*
cout << typeid(q2).name() << endl; //  -> int*
cout << typeid(q3).name() << endl; //  -> const int*  / int const*
cout << typeid(q4).name() << endl; //  -> const int*  / int const*
cout << typeid(q5).name() << endl; //  -> int* const*
//以上代码,朋友可以自己去验证一下是否正确

这里我们再给出一段代码,来看看是否正确🤔🤔🤔

#include<iostream>
using namespace std;

int main()
{
	int a = 5;
	const int* pp = &a;
	//const int* pp = nullptr;
	int* qq = p;

	//cout << typeid(pp).name() << endl;

	char s = 'a';
	const char* ss = &s;
	char* sss = ss;
	
	return 0;
}

整形常量指针p指向的是普通变量a的地址,整形变量指针qq指向p,也是普通变量a的地址,既然是普通变量,那么普通变量a的值应该是能被修改是吧🤫🤫,然当我们放在visual studio 2022上时,发现它报错了!!!,其实这更变量a无关,若我们将pp指向nullptr,仍然是一样的结果。因为在类型上,编译器是禁止将 const int* 类型的数据转换成 int* 类型的,使用char等其他类型也是如此

(2)const + 二级(多级)指针

我们再来看看const + 二级(多级)指针的情况,如下:

const int**q;  -> **q 不能被赋值
int* const *q;  ->  *q 不能被赋值
int** const q;   ->  q不能被赋值

📢📢📢注意:对于const + 多级指针 的结合,涉及到类型转化时

错误:
	const int*   -> int*        ;
	int**        -> const int** ;
	int* const*  -> int** //const修饰一级指针
		 《=》 const* -> *
		 《=》 const int* -> int* 是错误的!
	const int**  -> int**       ;
	
正确:
	int*         -> const int*  ;
	int**        -> int* const* 
		 《=》 * -> const*
		 《=》 int* -> const int* 是正确的!

这里我们给出一段代码,来看看是否正确🤔🤔🤔

#include<iostream>
using namespace std;
int main()
{
	int a = 10;
	int* p = &a;
	const int **q = &p;  // const int**  <-  int**
	
	return 0;
}

在这里插入图片描述
这里我们可以把换换const int* *q,即*q是整形常量的指针 《=》p,所以当我们把一个整形常量的地址赋值给*q时,const int b = 20; *q = &b,相当于直接就修改了p,使其指向了常量的地址,把变量b的指针间接地泄露给了普通指针*p,系统报错!!!
—>
解决方法:const int* const*q = &p;

  • 我们让其不能够给*q赋值,即禁用*q = &b

(3)引用操作符 &

引用是C++种的一种特殊数据类型,它提供了对现有别名的访问,通过引用可以使用相同的变量名来访问同一个内存地址的内容,一旦被初始化后,它将一致引用同一个对象,并且不能再引用其他对象,因此引用也被叫做更安全的指针!对比一下指针和引用的区别:

  • 引用是必须初始化的,指针可以不被初始化
  • 引用只有一级,而指针有多级
  • 在汇编层面上,定义或修改引用变量和指针变量是一样的

从以下代码即图例可以看出:

#include<iostream>
using namespace std;
void swap(int& a, int& b) { int t = a; a = b; b = t; } //引用底层还是转化为指针>实现
void swap(int* a, int* b) { int t = *a; *a = *b; *b = t; }

int main()
{
	int a = 10, b = 20;
	swap(&a, &b);
	swap(a, b);

	int *p = &a;
	int &q = a;

	int array[5] = {};
	int (&vv)[5] = array;
	
	return 0;

在这里插入图片描述
在这里插入图片描述

引用又可分为两种:左值引用 和 右值引用

  • 左值引用: 对象的一个命名引用,它绑定到左值(如一个具名变量),即有名字、有内存,通过左值引用,可以修改被引用对象的值。
  • 右值引用: 对临时对象或将要销毁的对象的引用,它绑定到右值(如一个临时对象,一个匿名对象,或一个将要销毁的对象),通过右值引用,可以实现资源的高效转移和移动语义
#include<iostream>
using namespace std;
{
	int a = 10;
	//int &&b = a;  //错误右值引用变量无法绑定到左值
	int &&c = 20;  //c++11提供了右值引用,汇编指令上产生临时量
	const int &d = a; //左值引用可以指向左值
	int &e = a;
	int &f = c; //右值引用本身是一个左值
	return 0;

在这里插入图片描述

📢📢📢注意:左值引用变量能够拥有右值和左值,但右值引用变量只能引用右值

上面就是关于const 、 指针 、 引用的问题,学而不思则罔,思而不学则殆,下面给出几道题目,来检验一下我们的学习成果

A)  int a = 10
    const int *p = &a
    int *q = p  
					    	xxx
B)  int a = 10
	int* const p = &a
   	int *q = p				ggg
   	
C) 	int a = 10
	int* const p = &a
   	const int *q = p	  	ggg
   	
D)	int a = 10
	int *p = &a
	const int **q = &p		xxx
	
E)	int a = 10
	int *p = &a
	int* const* q = &p		ggg

F)	int a = 10
	int *p = &a
	int ** const q = &p		ggg

G)	int a = 10
	int* const p = &a
	int **q = &p			int**   <-  int* const*
							xxx

H)	int a = 10
	const int*p = &a
	int* const* q = &p		int* const*   <-   const int**
					   《=》 int*          <-   const int*
							xxx

引用是不参与推测类型的

I)	int a = 10
	int *p = &a
	int *&q = p			《=》 int **q = &p
							ggg

J)	int a = 10
	int* const p = &a
	int *&q = p			《=》 int **q = &p
							xxx

K)	int a = 10
	int *p = &a
	const int* &q = p;	《=》 const int**q = &p
							ggg


🌻🌻🌻以上就是浅谈C/C++的常量const、指针和引用的有关问题,如果聪明的你浏览到这篇文章并觉得文章内容对你有帮助,请不吝动动手指,给博主一个小小的赞和收藏 🌻🌻🌻

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/464224.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

PLC_博图系列☞基本指令“SET_BF”置位位域

PLC_博图系列☞基本指令“SET_BF”置位位域 文章目录 PLC_博图系列☞基本指令“SET_BF”置位位域背景介绍SET_BF&#xff1a;置位位域说明类型为 PLC 数据类型、STRUCT 或 ARRAY 的位域参数示例 关键字&#xff1a; PLC、 西门子、 博图、 Siemens 、 SET_BF 背景介绍 这是…

【Algorithms 4】算法(第4版)学习笔记 19 - 6.0.4 网络流算法

文章目录 前言参考目录学习笔记1&#xff1a;介绍1.1&#xff1a;最小切分问题1.2&#xff1a;最大流问题1.3&#xff1a;小结2&#xff1a;Ford-Fulkerson 算法&#xff08;FF 算法&#xff09;2.1&#xff1a;介绍2.2&#xff1a;问题3&#xff1a;最大流量 - 最小切分定理 m…

ConsiStory:Training-Free的主体一致性生成

Overview 一、总览二、PPT详解 ConsiStory 一、总览 题目&#xff1a; Training-Free Consistent Text-to-Image Generation 机构&#xff1a;NVIDIA, Tel-Aviv University 论文&#xff1a;https://arxiv.org/pdf/2402.03286.pdf 代码&#xff1a;https://consistory-paper.g…

Github 2024-03-17 开源项目日报Top10

根据Github Trendings的统计,今日(2024-03-17统计)共有10个项目上榜。根据开发语言中项目的数量,汇总情况如下: 开发语言项目数量Python项目5TypeScript项目2Rust项目1JavaScript项目1C#项目1非开发语言项目1Solidity项目1《Hello 算法》:动画图解、一键运行的数据结构与算…

OPC UA 服务器的Web访问

基于Web 的应用非常普及&#xff0c;例如基于web 的SCADA &#xff0c;物联网 Dashboard 等等&#xff0c;那么基于Web 的应用如何访问OPC UA 服务器呢&#xff1f;本博文讨论这方面的问题。 Web 的通信方式 Web 是我们通常讲的网站&#xff0c;它由浏览器&#xff0c;HTTP 服…

腾讯云有免费服务器吗?在哪领取?

腾讯云免费服务器申请入口 https://curl.qcloud.com/FJhqoVDP 免费服务器可选轻量应用服务器和云服务器CVM&#xff0c;轻量配置可选2核2G3M、2核8G7M和4核8G12M&#xff0c;CVM云服务器可选2核2G3M和2核4G3M配置&#xff0c;腾讯云服务器网txyfwq.com分享2024年最新腾讯云免费…

elementUI两个select单选框联动

实现需求&#xff1a;两个单选框内容两栋&#xff0c;在选择第一个时&#xff0c;第二个选框能自动更新对应选项。且在切换第一个选项内容时&#xff0c;第二个选框会被清空且切换到新的对应选项。 设置值班班次和备班情况两个选项 &#xff0c;完整代码如下&#xff1a; <…

【数据结构和算法初阶(C语言)】二叉树学习日记①--树的概念/二叉树的概念、知识和存储结构

目录 1.树概念及结构 1.1树的概念 1.2 树的相关概念 1.3 树结构在实际当中的运用 1.4 树的表示 ①孩子兄弟表示法 ②双亲表示法--孩子找爸爸&#xff08;并查集是一个应用&#xff09; 2.二叉树概念及结构 2.1概念 现实中的二叉树模型&#xff1a; 2.3 特殊的二叉树&#xff1…

【C语言入门】浮点型数据在内存中的存储

✨✨欢迎大家来到Celia的博客✨✨ &#x1f389;&#x1f389;创作不易&#xff0c;请点赞关注&#xff0c;多多支持哦&#x1f389;&#x1f389; 所属专栏&#xff1a;C语言 个人主页&#xff1a;Celias blog~ 目录 ​编辑 引言 引例 一、浮点型在内存中的存储方式 1.1 …

Nodejs 第五十六章(爬虫)

什么是爬虫&#xff1f; 爬虫&#xff0c;也称为网络爬虫或网络蜘蛛&#xff0c;是指一种自动化程序或脚本&#xff0c;用于在互联网上浏览和提取信息。爬虫模拟人类用户在网页上的行为&#xff0c;通过HTTP协议发送请求&#xff0c;获取网页内容&#xff0c;然后解析并提取感…

Day18 Java学生管理系统

Day18 Java学生管理系统 一、需求分析 考虑的方面&#xff1a; 用户需求、功能需求、非功能性需求、约束条件、优先级和权衡、可追踪性、需求验证。 二、项目搭建 搭建学生管理系统 1、创建项目的main ;pojo ; sms ; utils包。 2、编写系统的 增&#xff08;涉及到扩容–…

一. 并行处理与GPU体系架构-GPU并行处理

目录 前言0. 简述1. 这个小节会涉及到的关键字2. CPU与GPU在并行处理的优化方向3. Summary总结参考 前言 自动驾驶之心推出的 《CUDA与TensorRT部署实战课程》&#xff0c;链接。记录下个人学习笔记&#xff0c;仅供自己参考 本次课程我们来学习下课程第一章——并行处理与GPU体…

4.1_5 文件存储空间管理

文章目录 4.1_5 文件存储空间管理&#xff08;一&#xff09;存储空间的划分与初始化&#xff08;二&#xff09;存储空间管理——空闲表法&#xff08;三&#xff09;存储空间管理——空闲链表法&#xff08;1&#xff09;空闲盘块链&#xff08;2&#xff09;空闲盘区链 &…

腾讯云企业用户可以申请免费服务器试用吗?

腾讯云企业用户可以申请免费服务器试用吗&#xff1f;可以的&#xff0c;腾讯云免费服务器申请入口 https://curl.qcloud.com/FJhqoVDP 免费服务器可选轻量应用服务器和云服务器CVM&#xff0c;轻量配置可选2核2G3M、2核8G7M和4核8G12M&#xff0c;CVM云服务器可选2核2G3M和2核…

拌合楼内部管理系统开发(三) 继续功能模块及数据表设计-收发管理模块(无人值守功能)

前言:继续闭门造车 继续发挥,上一篇写到了生产管理,今天开始做无人值守的功能模块的设计了.核心就是收发管理的模块了. 一、发货的工作流程&#xff1a; 我设想的发货流程如下&#xff1a; 1. 发货的源头指令来源于生产计划&#xff1a; 生产计划要素是需要生产的产品&#xff…

解决google Chorme 隐私设置错误

问题&#xff1a; 我们在使用浏览器的时候&#xff0c;出现隐私设置错误“您的链接不是私密连接”&#xff0c;如下图所示&#xff1a; 第一步开始来解决隐私设置错误&#xff0c;打开浏览器之后&#xff0c;点击右上方的三点图标&#xff0c;选择设置&#xff0c;如下图所示&…

基于支持向量机SVM的沉降预测,SVM详细原理,Libsvm详解

目录 支持向量机SVM的详细原理 SVM的定义 SVM理论 Libsvm工具箱详解 简介 参数说明 易错及常见问题 完整代码和数据下载链接:基于支持向量机SVM的沉降预测资源-CSDN文库 https://download.csdn.net/download/abc991835105/88947544 SVM应用实例,基于支持向量机SVM的沉降预测…

MYSQL报 - Lock wait timeout exceeded; try restarting transaction

前言 今天在使用数据库编辑数据时&#xff0c;页面突然卡主&#xff0c;退出程序后重新编辑&#xff0c;发现报错&#xff0c;1205 - Lock wait timeout exceeded&#xff1b; try restarting transaction&#xff08;如下图&#xff09;&#xff0c;正巧在和同事开会&#xf…

基于Springboot和Redis实现的在线选课系统

1.项目简介 1.1 介绍 毕业设计真的就是demo吗&#xff1f;作为工作前的最后一个校园项目&#xff0c;毕业设计应当尽可能的贴近企业实战&#xff0c;业务不必很复杂&#xff0c;但要做到麻雀虽小五脏俱全。本期学长跟大家一起分享如何开发一个在线选课系统&#xff0c;需求也…

如何实现队列和栈的转化(c语言)

文章目录 一.什么是栈二.什么是队列三.怎么把栈变成队列&#xff08;力扣&#xff09;四.怎么把队列变成栈&#xff08;力扣&#xff09;总结 一.什么是栈 栈&#xff08;stack&#xff09;又名堆栈&#xff0c;它是一种运算受限的线性表。限定权在表尾进行插入和删除操作的线性…
最新文章