C语言指针详解续

深入理解指针 (2)

一、如何规避野指针

1、指针的初始化

如果明确知道指针指向哪里,则直接赋值。如果不知道指针指向哪里,则可以给指针赋值NULL。
NULL:C语言中定义的一个标识符常量,值是0,0也是地址,此地址是无法使用的,读写该地址会报错。

int main()
{
	int a = 10;
	int* p = &a;//初始化

	int* ptr = NULL;//空指针
	*ptr = 100;//nullptr,报错

	return 0;
}

注:初始化为NULL指针就不要去访问

2、小心指针越界

一个程序向内存申请空间,则通过指针只能访问所申请的空间,不能超出范围访问,超出则越界访问。(详细讲解在主页)

1、指针不再使用时,及时设置为NULL

用于指针使用前检查有效性。在使用前判断指针是否安全,可避免错误。

int main()
{
	int a = 10;
	int* p = &a;
	int* ptr = NULL;
	if (p != NULL)
	{
		//使用p
	}
	if (ptr != NULL)
	{
		*ptr = 100;
	}
	return 0;
}


变量未初始化时使用,会造成野指针

int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	int* p = arr;
	int i = 0;
	int sz = sizeof(arr) / sizeof(arr[0]);
	for (i = 0; i < sz; i++)
	{
		printf("%d ", *p);
		p++;
	}
	//在这里继续使用p的话,p就是野指针了
	p = NULL;

	p = arr;
	if (p != NULL)
	{
		//使用
	}

	return 0;
}


再例如 返回栈空间地址的问题,走出函数后,函数则被销毁,很容易造成野指针问题,可以使用以上方法规避

int* test()
{
	//局部变量
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	//...
	return arr;
}
int main()
{
	int* p = test();
	//此时p就是野指针
	return 0;
}

二、assert断言

assert.h头文件定义宏assert( ),用于在允许时确保程序符合指定条件,如果不符合,就报错种植运行。这个宏常常被称为:“断言”。

assert(p != NULl);

assert(p);

在代码运行到这一行语句,验证变量p是否等于NULL,若不等于NULL,程序继续运行,否则终止运行,并给出报错信息。

assert( ) 宏接受一个表达式作为参数。如果表达式为真(返回值非零),assert( )不会产生任何作用,程序正常运行。如果该表达式为假(返回值为零),**assert( )**就会报错。

#include <assert.h>
int main() {
	int a = 10;
	int* p = NULL;
	assert(p != NULL);

	return 0;
}

在屏幕上会出现一条错误信息,显示没有通过的表达式,以及包含整个表达式的文件名和行号
在这里插入图片描述
若不需要断言,可以在 #include <assert.h> 输入 #define NDEBUG

#define NDEBUG
#include <assert.h>
int main() {
	int a = 10;
	int* p = NULL;
	assert(p != NULL);

	return 0;
}

在这里插入图片描述

assert( ) 的优点是,保证了指针的有效性。
assert( ) 的缺点是,因为引入了额外的检查,会稍微增加程序的运行实践。

一般我们在debug下使用,在release版本下,例如VS这类开发环境,在release下,直接优化掉了。这样有利于程序员排查问题(debug),而不影响用户使用效率(release)

三、指针的使用和传址

1、传值调用

将变量传递给函数,这种函数调用方式叫做:传值调用

int Max(int x, int y)
{
	if (x > y)
		return x;
	else
		return y;
}

int main()
{
	int a = 100;
	int b = 20;

	//传值调用
	int m = Max(a, b);
	printf("%d\n", m);

	return 0;
}

但是
一些传值调用需要分情况而定

例如,写一个函数,用于交换两个整形变量的值

void Swap(int x,int y)
{
int z= 0;//临时变量
z = x;
x = y;
y = z;
}
int main()
{
	int a = 10;
	int b = 20;

	printf("交换前:a=%d b=%d\n", a, b);
	Swap(a, b);

	printf("交换后:a=%d b=%d\n", a, b);
	return 0;
}
交换前:a=10 b=20
交换后:a=10 b=20

传值调用的时候,函数实参传递给形参后,
形参是实参的一份临时拷贝,
形参有自己独立的空间,
所以对形参的修改不能影响实参。

所以
在函数内部想要改变函数外部的变量,就需要传址调用。

2、传址调用

将变量的地址传递给函数,这种函数调用方式叫做:传址调用

void Swap(int* px, int* py)
{
	int z = 0;//临时变量
	z = *px;//z = a
	*px = *py;//a=b
	*py = z;//b = a
}
int main()
{
	int a = 10;
	int b = 20;

	printf("交换前:a=%d b=%d\n", a, b);

	Swap(&a, &b);

	printf("交换后:a=%d b=%d\n", a, b);
	return 0;
}

交换前:a=10 b=20
交换后:a=20 b=10

————————

有问题请指出…

  • 6
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
1. 智慧社区背景与挑战 随着城市化的快速发展,社区面临健康、安全、邻里关系和服务质量等多方面的挑战。华为技术有限公司提出智慧社区解决方案,旨在通过先进的数字化技术应对这些问题,提升城市社区的生活质量。 2. 技术推动智慧社区发展 技术进步,特别是数字化、无线化、移动化和物联化,为城市社区的智慧化提供了可能。这些技术的应用不仅提高了社区的运行效率,也增强了居民的便利性和安全性。 3. 智慧社区的核心价值 智慧社区承载了智慧城市的核心价值,通过全面信息化处理,实现对城市各个方面的数字网络化管理、服务与决策功能,从而提升社会服务效率,整合社会服务资源。 4. 多层次、全方位的智慧社区服务 智慧社区通过构建和谐、温情、平安和健康四大社区模块,满足社区居民的多层次需求。这些服务模块包括社区医疗、安全监控、情感沟通和健康监测等。 5. 智慧社区技术框架 智慧社区技术框架强调统一平台的建设,设立数据中心,构建基础网络,并通过分层建设,实现平台能力及应用的可持成长和扩展。 6. 感知统一平台与服务方案 感知统一平台是智慧社区的关键组成部分,通过统一的RFID身份识别和信息管理,实现社区服务的智能化和便捷化。同时,提供社区内外监控、紧急救助服务和便民服务等。 7. 健康社区的构建 健康社区模块专注于为居民提供健康管理服务,通过整合医疗资源和居民接入,实现远程医疗、慢性病管理和紧急救助等功能,推动医疗模式从治疗向预防转变。 8. 平安社区的安全保障 平安社区通过闭路电视监控、防盗报警和紧急求助等技术,保障社区居民的人身和财产安全,实现社区环境的实时监控和智能分析。 9. 温情社区的情感沟通 温情社区着重于建立社区居民间的情感联系,通过组织社区活动、一键呼叫服务和互帮互助平台,增强邻里间的交流和互助。 10. 和谐社区的资源整合 和谐社区作为社会资源的整合协调者,通过统一接入和身份识别,实现社区信息和服务的便捷获取,提升居民生活质量,促进社区和谐。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值