1 问题现象
程序运行时报错,segmentation fault
segmentation fault 就是经常说的内存泄露/溢出: 当一个进程执行一个无效的内存引用,或发生断错误时,会触发 SIGSEGV信号,内核默认的动作就是 终止该进程。
2 C++指针使用
2.1 指针释放
在C/C++中,当指针需要删除时,对于new的指针,调用delete就可以删除 比如:
int* p = new int(17);
delete p;
有时候为了避免使用错误,一般在delete之后,将p置为NULL,即
int* p = new int(17);
delete p;
p = NULL;
3 delete 的作用
int * ipt = new int; // create new pointer-to-int
cout << ipt << endl; // 0x200102a0, so pointer ipt points to address 0x200102a0
cout << *ipt << endl; // 0, so the value at that address for now is 0. Ok, nothing was assigned
*ipt = 1000; // assign a value to that memory address
cout << *pt << endl; // read the new value, it is 1000, ok
cout << *((int *) 0x200102a0) << endl; // read exactly from the address, 1000 too
delete ipt; // now I do delete and then check
cout << ipt << endl; // 0x200102a0, so still points to 0x200102a0
cout << *ipt << endl; // 1000, the value there is the same
cout << *((int *) 0x200102a0) << endl; // 1000, also 1000 is the value
3.1 delete p 之后为什么要 p=NULL?
delete p后,p并不会自动被置为NULL
对一个非空指针delete后,若没有赋NULL,若再次delete的话,有可能出现问题。
int *p = new int(3);
delete p;
p = NULL;
delete p;//再次 delete p 则不会出问题
3.2 "=delete” 修饰
C++11中,当我们定义一个类的成员函数时,如果后面使用"=delete"去修饰,那么就表示这个函数被定义为deleted,也就意味着这个成员函数不能再被调用,否则就会出错。
#include <cstdio>
class TestClass
{
public:
int func(int data)=delete;
};
int main(void)
{
TestClass obj;
obj.func(100);//func 被 delete修饰
return 0;
}
编译时报错。
在C++11之前,当我们希望一个类不能被拷贝,就会把构造函数定义为private,但是在C++11里就不需要这样做了,只需要在构造函数后面加上=delete来修饰下就可以了
3.3 c++ new
new开辟的空间在堆上面,而不在存放一般变量的栈上面,所以局部函数中new出来的新空间,在局部函数调用结束之后仍然能够使用。
如果new出来的空间,记得用delete释放。
3.4 C++ 指向指针的指针(多级间接寻址)
指针的指针就是将指针的地址存放在另一个指针里面。通常,一个指针包含一个变量的地址。当我们定义一个指向指针的指针时,第一个指针包含了第二个指针的地址,第二个指针指向包含实际值的位置。
#include <iostream>
using namespace std;
int main ()
{
int var;
int *ptr;
int **pptr;
var = 3000;
// 获取 var 的地址
ptr = &var;
// 使用运算符 & 获取 ptr 的地址
pptr = &ptr;
// 使用 pptr 获取值
cout << "var 值为 :" << var << endl;
cout << "*ptr 值为:" << *ptr << endl;
cout << "**pptr 值为:" << **pptr << endl;
return 0;
}
输出:
var 值为 :3000 *ptr 值为:3000 **pptr 值为:3000
4 c语言指针用法
4.1 指针
指针是一种保存变量地址的变量,在C语言中,指针是表达某个计算的唯一途径。
(1)指针是能够存放一个地址的一组存储单元(通常是一个或4个字节)。
一元运算符&,是取地址运算符,可用于取对象的地址;
一元运算符*,是间接寻址或间接引用运算符,可用于访问指针所指向的对象。
指针的大小
- 在32为计算机上指针大小4字节。
- 在64为计算机上指针大小8字节。
(2)指针只能指向某种特定类型的对象,即每个指针必须指向某种特定的数据类型,一个例外的情况是指向void类型的指针可以存放指向任意类型的指针,但不能间接引用其自身。
char * p=(char*)malloc(sizeof(char)*size); //size 所需的内存大小
4.2 指针类型
int*; *p可以访问4个字节。
char*; *p可以访问1个字节。
double*; *p可以访问8个字节
4.3 野指针
野指针就是指针指向的位置是不可知的(随机的、不正确的、没有明确限制的。
4.3.1 野指针的类型
(1)指针未初始化
nt main(){
int a;//局部变量不初始化,默认是随机值
int *p;//局部的指针变如果没有初始化,就被初始化为随机值。
}
(2)指针越界访问
int main(){
int arr[10];
int *p = arr;
for(int i = 0;i<12;i++){
p++;
}
//当指针的范围超出数组的范围时,p就是野指针。
}
(3)指针指向的空间释放
4.3.2 避免野指针的方法
1.指针初始化
2.小心指针越界
3.指针指向内存释放 即 指向NULL
4.指针使用之前检查有效性
4.4 动态开辟内存
#include <stdio.h>
int* getSpace()
{
//开辟5个连续的int大小的内存
int* p = malloc(sizeof(int) * 5);
if (p == NULL)
{
return;
}
//赋值
for (int i = 0; i < 5; i++)
{
p[i] = i + 100;
}
//返回开辟好的内存指针
return p;
}
void main()
{
int* p = getSpace();
for (int i = 0; i < 5; i++)
{
printf("%d\n", p[i]);
}
//手动释放
free(p);
//避免出现野指针
p = NULL;
}
参考文献:
【1】对于C++中的指针,delete命令对内存有什么作用? |
【2】 C语言指针用得好犹如神助!这些使用技巧值得收藏! - 哔哩哔哩