C语言的空类型指针,空指针,野指针详解

目录
  • 空类型指针-void*
  • 空指针-NULL
  • 野指针
    • 造成野指针的原因
      • 1.指针未初始化
      • 2.指针越界访问
      • 3.指针指向的空间已经释放
    • 避免野指针
  • 总结

空类型指针-void*

void是空类型,void*是空类型指针,又叫万能指针,就是该指针能接收任意类型的指针,可以指向任何类型对象,所以不能对空类型指针进行解引用,必须强制类型转换成相应的指针类型,才能进行解引用操作。

空指针类型:

  • 作为函数形参类型,可以接收任意类型的指针;
  • 作为函数返回值类型,在函数外面,将其强制类型转换为相应的指针类型
  • 可以与另一个void*类型指针比较大小

注意:空类型指针不能进行解引用操作;不能进行±整数运算。

空指针-NULL

在C语言中,空指针NULL指的是地址为0的那块空间

#define NULL((void*)0)

对于这块空间是不准我们进行访问的,所以,对NULL是不能进行解引用操作的,所以每次对指针进行解引用操作之前,我们要判断是否为空指针。

野指针

野指针是指向一个非法的或已销毁的内存的指针。

对野指针进行解引用操作是非法的。

造成野指针的原因

1.指针未初始化

int main()
{
	char* p;
	//此时p是野指针
	return 0;
}

没有对指针p进行初始化,此时p就是野指针,如果此时对p进行解引用操作,非法访问内存,程序就会崩溃。

2.指针越界访问

int main()
{
	int arr[] = {1,2,3,4,5};

	int* p = arr;

	int i = 0;
	for (i = 0; i < 10; i++)
	{
		printf("%d ",p[i]);
	}

	return 0;
}

虽然上面程序正常运行,但是其实越界访问了;只是仅仅访问了非法的内存空间,没有改变空间的值,程序有可能没来得及报错,但并不代表程序没有错,但是对于下面的代码,程序就会崩溃:

int main()
{
	int arr[10] = {0};
	int i = 0;
	int* p = arr;

	for (i = 0; i <= 10; i++)
	{
		*p = i;
		p++;
	}

	return 0;
}

因为这里非法访问内存的同时试图改变空间的值,所以程序崩溃。

3.指针指向的空间已经释放

char* fun()
{
	char arr[] = "abc";
	return arr;
}

int main()
{
	char* p = fun();
	printf("%s\n",p);
	return 0;
}

执行程序,给出如下警告

虽然程序没有崩溃,但是这种写法是非法的,arr是局部变量,函数调用结束,栈帧销毁,局部变量空间归还给操作系统,我们没有使用权限,此时p就是野指针,*p属于非法访问内存。

避免野指针

1.指针要进行初始化

指针要有初始值,初始化为NULL,或者有具体的指向。

既然NULL也不能进行解引用操作,那么为什么可以将指针初始化为NULL?这里初始化为NULL,只是为了给指针一个指向,但是实际使用时,我们并不能对NULL进行解引用操作,所以使用指针之前才要有效性判断。

2.使用指针之前要进行有效性判断

使用指针之前,要判断是否为NULL,如果为NULL,那么是不能进行解引用操作的

3.避免越界访问

不要进行越界访问操作,即使还是访问不改变值也是非法的

4.不要返回局部变量的地址

局部变量空间在函数到调用结束,就归还给操作系统,如果返回局部变量的地址,函数外面接收该返回值的指针就变成了野指针

5.当指针指向的空间释放后,要将该指针置为NULL

这样避免对野指针解引用操作,同时避免二次释放动态开辟的内存空间

int main()
{
	int* p = (int*)malloc(10*sizeof(int));

	//1.判断有效性
	if (p == NULL)
	{
		return -1;
	}

	//2.使用指针
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		p[i] = i;
	}

	//3.释放指针指向的空间
	free(p);

	//free(p);//非法操作
	//4.指针置为NULL
	p = NULL;

	free(p);//释放空指针什么都不做

	return 0;
}

总结

本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注我们的更多内容!

(0)

相关推荐

  • 基于C语言中野指针的深入解析

    "野指针"的成因主要有两种:(1)指针变量没有被初始化.任何指针变量刚被创建时不会自动成为NULL指针,它的缺省值是随机的,它会乱指一气.所以,指针变量在创建的同时应当被初始化,要么将指针设置为NULL,要么让它指向合法的内存.例如 复制代码 代码如下: char *p = NULL;     char *str = (char *) malloc(100); (2)指针p被free或者delete之后,没有置为NULL,让人误以为p是个合法的指针.参见7.5节.别看free和dele

  • C语言之free函数以及野指针介绍

    [FROM MSDN && 百科]原型:void free(void *ptr);#include<stdlib.h>或#include <malloc.h>Deallocate space in memory释放ptr指向的存储空间.被释放的空间通常被送入可用存储区池,以后可在调用malloc.realloc以及realloc函数来再分配.注意:连续两次使用free函数,肯定会发生错误.malloc的次数要和free的次数相等.A block of memory

  • C++野指针和悬空指针的实现方法

    目录 一.野指针 二.悬空指针 2.1 情况一 2.2 情况二 2.3 情况三 野指针和悬空指针是指针中常见的两个概念,本文结合实例讲解来讲解下. 一.野指针 野指针是指尚未初始化的指针,既不指向合法的内存空间,也没有使用 NULL/nullptr 初始化指针. 来看一个简单例子: #include <iostream> using namespace std; int main() { int *p; // 野指针 int *q = NULL; // 非野指针 p = new int(5);

  • 解析C语言中空指针、空指针常量、NULL & 0的详解

    什么是空指针常量(null pointer constant)?[6.3.2.3-3] An integer constant expression with the value 0, or such an expression cast to type void *, is called a null pointer constant. 这里告诉我们:0.0L.'\0'.3 - 3.0 * 17 (它们都是"integer constant expression")以及 (void*

  • C语言的空类型指针,空指针,野指针详解

    目录 空类型指针-void* 空指针-NULL 野指针 造成野指针的原因 1.指针未初始化 2.指针越界访问 3.指针指向的空间已经释放 避免野指针 总结 空类型指针-void* void是空类型,void*是空类型指针,又叫万能指针,就是该指针能接收任意类型的指针,可以指向任何类型对象,所以不能对空类型指针进行解引用,必须强制类型转换成相应的指针类型,才能进行解引用操作. 空指针类型: 作为函数形参类型,可以接收任意类型的指针: 作为函数返回值类型,在函数外面,将其强制类型转换为相应的指针类型

  • Go语言基础类型及常量用法示例详解

    目录 基础类型 概述 按类别有以下几种数据类型 数值类型 派生类型 变量 概述 单个变量声明 多个变量声明 基础类型 概述 在 Go 编程语言中,数据类型用于声明函数和变量.数据类型的出现时为了把数据分成所需要用大数据的时候才需要申请大内存,这样可以充分的列用内存. 按类别有以下几种数据类型 数值类型 布尔型 bool:布尔型的值只可以是常量 true 或者 false,默认值为 false. 字符串类型 string:编码统一为 UTF-8 编码标识 Unicode 文本,默认值为空字符串.

  • C语言 指针与数组的详解及区别

    C语言 指针与数组的详解及对比 通俗理解数组指针和指针数组 数组指针: eg:int( *arr)[10]; 数组指针通俗理解就是这个数组作为指针,指向某一个变量. 指针数组: eg:int*arr[10]; 指针数组简言之就是存放指针的数组: --数组并非指针&&指针并非数组 (1)定义一个外部变量: eg:int value=10; int *p=&value; 举例:当需要在一个函数中用这个变量时:externa int*p;而非extern int p[]; 分析:当用:e

  • C语言中指针和数组试题详解分析

    目录 数组题: 程序一(一维数组): 字符数组 程序二(字符数组): 程序三(字符数组): 程序四(字符数组): 程序五(字符数组): 二维数组 程序六( 二维数组): 指针题 程序七( 指针): 程序八( 指针): 程序九( 指针): 程序十( 指针): 程序十( 图): 程序十一( 指针): 程序十二( 指针): 程序十三( 指针): 指针 和 数组 试题解析 小编,在这里想说一下,c语言的最后一节 C预处理,可能还需要一些时间,因为小编,昨天才下载了虚拟机 和 linux 系统,还没开始安

  • Go语言学习教程之结构体的示例详解

    目录 前言 可导出的标识符 嵌入字段 提升 标签 结构体与JSON相互转换 结构体转JSON JSON转结构体 练习代码步骤 前言 结构体是一个序列,包含一些被命名的元素,这些被命名的元素称为字段(field),每个字段有一个名字和一个类型. 结构体用得比较多的地方是声明与数据库交互时需要用到的Model类型,以及与JSON数据进行相互转换.(当然,项目中任何需要多种数据结构组合在一起使用的地方,都可以选择用结构体) 代码段1:声明一个待办事项的Model类型: type Todo struct

  • C语言动态内存管理malloc柔性数组示例详解

    目录 1.1为什么存在动态内存管理 1.2动态内存管理函数 1.2.1malloc 1.2.2free 1.2.3calloc 1.2.4realloc 1.3动态内存管理函数易错点 1.3.1对NULL指针的解引用操作 1.3.2对动态开辟空间的越界访问 1.3.3对非动态开辟内存使用free释放 1.3.4使用free释放一块动态开辟内存的一部分 1.3.5对同一块动态内存多次释放 1.3.6动态开辟内存忘记释放(内存泄漏) 2.1常见相关笔试题 2.2C/C++语言中的内存开辟 2.3柔性

  • C语言实现顺序表的基本操作的示例详解

    目录 一.认识顺序表 1.线性表 2.顺序表的概念及结构 二.顺序表的基本操作(接口实现) 1.初始化顺序表 2.打印顺序表 3.尾插 4.尾删 5.扩容 6.头插 7.头删 8.任意位置插入 9.任意位置删除 10.查找某个数的位置 三.顺序表演示及代码(含源码) 1.演示效果 2.完整源代码 一.认识顺序表 1.线性表 线性表是n个具有相同特性的数据元素的有限序列,线性表是一种在实际中广泛使用的数据结构,常见的线性表有顺序表.链表.栈.队列.字符串……线性表在逻辑上是线性结构,也就是说是一条

  • C语言静态与动态通讯录的实现流程详解

    目录 静态通讯录 contact.h contact.c test.c 动态通讯录 contact.h contact.c qsort.c test.c 本次通讯录的代码已经放到我的Gitee仓库中,感兴趣的小伙伴可以去看看 Gitee 静态通讯录 在我们学习完C语言的结构体.指针以及动态内存管理之后,我们就可以实现一些有意思的小项目了,通过这些小项目可以加深我们对于相关知识的理解. 静态通讯录主要要求有 静态大小,可以记录10个人的信息(大小自己定) 记录的信息如下:名字.性别.年龄.电话.住

  • C语言头文件<string.h>函数详解

    目录 1. strlen —— 求字符串长度 1.1 strlen 的声明与用处 1.2 strlen 的用法 1.3 strlen 的模拟实现 2. strcpy —— 字符串拷贝 2.1 strcpy 的声明与用处 2.2 strcpy 的用法 2.3 strcpy 的模拟实现 3. strcmp —— 字符串比较 3.1 strcmp 的声明与用处 3.2 strcmp 的用法 3.3 strcmp 的模拟实现 4. strcat —— 字符串追加 4.1 strcat 的声明与用处 4.

  • Golang反射获取变量类型和值的方法详解

    目录 1. 什么是反射 2. reflect.Type 2.1 类型Type和种类Kind 2.2 引用指向元素的类型 2.3 结构体成员类型 3. reflect.Value 3.1 结构体的成员的值 3.2 遍历array.slice 3.3 遍历map 4. 反射的三大定律 4.1 从interface到反射对象 4.2 从反射对象到interface 4.3 通过反射修改对象,该对象值必须是可修改的 1. 什么是反射 反射是程序在运行期间获取变量的类型和值.或者执行变量的方法的能力. G

随机推荐