Linux segmentation fault 错误定位方法及C指针用法

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语言指针用得好犹如神助!这些使用技巧值得收藏! - 哔哩哔哩

【3】 https://www.jb51.net/article/233903.htm

【4】C指针开辟内存空间_DevCsdner的博客-CSDN博客_指针开辟内存空间 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值