自用指针总结(C++)

本文深入讲解指针的基本概念、用法及其在C++中的重要应用,包括指针的声明、赋值、算术运算,以及如何使用指针访问数组元素和动态分配内存。同时对比了指针与引用的区别,探讨了指针在面向对象编程中的角色。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

指针概念

指针(pointer)是一个值为内存地址的变量(或者数据对象)

使用指针来读取数据,在重复性操作的状况下,可以明显改善程序性能,例如在遍历字符串,查取表格,源控制表格及树状结构上。对指针进行复制,之后再解引用指针以取出数据,无论在时间或空间上,都比直接复制及访问数据本身来的经济快速。

基本用法

datatype * pointer_name;

int year = 6;
int* ptr_year = &year;
//
double day = 7.0;
double* ptr_day = &day;

在声明里的 * 号和在声明后使用中的 * 号代表的符号完全不同
所以我们在声明和定义的时候尽量分成两种写法
但在以下的声明里是完全一样的,只是要分成两种理解更好.

int* p;  		//p就是一个地址变量,表示一个十六进制地址
其意思为定义一个指针类型的int
int *p;			//*p是一个整型变量,能够表示一个整型值.

为什么需要给指针定义特定数据类型

因为指针所指的是内存的一块空间,在声明的时候和数组一样需要明确知道具体长度,而指针指向的变量的数据类型不同,空间长度就不同,比如:int型需要4个字节的空间,long需要8个字节的空间。所以我们需要给指针定义合适的数据类型.
而在对指针的某些操作中,只有知道指针的数据类型,我们才能根据不同的类型操作不同长度的连续空间.
比如
int a= * p
即取值操作就要知道p所指向的空间权里存放的变量的类型,根据不同的类型,*操作会读取不同长度的连续空间,例如:int 4字节;

取地址符&

int num = 0;
int * ptr_num = & num;

间接运算符

int num = 0;
int * ptr_num = #	//	&读作ampersand
*ptr_num = 1;			//	*与ptr_num中间没空格  就如上面所述 此处非定义
//此处为 num = 1;

示例

double num = 1;
double * ptr_num = #
cout << "打印num的指针所指向的值"<< *ptr_num << endl; 
cout << "打印num的指针的值"<<  ptr_num << endl; 

输出的地址乱码

在这里插入图片描述

	char ch = 'a';
	char * ptr_ch = &ch;
	cout << ptr_ch << '\n' << *ptr_ch << endl;

在C里面定义字符串的句式为
char * string = "what?"
也就是输出的方式(地址)已经被改成字符串了
所以是以字符串的类型打印字符

所以我们要强转成void *类型 (任意类型)

cout << (void *)ptr_ch << endl;

null pointer 空指针

空指针不指向对象,使用指针之前我们可以检测指针是否为空.

当我们给指针初始化时不指向对象时,会默认指向一个系统分配的值.(野指针)
尽量等定义了对象之后再定义指向它的指针.
指针需要及时释放,也需要正确释放.

用法

以下三句话同样效果

int *ptr1 = nullptr;			//等价于 int *ptr 1 = 0;
int *ptr2 = 0;				//将ptr2初始化为字面常量0;

//需要包括cstdlib
int *ptr3 = NULL;			//等价于 int *ptr3 = 0;

void *指针

void *指针是一种特殊的指针类型,可以存放任意对象的地址.

void *指针存放了一个内存地址,地址指向的内容是什么类型是不能确定.
当我们尝试使用void *去修改其指向的对象的值时,系统会报错

void *不是一个对象型指针

void *作用
①一般用来和别的指针比较,
②或者作为函数的输入和输出;
③赋值给另一个void *指针.

小结

①指针也是变量,但是变量是储存着另一个对象的内存地址,这个行为也称为指针变量指向这个对象.
②指针变量可以赋值,指针所指对象在初始化之后可以通过程序改变
③指针变量的命名和其他变量的命名规则一样(作为区分一般在前面加上p 或者 ptr 或者 pointer)
④指针可以是所有基本数据类型、数组和其他所有高级数据结构的地址
⑤若指针已经申明是一种数据类型的地址,那它就不能用于存储其他类型的地址
⑥指针只有赋值后才能使用(指向地址)

引用(reference)

给对象起了另一个小名(引用就是别名)
int int_value = 1;
int& refValue = int_value; //refValue指向int_value
int& refValue2; //错 引用必须初始化.要赋值

注意:
①引用只能绑定在对象上,不能与字面值或某个表达式的计算结果绑定在一起(如 double & dou = 10.0;)
所以指向常量的引用是非法的;(但可以使用 const double& dou = 10.0;)
②引用之前不需要测试有效性.所以引用比使用指针效率高.
③引用并不是一个对象,只是一个别名(未分配内存).

引用和指针的区别

引用其实还是指针,是底层被指针封装后的产物.
获取引用地址时,编译器会进行内部转换

指针和数组

double score[] {0,1,2,3,4};
double * ptr_score = score;
cout << sizeof(score) << "\t" << sizeof (ptr_score) << endl;
cout << &score[0] << "\t" << ptr_score << endl;

将显示如下界面
在这里插入图片描述
可以得出以下两个结论:
①数组在内存里是一串连续的地址,而数组名(指针的名字,不带号)就是这块连续内存空间的首地址
②数组里因为存放着5个double类型的数据,所以是5
8 = 40
而ptr_score是地址,是指针,在32位的编译器里只占4个字节,哪怕声明是double 也只占4个字节.

指针的算术运算

指针的递增和递减(++ --)

也称之为指针的平移
移动的单位是以sizeof(T)的长度来移动.
假如在double数组指针里
0xfafed0 到 0xfafed8 之间移动了一个double数据的长度 即8个字节

指针加减整数值

小tips:

double score[] {0,1,2,3,4};
double * ptr_score = score;
cout << *(ptr_score - 7) << endl;

在这里插入图片描述
++num是非法的
所以我们使用指针来*++ptr_num

数组名和首地址

数组名就是这块连续内存单元的首地址

int num[50]; //num是数组名,也可以理解成数组的首地址

num的值与&num[0]的值是相同的
数组的第i+1元素可以表示为:

&num[i + 1] 或 num + i
num[i + 1]*(num + i + 1)

为指向数组的指针赋值:
int * ptr_num = num; 或int * ptr_num = &num[0];
指针变量可以指向数组元素
int * ptr_num = &num[4]; 或 int * ptr_num = num + 4;

动态分配内存(面向对象)

使用new分配/delete释放内存

指针真正的用武之地是在运行阶段来分配未命名的内存来出储存值,而这块内存的访问就只能通过指针.

1.在运行阶段为int值分配一个未命名的内存
2.使用内存来访问(指向)这个值(->)注意不要创建两个指向同一块内存的指针,可能误删除两个指针.

int *p = new int;

3.释放内存
delete ptr_int;

指针指向另外的指针,原本的内存没有释放,称之为野指针/内存泄漏
内存的释放用三点注意事项

与new配对使用(不要去释放不是new创建的内存空间)
不释放已经释放的内存(重复释放可能导致被覆盖的内存区域被误释放.)
不释放声明变量分配的内存

delete在C++里不是删除,是释放内存.就好比清空了回收站依旧可以通过软件找回来,只要不覆盖(再次清空回收站),就不是真正意义上的删除.

使用new创建动态分配的数组

int * intArray = new int[10];
delete [] intArray;

使用New为数组分配内存 也要使用delete []释放内存

补充

在这里插入图片描述

栈区(stack)

由编译器自动分配释放,一般存放函数的参数值、局部变量的值等
操作方式类似数据结构的栈-先进后出

堆区(heap)

一般由程序员分配释放,若程序不释放,程序结束时可能由操作系统回收
注意:与数据结构中的堆是两回事,分配方式类似链表

全局区(静态区-static)

全局变量和静态变量是储存在一起的
程序结束后由系统释放

文字常量区

常量字符串就放在这里,程序结束由系统释放

程序代码区

存放函数体的二进制代码

int num = 90;  //左边栈区  右边常量区
	double * dArray = new double[10];// 左边还是栈区  右边是堆区   堆区里的内存的地址被dArray指向
	//因为栈区的高效率 所以多采用指针和引用,而事实上执行程序的是堆区.

用指针来创造二维指针

在这里插入图片描述
new int[10]是计算机中的一维,
而new int [5][3]是二维
(*p2)
为降维操作,小括号优先级最高.
int *是int 指针类型 像

int [][]

可以理解成前面的[]被换成了(*p2)

输出二维数组

利用数组地址的相邻性我们可以输出数组
在这里插入图片描述
p2 + i 与 (p2 + i)的值相同
(*(p2+i))显示的是1,4,7,11,14
在这里插入图片描述

总结

指针是一个变量,储存另一个变量(对象)的内存地址

指针的声明由基本类型、星号(*)和变量名组成

为指针赋值,赋值运算符右侧必须是一个地址.

如果是普通变量需要在前面加一个取地址运算符&;
如果是另一个指针变量或一个数组,不需要加&运算符

运算符*用于返回指针指向的内存地址中储存的值

使用指针访问一维数组和二维数组的元素

题外话

指针由于麻烦的原因,我们用引用多于指针,但是指针其自身的强大是我们不可或缺的工具,使用的场景常常为封装的时候

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值