C++指针的深入解析
Qingyh Lv2

指针的概念

指针是一种特殊的数据类型,用于存储变量的内存地址而非直接存储值。通过指针可以间接访问或操作内存中的数据,常用于动态内存分配、数组操作和函数参数传递等场景。

1
2
int var = 10;     // 定义整型变量
int *ptr = &var; // 指针ptr存储var的地址

动态内存管理:通过指针可以在程序运行时动态分配或释放内存(如mallocfree)。

1
2
int *arr = (int*)malloc(5 * sizeof(int)); // 动态分配数组
free(arr); // 释放内存

高效数据传递:函数参数传递指针可避免数据复制,提升性能。如下面代码所示

1
2
3
4
5
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字节。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#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;
}

打印的结果为:
image
其实也很好理解,指针本质是内存的地址,对于32位系统来说,指针的长度为4字节;对于64位系统来说,指针的长度为8字节。

const关键字

const是C/C++语言中的一个重要关键字,用于定义常量,表示该变量的值在程序运行期间不能被修改。const关键字可以应用于变量、函数参数、函数返回值以及成员函数。

const特点:

  • 不可变性const变量的值一旦初始化后就不能再被修改(定义时初始化)
  • 编译期检查:编译器会在编译时检查对const变量的修改操作,并报错
  • 类型安全const提供了额外的类型安全保证

以下是const使用过程中可能出现的错误:
1.const常量不能再作为左值,(不然会直接修改常量的值),如:

1
2
const int a=10;
a=20;//尝试直接修改常量,错误

2.不能把常量的地址泄露给一个普通的指针或者引用变量(不然会间接的修改常量的值),只能传给const类型的指针或变量

1
2
3
4
5
6
7
const int a=10;
int *p=&a;
//这样可以间接通过指针解引用方法修改内存a的值。
*p=20;

//正确的定义方式为
const int *p=&a;

判断const修改的类型

C++中const修饰符的规则如下:const修饰的是与其最近的表达式(需先去除类型说明符如int、int*)并且遵循最少原则:在int*和int之间优先选择int。去除类型说明符后的表达式即表示该部分不可修改。

const和一级指针

常量指针

见代码:

1
2
3
4
5
6
7
8
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类型的内存地址,但不能通过指针间接修改所指向内存的值。

指针常量

代码如下

1
2
3
4
5
6
7
8
int a=10;
int b=100;

int * const p=&a; //const最近且满足最少原则的类型应该是int *,则其修饰的表达是为 p,表示p不能被修改

//指针p是常量,不能再指向其他内存,但是可以通过指针解引用修改指向内存的值
p=&b; //错误
*p=20; //正确

const修饰失效

注意:当const 右边没有指针符号*时,const不参与类型定义。

1
2
3
4
int * q1=nullptr;
int *const q2=nullptr;
int const *q3=nullptr;
//这里q1和q2的类型都是 int *; q3的类型是int const *;

const和二级指针的组合

指向常量的二级指针

1
2
3
4
5
int x = 10;
const int* p = &x;
const int** pp = &p;
// *pp = &y; // 合法
// **pp = 20; // 非法,x是常量
  • 表示指向一个指向常量的指针的指针
  • 可以通过二级指针修改一级指针的指向,可以修改二级指针
  • 但不能修改最终指向的值
    image

指向指针常量的二级指针

1
2
3
4
5
int x = 10;
int* const p = &x;
int* const* pp = &p;
// *pp = &y; // 非法,p是常量指针
// **pp = 20; // 合法,x可以被修改
  • 表示指向一个指针常量的指针
  • 不能通过二级指针修改一级指针的指向
  • 但可以修改一级指针指向的值,可以修改二级指针
    image

二级指针常量

1
2
3
4
5
6
int x = 10;
int* p = &x;
int** const pp = &p;
// pp = &q; // 非法,pp是常量
// *pp = &y; // 合法,修改p的指向
// **pp = 20; // 合法,修改x的值
  • 表示二级指针本身是常量
  • 不能修改二级指针的指向
  • 但可以修改一级指针的指向及其指向的值
    image

完全常量二级指针

1
const int* const* pp;
  • 表示指向一个指向常量的指针常量的指针
  • 既不能修改一级指针的指向,也不能修改最终指向的值
    image

总结 const 和 指针的类型转换公式

在C++中,指针和const的组合使用需要注意类型转换的规则。以下是总结的一些转换方式:

一级指针转换

1
2
3
4
5
6
7
8
9
int * <<<=== const int *  ;//是错误的!!!
// 不能将const指针赋值给非const指针,这会导致const保护失效

const int * <<<=== int *; //是正确的!!!
// 可以将非const指针赋值给const指针,这是安全的类型降级
// 例如:
int a = 10;
int *pa = &a;
const int *cpa = pa; // 合法转换

二级指针转换

1
2
3
4
5
6
7
8
9
10
11
int ** <<<=== const int **; //是错误的!!!
const int **<<<=== int **; //是错误的!!!
//在二级指针甚至多级指针中,两边都要有const 才算正确;

int ** <<<===int * const *;//是错误的!!!
//前面说到,const只负责其右边的类型构造,上面可以简化为
int * <<<===int const *; //判断为错误

int *const *<<<=== int **; //是正确的!!!
//简化为
int const *<<<=== int *;

以下是一些转换的错误样例

错误样例

1
2
3
int a=10;
const int *p=&a;
int *q=p;//这里 int *<<<===const int *,不匹配
1
2
3
int a=10;
int *p=&a;
const int **q=&p; //const int ** <<<=== int **,不匹配,&p取地址加一个*
1
2
3
4
int a=10;
int *const p=&a; //p为int *,const 只在其右边有指针时起作用;
int **q=&p;//因为这有一个取地址操作,则 int ** <<<===int *const *,不匹配

1
2
3
int a=10;
const int *p=&a;
int *const*q =&p; //int *const *<<<===const int **,左边是const 与一级指针结合,右边是const 与二级指针结合,不匹配(我是这么理解的,不知道有没有更好的解释)

指针与数组结合

数组指针

1
2
3
4
5
6
7
8
9
10
11
//数组类型的指针

//指针有各种类型 ,int *,float *
//将数组当作一种数据类型,定义一个指向数组的指针

int a=10;
int *pa=&pa;

int arr={1,2,3};
int (*pa) []=&arr;
//表明这是一个指针,并且指向一个数组,这个数组中的类型是int 类型

指针数组

1
2
3
int a=10,b=20,c=30;
int *arr[]={&a,&b,&c};
//arr先与[]结合,表示这是一个数组,并且这个数组的类型是int *

指针与函数结合

函数指针

1
2
//是一个指针,指向一个函数,函数返回类型是int 型
int (*fun) (int x);

指针函数

1
2
int *fun (int x)
//fun先与()结合,表示这是一个函数,返回类型为int *;
由 Hexo 驱动 & 主题 Keep
本站由 提供部署服务
总字数 31k