首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >【C语言】带你层层深入指针——指针详解3(野指针、assert等)

【C语言】带你层层深入指针——指针详解3(野指针、assert等)

作者头像
zore
发布2025-12-30 18:38:39
发布2025-12-30 18:38:39
1210
举报
文章被收录于专栏:C/C++ 专栏C/C++ 专栏

前言: 书接上回,由于文章过长,所以分了几篇文 若内容对大家有所帮助,可以收藏慢慢看,感谢大家支持 谢谢大家 ! ! !

六、野指针

1.野指针是什么?

就像流浪猫、流浪狗一样没有家一样 野指针就是指针指向的位置是未知的

2.野指针的成因

那么为什么会出现野指针呢? 主要有以下几点:

  • 指针未初始化
代码语言:javascript
复制
int * p ;
* p = 20 ;

此处的p指针未初始化,就是一个野指针,其所指向的地址为随机值 而之后的 * p 就会非法访问

  • 指针越界访问

通过指针遍历数组时超出数组范围 就像未经许可闯入他人房间属于非法访问

代码语言:javascript
复制
int arr[10] = {0};
int* p = %arr[0];
p = p + 10;
*p = 100;
//此处的 p 就属于野指针 

当 p 指向数组有效范围(如arr[0 ] ~ arr [ 9 ] )时是合法指针一旦 p 指向 arr [ 10 ] 及之后的位置,就变成野指针 以上末尾的 p 就属于野指针,无法访问 arr[ 11 ] ,越界访问

  • 指针指向已释放空间
代码语言:javascript
复制
#include <stdio.h>

int* test()
{
	int n = 100;
	return &n;
}

int main()
{
	int* p = test();
	printf("%p\n\n", p);

	return 0;
}

当出了 test ( ) 函数时,n 的内存空间被释放 虽然指针变量本身仍存在,但指向的空间已无效 继续通过该指针访问内存可能导致程序崩溃或数据错误 故 p 为野指针,是非法访问

3.如何避免野指针

  • 指针初始化

必须养成指针初始化的习惯,未初始化的指针不知道指向何处 若明确知道指针应指向的地址,直接赋地址值; 若不确定指针指向,应赋值为NULL(空指针) (NULL是C语言中的标识符常量,其值为0)

例如:

代码语言:javascript
复制
int * p = NULL;//此地址无法使用
  • 小心指针越界

不超出范围访问

  • 指针不使用时,置 NULL,使用前检查有效性 例如:
代码语言:javascript
复制
int * p = NULL;//指针不使用时,置 NULL
。。。。。。。
。。。。。。。
。。。。。。。
if( p != NULL)//使用前检查有效性
*p = 100;

当确认不是NULL时再使用该指针

  • 避免返回局部变量的地址

七、assert断言

在编写程序过程中,需要一个提醒代码漏洞/Bug的工具,以便于程序员及时修改和完善代码 assert关键字就是这个工具

1.概念

assert 是定义在 < assert.h > 头文件中的一个宏 用于在运行时确保程序符合指定条件 若不符合条件,就报错 该宏被称为断言

2.使用

代码语言:javascript
复制
assert(p != NULL);

若 p 为空指针,就报错;若不为空,则运行

另外 使用前记得包含头文件<assert.h> 在头文件前面可定义开关来控制 assert # include DEBUG为开 # include NDBUG为关 可随意控制开关

代码演示:(不报错)

代码语言:javascript
复制
#define DEBUG
#include<stdio.h>
#include<assert.h>

int main()
{
	int g = 100;
	int* p = &g;

	assert(p != NULL);

	*p = 1000;
	printf("%d\n\n", g);

	return 0;
}

运行结果:(不报错)

在这里插入图片描述
在这里插入图片描述

代码演示:(报错)

代码语言:javascript
复制
#define DEBUG//定义控制assert打开
#include<stdio.h>
#include<assert.h>

int main()
{
	int g = 100;
	int* p = &g;

	p = NULL;
	assert(p != NULL);

	*p = 1000;
	printf("%d\n\n", g);

	return 0;
}

运行结果:(报错)

在这里插入图片描述
在这里插入图片描述

我们可以看到打印了如下信息: Assertion failed: p != NULL, file D:\学校\C语言\QwQ\QwQ\QwQ.c, line 11 (这就是错误的具体位置)

这就是assert的好处了: 可以自动标识文件和出问题的行号

代码演示:(关闭assert)

代码语言:javascript
复制
#define NDEBUG//定义控制assert关闭
#include<stdio.h>
#include<assert.h>

int main()
{
	int g = 100;
	int* p = &g;

	p = NULL;
	assert(p != NULL);

	*p = 1000;
	printf("%d\n\n", g);

	return 0;
}

运行结果:

在这里插入图片描述
在这里插入图片描述

这里用 #define NDEBUG 定义控制assert关闭

可以看到,代码正常运行,未出现报错, 如果不仔细发现,是找不到错误的,这就是 asser t的好处了

综上所述,assert的好处还是很多的: 1.可以自动标识文件和出问题的行号 2.可以通过定义来随意控制开关 assert( ) 但是要注意: assert 引入了检查,一定程度上增加了运行时间,故确定指针无问题后,可禁用 assert 来减少运行时间 另外,VS 中 Release 版本中默认优化了 assert

八、const 修饰指针

1.const 修饰变量

变量 n 被 const 修饰后,致使无法直接修改 n ,修改就会报错

代码演示:

代码语言:javascript
复制
#include <stdio.h>

int main()
{
	const int n = 10;//const 修饰变量
	n = 100;

	printf("%d\n\n", n);

	return 0;
}

运行结果:(报错)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

这里可见: const 阻止了对变量 n 的修改,若要强行直接修改就会报错停止运行

但是,不能直接对值进行修改,能通过地址对 变量进行修改 代码演示:

代码语言:javascript
复制
#include <stdio.h>

int main()
{
	const int n = 10;//const修饰变量
	int* p = &n;//取出n的地址
	*p = 100;//通过指针对n进行修改

	printf("%d\n\n", n);

	return 0;
}

运行结果:

在这里插入图片描述
在这里插入图片描述

这里可以看到,n 的值确实被指针间接修改了 所以const 修饰变量后不能直接对值进行修改,但能通过地址对变量进行修改

2.const 修饰指针变量

const 修饰指针变量有两种形式 1.int * p ;(无修饰) 2.int const * p ;const int * p ;(const放在 * 左边修饰) 3.int * const p ;(const放在 * 右边修饰)

(1)const放在 * 左边修饰
代码语言:javascript
复制
int const * p ;
const int * p ;
//二者等价

限制的是指针指向的内容( 即 * p ) 不能通过指针变量来修改它所指向的内容 但指针变量本身的内容( 存储的地址 )可以改变

代码演示:(改变指针所指向的内容)(报错)

代码语言:javascript
复制
#include <stdio.h>

int main()
{
	int n = 10;

	int const* p = &n;
	//取出n的地址
	//const修饰指针变量

	*p = 100;//通过指针对n进行修改

	printf("%d\n\n", n);

	return 0;
}

运行结果:(改变指针所指向的内容)(报错)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

代码演示:(改变指针本身内容)(不报错)

代码语言:javascript
复制
#include <stdio.h>

int main()
{
	int n = 10;
	int m = 100;

	int const* p = &n;
	//取出n的地址
	//const修饰指针变量

	p = &m;//改变 p 指针的内容

	printf("%d\n\n", *p);

	return 0;
}

运行结果:(改变指针本身内容)(不报错)

在这里插入图片描述
在这里插入图片描述

由以上两段代码可知:

const放在 * 左边修饰指针变量: 限制的是指针指向的内容( 即 * p ) 不能通过指针变量来修改它所指向的内容 但指针变量本身的内容( 存储的地址 )可以改变

(2)const放在 * 右边修饰
代码语言:javascript
复制
int * const p ;

与const放在 * 左边修饰相反 限制的是指针变量本身的内容 不能修改指针变量本身的内容( 存储的地址 ) 但指针指向的内容( 即 * p )可以改变

代码演示:(改变指针本身内容)(报错)

代码语言:javascript
复制
#include <stdio.h>

int main()
{
	int n = 10;
	int m = 100;

	int* const p = &n;
	//取出n的地址
	//const修饰指针本身内容

	p = &m;//改变 p 指针的内容

	printf("%d\n\n", *p);

	return 0;
}

运行结果:(改变指针本身内容)(报错)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

代码演示:(改变指针所指向的内容)(不报错)

代码语言:javascript
复制
#include <stdio.h>

int main()
{
	int n = 10;

	int* const p = &n;
	//取出n的地址
	//const修饰指针本身内容

	*p = 100;

	printf("%d\n\n", n);

	return 0;
}

运行结果:(改变指针所指向的内容)(不报错)

在这里插入图片描述
在这里插入图片描述

由以上两段代码可知:

const放在 * 右边修饰变量: 限制的是指针变量本身的内容 不能修改指针变量本身的内容( 存储的地址 ) 但指针指向的内容( 即 * p )可以改变

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2025-12-01,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 六、野指针
    • 1.野指针是什么?
    • 2.野指针的成因
    • 3.如何避免野指针
  • 七、assert断言
    • 1.概念
    • 2.使用
  • 八、const 修饰指针
    • 1.const 修饰变量
    • 2.const 修饰指针变量
      • (1)const放在 * 左边修饰
      • (2)const放在 * 右边修饰
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档