C++中的const,指针和引用
在线C/C++编译器,可以试着运行代码。
C++中的const
在C语言中,const修饰的量称为常变量(在编译过程中,const就是当成变量的编译生成指令的),不可以直接修改它的值,但是可以通过地址进行修改其对应的值。并且const修饰的变量可以不进行初始化,编译器最后默认赋值为0。
#include <stdio.h>
void main()
{
const int a = 10;
// a=30; a不能直接作为左值修改其值
int *p = (int *)&a; // p指向a的地址,所以后面通过指针可以修改地址的值 //理论上来说是错误的,int* <- const int* 这种转化不支持,但是编译器确实通过了
*p = 30;
printf("%d,%d,%d", a, *p, *(&a)); // 30,30,30
const int i;
printf("%d",i); // 0
}
然而在C++中,这个一样的代码就会出现不一样的结果:
#include<iostream>
using namespace std;
int main()
{
const int a = 10;
// a=30; 不能直接作为左值进行修改其值
int *p = (int *)&a; //理论上来说是错误的,int* <- const int* 这种转化不支持,但是编译器确实通过了
*p = 30;
cout << a << "," << *p << "," << *(&a) << endl; // 10,30,30 在编译过程中会直接替换a为10
// const int i; C++中const必须初始化,也成为常量
int array[a]; // a是常量,座椅所以可以初始化数据长度
int b = 20;
// int test_array[b]; b是变量,所以不能直接初始化数组长度
return 0;
}
这是因为在C++中const修饰的变量在编译过程中会将const修饰的值直接替换为对应的值。
C++中const修饰的量称为常量,必须进行初始化,不可以直接修改它的值,但是可以通过地址进行修改其对应的值。
C++引用
C++引用又可以分为左值引用和右值引用。
- 左值,它有内存,有名字,值可以修改
- 右值,没内存,没名字
- 一个右值引用变量,其本身是一个左值
以下举例进行说明:
int i = 10; // i是一个左值,有内存,有名字,值可以修改
int &j = i; // j左值引用变量
// int m = &20; 20是一个右值,没内存,没名字
int &&m = 20;// 可以使用右值引用
m = 30;
// int &&n = m; n是一个右值引用变量,但是它本身是一个左值
int &n = m;
const int &k = 20; // int temp=20;const int &k=temp;这个代码的编译过程和int &&m=20;一样,不过m可以被修改而k不能被修改
// k = 30; k是常量,不能被修改
C++中指针和引用的区别
- 引用是一种更安全的指针。
- 引用必须初始化,指针可以不初始化。
- 引用只有一级引用,没有多级引用;指针可以有一级指针,也可以有多级指针。
- 定义一个引用变量和定义一个指针变量,其汇编指令是一模一样的;通过引用变量修改所引用的内存的值,和通过指针解引用去修改指针所指向的内存值,其底层指令是一模一样的。
int a = 0;
int b = 10;
int &c = a;
// int &d; 引用必须要初始化
int *d = &b;
int *e; // 指针可以不初始化
c = 20; // c就相当于a的别名,
cout << a << "," << b << "," << c << endl; // 20,10, 20
*d = 30;
cout << a << "," << b << "," << *d << endl; // 20,30, 30
函数传值和传引用的区别
#include<iostream>
using namespace std;
void swap_comm(int x,int y)
{
int temp = x;
x = y;
y = temp;
}
void swap(int *x,int *y)
{
int temp = *x;
*x = *y;
*y = temp;
}
void swap(int &x,int &y)
{
int temp = x;
x = y;
y = temp;
}
int main()
{
int array[10] = {};
int *a_p1 = array;// 指针指向数组的首地址
int (&a_inf)[10] = array;//定义一个引用变量来存储array,也就是别名
cout << sizeof(array) << "," << sizeof(a_p1) << "," << sizeof(a_inf) << endl; // 40,8,40
int a = 0;
int b = 10;
cout << a << "," << b << endl; //0,10
swap_comm(a, b);//传值,没啥用,会新建临时变量,更改的只是临时变量的值,不会更改a,b的值
cout << a << "," << b << endl; // 0,10
swap(a, b);//传引用
cout << a << "," << b << endl; // 10,0
swap(&a, &b);//传指针
cout << a << "," << b << endl; // 0,10
return 0;
}
C++中const和一二级指针的结合使用
C++中const修饰的量叫做常量,和普通变量的区别在于:1、编译的方式不同,直接替换程序中出现的名字。2、不能作为左值,也就是不能重新直接修改它对应的值,但是可以通过指针修改它的值。
const修饰的量(常量)常出现的错误是:
- 常量不能在作为左值,直接修改常量的值。
- 不能把常量的地址泄露给一个普通的指针或者普通的引用变量。
const和指针联用的情况,const修饰的是离它类型最近的类型:
const int *p; //可以指向其他内存的地址,但是不能用指针间接修改其对应的值,p=&a;√ *p=a;×
int const* p;
//上面两个是一样的,不过常用第一种
int *const p; //指针p是常量,不能指向其他内存,但是可以通过指针间接修改内存所指向的值 *p=a;√ p=&a;×
const int *const p;//既不可以修改p指针,也不可以通过指针修改指向的内存
const和指针类型转化
int* q1 = nullptr;
int* const q2 = nullptr; // const右边没有*,则不参与类型
// int*,int *
cout << typeid(q1).name() << "," << typeid(q2).name() << endl;
int a = 10;
int* p1 = &a;
const int* p2 = &a; // const int* <- int*
int* const p3 = &a; // int* <- int*
int* p4 = p3; // int* <- int*
// const int** m = &p; // const int ** <= int **
总结const和指针的类型转化公式:
int* <= const int* 不可以的
const int* <= int* 可以的
const int** <= int** 不可以的
int** <= const int** 不可以的
int** <= int* const* 等价于 int*<=const int* 不可以的
int* const* <= int** 等价于 const int* <=int* 可以的
C++ 底层const二级指针为何能被非const指针初始化? - 张三的回答 - 知乎解释了二级指针和二级常量指针的转化问题。
int* p = nullptr;
const int** cpp = &p; //假如这行代码是正确的...,那么后面 *cpp=&ci;就会出现问题
const int ci = 0;
*cpp = &ci; // const int* *cpp=const int* ci;看上去没有问题,但是 *cpp本质上就是p,而p指向了ci的地址,就出现了int* <- const int*
const,指针,引用判断正误
以下简要说明const和二级指针的用法问题文章来源:https://www.toymoban.com/news/detail-646301.html
/*
int a = 10;
const int* p = &a; // const int* <- int*
int* const* q = &p; // int* const* <- const int **;等价于int* <- const int*。错误
*/
/*
int a = 10;
int*const p = &a; // int* <- int*;
int** q = &p;//int** <- int* const*;错误,因为p取了地址,所以需要考虑const
*/
/*
int a = 10;
int* p = &a; // int* <- int*;
int** const q = &p;//int** <- int**;
*/
/*
int a = 10;
int* p = &a; // int* <- int*;
int* const* q = &p;//int* const* <- int**;
*/
/*
int a = 10;
int* p = &a; // int* <- int*;
const int** q = &p; // const int ** <- int**; 错误,不支持转化
*/
/*
int a = 10;
int* const p = &a; // int* <- int*;
const int* q = p; // const int* <- int*
*/
/*
int a = 10;
int* const p = &a; //int* <- int*; const后面没有*所以不参与类型转化
int* const q = p; //int* <- int*
*/
/*
int a = 10;
int* const p = &a; //int* <- int*; const后面没有*所以不参与类型转化
int* q = p; //int* <- int*
*/
/*
int a = 10;
const int* p = &a; //const int* <- int *;
int* q = p; //int* <- const int*;错误
*/
const和一级指针和引用结合的代码分析:文章来源地址https://www.toymoban.com/news/detail-646301.html
int a = 10;
int* p = &a;
const int*& q = p; //const int** q=&p=int** p;错误
int a = 10;
const int* p = &a;
int*& q = p;//int** q=const int** p;错误
int a = 10;
int* const p = &a;
int*& q = p; //int** q=int* const* p; 错误
//或者 int**q=&p;p是const修饰的量,不能将其地址赋值给普通变量
int a = 10;
int* p = &a;
int*& q = p; //int** p=&q;
//写一句代码,在内存的0x0018ff4处写一个为4字节的整数10;
int* p = (int*)0x0018ff4;
*p = 10;
int a = 10;
int* p = &a;
int** q = &p;
int*& m = p; // int** m=&p;还原回来就是这样的
//判断是否正确
//const int*& k = p; // const int** k=&p; const int** <- int**;所以是错误的
到了这里,关于C++中const,指针和引用的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!