C++指针与引用:深入解析
指针的概念
指针是一种特殊的数据类型,用于存储变量的内存地址而非直接存储值。通过指针可以间接访问或操作内存中的数据,常用于动态内存分配、数组操作和函数参数传递等场景。
int var = 10; // 定义整型变量
int *ptr = &var; // 指针ptr存储var的地址
动态内存管理:通过指针可以在程序运行时动态分配或释放内存(如malloc
和free
)。
int *arr = (int*)malloc(5 * sizeof(int)); // 动态分配数组
free(arr); // 释放内存
高效数据传递:函数参数传递指针可避免数据复制,提升性能。如下面代码所示
void modify(int *x) { *x = 20; }
int main() {
int a = 10;
modify(&a); // a的值被改为20
}
Tips:
未初始化的指针可能指向非法内存,导致崩溃。指针的字节固定为4字节或者8字节(根据操作系统确定)。如int是4字节,char 是1字节,double是8字节;但是对于指针来说char *,和int *,double *都是4字节。
#include <iostream>
using namespace std;
class A
{
int ma_;
int mb_;
int mc_;
};
int main()
{
cout << "sizeof(char) :" << sizeof(char) << endl;
cout << "sizeof(int) :" << sizeof(int) << endl;
cout << "sizeof(double) :" << sizeof(double) << endl;
cout << "sizeof(class A):" << sizeof(A) << endl;
cout << "sizeof(char *) :" << sizeof(char *) << endl;
cout << "sizeof(int *) :" << sizeof(int *) << endl;
cout << "sizeof(double*):" << sizeof(double*) << endl;
cout << "sizeof(class A *) :" << sizeof(A *) << endl;
return 0;
}
打印的结果为:
其实也很好理解,指针本质是内存的地址,对于32位系统来说,指针的长度为4字节;对于64位系统来说,指针的长度为8字节。
const关键字
const
是C/C++语言中的一个重要关键字,用于定义常量,表示该变量的值在程序运行期间不能被修改。const
关键字可以应用于变量、函数参数、函数返回值以及成员函数。
const特点:
- 不可变性:
const
变量的值一旦初始化后就不能再被修改(定义时初始化) - 编译期检查:编译器会在编译时检查对
const
变量的修改操作,并报错 - 类型安全:
const
提供了额外的类型安全保证
以下是const使用过程中可能出现的错误:
1.const常量不能再作为左值,(不然会直接修改常量的值),如:
const int a=10;
a=20;//尝试直接修改常量,错误
2.不能把常量的地址泄露给一个普通的指针或者引用变量(不然会间接的修改常量的值),只能传给const类型的指针或变量
const int a=10;
int *p=&a;
//这样可以间接通过指针解引用方法修改内存a的值。
*p=20;
//正确的定义方式为
const int *p=&a;
判断const修改的类型
C++中const修饰符的规则如下
:const修饰的是与其最近的表达式(需先去除类型说明符如int、int*)并且遵循最少原则:在int*和int之间优先选择int。去除类型说明符后的表达式即表示该部分不可修改。
const和一级指针
常量指针
见代码:
int a=10;
int b=100;
const int *p=&a;
int const *p=&a; //与上一行等效,const与int的位置互换不影响含义
//这里去掉最近的类型,即 int ,const修饰的是*p,表示*p不能被修改。
*p=20; //错误:试图修改常量指针指向的内容
p=&b; //正确:可以改变指针的指向
该指针可以指向不同的int类型的内存地址,但不能通过指针间接修改所指向内存的值。
指针常量
代码如下
int a=10;
int b=100;
int * const p=&a; //const最近且满足最少原则的类型应该是int *,则其修饰的表达是为 p,表示p不能被修改
//指针p是常量,不能再指向其他内存,但是可以通过指针解引用修改指向内存的值
p=&b; //错误
*p=20; //正确
const修饰失效
注意
:当const 右边没有指针符号*时,const不参与类型定义。
int * q1=nullptr;
int *const q2=nullptr;
int const *q3=nullptr;
//这里q1和q2的类型都是 int *; q3的类型是int const *;
const和二级指针的组合
指向常量的二级指针
int x = 10;
const int* p = &x;
const int** pp = &p;
// *pp = &y; // 合法
// **pp = 20; // 非法,x是常量
- 表示指向一个指向常量的指针的指针
- 可以通过二级指针修改一级指针的指向,可以修改二级指针
- 但不能修改最终指向的值
指向指针常量的二级指针
int x = 10;
int* const p = &x;
int* const* pp = &p;
// *pp = &y; // 非法,p是常量指针
// **pp = 20; // 合法,x可以被修改
- 表示指向一个指针常量的指针
- 不能通过二级指针修改一级指针的指向
- 但可以修改一级指针指向的值,可以修改二级指针
二级指针常量
int x = 10;
int* p = &x;
int** const pp = &p;
// pp = &q; // 非法,pp是常量
// *pp = &y; // 合法,修改p的指向
// **pp = 20; // 合法,修改x的值
- 表示二级指针本身是常量
- 不能修改二级指针的指向
- 但可以修改一级指针的指向及其指向的值
完全常量二级指针
const int* const* pp;
- 表示指向一个指向常量的指针常量的指针
- 既不能修改一级指针的指向,也不能修改最终指向的值
总结 const 和 指针的类型转换公式
在C++中,指针和const的组合使用需要注意类型转换的规则。以下是总结的一些转换方式:
一级指针转换
int * <<<=== const int * ;//是错误的!!!
// 不能将const指针赋值给非const指针,这会导致const保护失效
const int * <<<=== int *; //是正确的!!!
// 可以将非const指针赋值给const指针,这是安全的类型降级
// 例如:
int a = 10;
int *pa = &a;
const int *cpa = pa; // 合法转换
二级指针转换
int ** <<<=== const int **; //是错误的!!!
const int **<<<=== int **; //是错误的!!!
//在二级指针甚至多级指针中,两边都要有const 才算正确;
int ** <<<===int * const *;//是错误的!!!
//前面说到,const只负责其右边的类型构造,上面可以简化为
int * <<<===int const *; //判断为错误
int *const *<<<=== int **; //是正确的!!!
//简化为
int const *<<<=== int *;
以下是一些转换的错误样例
错误样例
int a=10;
const int *p=&a;
int *q=p;//这里 int *<<<===const int *,不匹配
int a=10;
int *p=&a;
const int **q=&p; //const int ** <<<=== int **,不匹配,&p取地址加一个*
int a=10;
int *const p=&a; //p为int *,const 只在其右边有指针时起作用;
int **q=&p;//因为这有一个取地址操作,则 int ** <<<===int *const *,不匹配
int a=10;
const int *p=&a;
int *const*q =&p; //int *const *<<<===const int **,左边是const 与一级指针结合,右边是const 与二级指针结合,不匹配(我是这么理解的,不知道有没有更好的解释)
指针与数组结合
数组指针
//数组类型的指针
//指针有各种类型 ,int *,float *
//将数组当作一种数据类型,定义一个指向数组的指针
int a=10;
int *pa=&pa;
int arr={1,2,3};
int (*pa) []=&arr;
//表明这是一个指针,并且指向一个数组,这个数组中的类型是int 类型
指针数组
int a=10,b=20,c=30;
int *arr[]={&a,&b,&c};
//arr先与[]结合,表示这是一个数组,并且这个数组的类型是int *
指针与函数结合
函数指针
//是一个指针,指向一个函数,函数返回类型是int 型
int (*fun) (int x);
指针函数
int *fun (int x)
//fun先与()结合,表示这是一个函数,返回类型为int *;