C++指针的使用及注意事项

什么是指针

我们常说的指针是一个变量,为复合类型(包括数组、字符串、结构等),指针变量实质是指存储了一个内存地址。而变量会有自己的内存空间,所以虽然指针变量代表着另外一个内存地址,但其自身也会有对应的内存空间存储值,从而导致双重指针或多重指针的存在(多级间接寻址)。

在计算机中每个变量都有自己的内存位置,并定义了使用地址运算符(&)可以取用的内存地址。即如果var是一个变量,则&var代表它的地址。

指针的声明及使用

指针标准声明定义为:

type *var-name;

下面是两个不同的声明:

int* var; //第一种
int *var; //第二种

这两个等价声明了一个整形指针var,称var的类型为指向int的指针(整型指针),称*var的类型为int,而不是指针。
虽然二者等价,但第一种声明方式尤其要注意以下情况:

int* var1,var2;

此语句将声明var1为int* , var2则为int(而非int*)

int a = 13;
int *p = NULL;
p = &a;
cout<<*p<<endl;   //打印指针指向地址处存储的值, *为解除引用	 
cout<<p[0]<<endl; //也可采用访问数组的形式获取指针指向地址处存储的值	 

注意:指针变量可以是基本类型指针,也可以是其他数据类型(如数组,结构体,类等等)。另外,还有函数指针,用于指向函数的入口地址,感兴趣的朋友可以参考这篇博文

数组指针和指针数组

数组指针:数组是修饰词,指针是名词,本质上是指针,可以理解为数组的指针,如:int (* arr) [10] 就是一个数组指针
指针数组:指针是修饰词,数组是名词,本质上是数组,可以理解为存放指针的数组,如:int* arr[10]; 一个指针数组。

指针使用不当导致的问题

内存越界

内存越界是最常见的错误,当访问超出申请内存大小的内存时就会出现内存越界的错误,从而导致程序崩溃。

内存泄漏

内存泄漏指的是程序中已经动态分配的内存没有被释放,导致程序占用的内存越来越多,最终导致程序崩溃。

野指针

野指针指的是指针变量未初始化或指向一个已经释放的内存块,访问该内存块的值会造成不可预测的结果。

释放内存后的崩溃瞬间

以下的代码都是错误示例,在编写程序时需要注意。
1). 重复释放内存
当你写了如下代码:

int * p1 = new int;
delete p1;
delete p1;	//释放野指针

编译是可以通过的,但是程序运行时就会崩溃。当然,我们编写代码时并不会连续写两条相同的 delete,但很多时候两条语句并不在一起,或者操作的并不是同一个指针,就像下面这样:

int * p1 = new int;
int * p2 = p1;
delete p1;
delete p2;	//重复释放内存

虽然不是同一个指针,但释放的是同一块内存空间,本质上和上面是一样的(也许编译器的处理方法不一样,这里不做讨论)。
C++ 类的拷贝构造函数会涉及到深拷贝和浅拷贝,浅拷贝有时也会出现重复释放内存的问题。

2). 释放非堆区内存

当你释放的内存不是申请的动态内存,也就是非堆区内存,也会造成程序崩溃:

int a;
int * p1 = new int;
p1 = &a;
delete p1;	//释放非堆区内存

我们学 C/C++ 的指针就是为了指来指去的,但是当指向动态内存的指针,在释放该内存之前就指向了其他地方,这样最后 delete 释放的并不是动态内存空间,而真正的需要释放的地址已经找不到了。所以在使用指向动态内存的指针时一定要小心,不然程序崩溃了,你也崩溃了。

我们可以使用 const 关键字来修饰指针,如int * const p1 = new int;,之后指针再指向其他地址就会报错。只是这样在后面释放内存之后,这个指针也不能再使用了。

内存管理策略

new和delete成对出现

内存管理是指对内存的分配、释放和使用的管理。在C++中,有两种内存分配方式,即栈内存分配和堆内存分配。栈内存分配由编译器自动管理,当一个函数被调用时,它所需要的局部变量和参数会被分配在栈中,在函数返回时会自动释放。堆内存分配需要程序员手动管理,通过调用new和delete运算符来动态分配和释放内存。

使用智能指针

在程序中,可以使用智能指针来管理内存。智能指针是一种类似于指针的对象,它可以自动管理动态分配的内存。C++11引入了std::unique_ptr和std::shared_ptr两种智能指针,它们都定义在头文件中。

std::unique_ptr是一种独占式的智能指针,它只能有一个指针指向同一个内存块,不能复制或共享。当std::unique_ptr被销毁时,它所管理的内存块也会被自动释放。例如:

std::unique_ptr<int> p(new int); // 定义一个std::unique_ptr指向一个int类型的内存块*p = 10; // 在该内存块中存储一个值为10的整数cout << *p; // 输出该内存块中存储的整数,即10

std::shared_ptr是一种共享式的智能指针,可以有多个指针指向同一个内存块,当所有指向该内存块的std::shared_ptr被销毁时,该内存块也会被自动释放。std::shared_ptr可以使用std::make_shared函数来创建。例如:

std::shared_ptr<int> p1 = std::make_shared<int>(); // 定义一个std::shared_ptr指向一个int类型的内存块*p1 = 10; // 在该内存块中存储一个值为10的整数std::shared_ptr<int> p2 = p1; // p2也指向该内存块cout << *p1 << " " << *p2; // 输出该内存块中存储的整数,即10 10

结语

总之,指针和内存管理是C++编程中非常重要的一部分,需要程序员对其有深入的理解和掌握。指针的使用需要谨慎,避免出现内存泄漏和野指针等问题,可以使用智能指针来管理内存,减少程序员的负担。

参考文献
[1] C++动态内存的申请和释放
[2] C++指针与动态内存分配
[3] C++指针和引用、智能指针
[4] 数组指针和指针数组

  • 28
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值