指针基础知识2

news/2025/2/9 5:18:51 标签: c语言, 学习, 其他

1. 指针运算

1.1 指针 +- 整数

以数组举例:因为数组在内存中是连续存放的,只要知道第⼀个元素的地址,顺藤摸瓜就能找到后面的所有元素。这时就会用到指针加减整数。

1.2指针-指针

指针 - 指针可以得到两个指针之间的数据个数。但是,要注意这种运算前提是,两个指针指向同一块空间。如:数组空间,字符串,动态开辟的一块空间等。

例如:对于字符串类型,两个指针采用左闭右开的形式相减,就能得到字符串内的字符个数。

1.3指针的关系运算

指针之间支持各类关系运算符(< , > , == , != 等)

2. 野指针

概念:野指针就是指针指向的位置是不可知的(随机的、不正确的、没有明确限制的

1.  野指针成因(举例)

1.1 指针未初始化

   

1.2. 指针越界访问

当指针指向的范围超出数组arr的范围时,p就是野指针。

1.3 指针指向的空间已释放

在这段代码里,我们调用 test 函数,为其创建函数栈帧,函数调用结束时栈帧销毁。临时变量 n 也销毁,这时候为 n 分配的空间就已经被操作系统回收,这时候操作系统有可能将这段空间另做处理,如果我们将其作为返回值并使用, 就会导致野指针。

2. 如何规避野指针

2.1指针初始化

定义指针变量时,如果明确知道指针指向哪里就直接赋值地址,如果不知道指针应该指向哪里,可以给指针赋值NULL.

NULL 是C语言中定义的⼀个标识符常量,也就是空指针,它值是0,0也是地址,并且这个地址是无法使用的,读写该地址会报错。

2.2 小心指针越界

⼀个程序向内存申请了哪些空间,通过指针也就只能访问哪些空间,不能超出范围访问,超出了就是越界访问对于越界访问,虽然编译器有时候不会报错,但这无疑是一种危险行为。

2.3 合理处理指针变量

指针变量不再使用时,及时置NULL,指针使用之前检查有效性。

所以我们默认被赋予NULL的指针变量不可被使用,如果要使用需另做处理。

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

如造成野指针的第3个例子,不要返回局部变量的地址。

3. assert 断言

3.1简介

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

3.2 简单例子

上面代码在程序运行到这一行语句时,验证变量 p 是否等于 NULL 。如果确实不等于 NULL ,程序继续运行,否则就会终止运行,并且给出报错信息提示。

如果已经确认程序没有问题,不需要再做断言,就在 #include 语句的前面,定义⼀个宏 NDEBUG 。

然后,重新编译程序,编译器就会禁用文件中所有的 assert() 语句。

3.3使用小结

总结:assert() 的缺点是,因为引入了额外的检查,增加了程序的运行时间。

一般我们可以在 Debug 中使用,在 Release 版本中选择禁用assert 就行,在 VS 这样的集成开 发环境中,在 Release 版本中,直接就是优化掉了。这样在 debug 版本写有利于程序员排查问题, 在 Release 版本不影响用户使用时程序的效率。

4. 传值调用和传址调用

学习指针的目的是使用指针解决问题的,在C语言中,有时候就不得不用到指针。

4.1 传值调用

在实践传值调用有可能达不到我们的目的。

例如:写⼀个函数,交换两个整型变量的值。

在main函数内部,创建了a和b,在调用 swap 函数时,将实参a,b传给了形参x,y。

但x的地址和a的地址不一样,y的地址和b的地址不⼀样,相当于x和y是独立的空间,那么在swap函数内部交换x和y的值, 就不会影响a和b。

结论:实参传递给形参的时候,形参会单独创建一份临时空间来接收实参,对形参的修改不影响实 参。

4.2 传址调用

想要在 swap 函数中交换a,b,就需要在main函数中将a和b的地址传递给swap函数,在 swap 函数里通过地址间接的操作main函数中的a和b,达到交换的效果。

所以,传址调用可以让函数和主调函数之间建立真正的联系,在函数内部可以修改主函数中的变量。


http://www.niftyadmin.cn/n/5845535.html

相关文章

Vite 代理下的 POST 请求跨域问题排查与解决方案

&#x1f4cc; 问题描述 在 Vite 开发环境中&#xff0c;我遇到了一个奇怪的现象&#xff1a; GET 请求可以成功返回数据POST 请求却返回 403 Forbidden: Invalid CORS request但如果我手动使用 fetch 直接请求服务器 API&#xff0c;POST 请求可以成功 我的 Vite 代理配置如…

kafka专栏解读

kafka专栏文章的编写将根据kafka架构进行编写&#xff0c;即先编辑kafka生产者相关的内容&#xff0c;再编写kafka服务端的内容&#xff08;这部分是核心&#xff0c;内容较多&#xff0c;包含kafka分区管理、日志存储、延时操作、控制器、可靠性等&#xff09;&#xff0c;最后…

SQL写法:行行比较

环境准备 数据库版本&#xff1a;MySQL 5.7.20-log 建表 SQL DROP TABLE IF EXISTS t_ware_sale_statistics; CREATE TABLE t_ware_sale_statistics ( id bigint(20) NOT NULL AUTO_INCREMENT COMMENT 主键id, business_id bigint(20) NOT NULL COMMENT 业务机构编码, w…

docker grafana安装

mkdir /root/grafana-storage chmod 777 -R /root/grafana-storage docker run -d -p 3000:3000 --namedocker-apisix-grafana-1 --network docker-apisix_apisix -v /root/grafana-storage:/var/lib/grafana grafana/grafana:9.1.0 浏览器访问&#xff1a; http://192.…

【ubuntu下验证下菜品识别,训练,部署,验证 CNN + TensorFlow / PyTorch】

下来我会详细介绍如何在 Ubuntu 上运行你训练和部署的 菜品识别模型,确保每一步都能理解并能在你的系统中运行。 环境准备 1.1 安装必要的软件 在 Ubuntu 上,首先需要安装 Python 和相关的依赖库:更新系统: 打开终端,运行以下命令: bash sudo apt update && su…

Linux 调用可执行程序

Linux 调用可执行程序 1. system() 函数1.1 system() 函数的声明1.2 system() 函数的不同场景返回值1.3 system() 函数的代码示例 2. exec() 函数族2.1 exec() 函数族的声明2.2 exec() 函数族执行失败的情况2.3 exec() 函数族的代码示例 3. exec() 与 system() 的区别以及使用注…

B+树原理详解及C语言实现

目录 B树的原理 B树的操作过程&#xff08;图形化演示&#xff09; B树的应用场景 B树与B树的对比 C语言实现及应用实例 文件结构 总结 B树的原理 B树是B树的一种变体&#xff0c;广泛应用于数据库和文件系统中。其原理和特点如下&#xff1a; 数据结构&#xff1a;B树…

【实用技能】如何借助3D文档控件Aspose.3D, 在Java中无缝制作 3D 球体

概述 创建 3D 球体是 3D 图形设计的一个基本方面。无论您是在开发游戏、模拟还是可视化&#xff0c;无缝创建 3D 球体模型的能力都至关重要。Aspose.3D通过提供强大的 3D 图形 SDK 在各个行业中发挥着重要作用。它允许开发人员轻松创建、操作和转换 3D 模型。此 SDK 对于希望将…