C++中const,指针和引用

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++中指针和引用的区别

  1. 引用是一种更安全的指针。
  2. 引用必须初始化,指针可以不初始化。
  3. 引用只有一级引用,没有多级引用;指针可以有一级指针,也可以有多级指针。
  4. 定义一个引用变量和定义一个指针变量,其汇编指令是一模一样的;通过引用变量修改所引用的内存的值,和通过指针解引用去修改指针所指向的内存值,其底层指令是一模一样的。
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和二级指针的用法问题

/*
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和一级指针和引用结合的代码分析:

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**;所以是错误的  

猜你喜欢

转载自blog.csdn.net/qq_45041871/article/details/132253644