当前位置: 首页 > news >正文

C语言:深入理解指针(2)

1. const 修饰指针

1.1 const 修饰变量

        变量是可以修改的,但当我们想加上一些限制使某个变量不能修改,这时就会用到 const。

        我们可以看到,当 x 被 const 修饰后,再修改 x 时会发生错误。要想解决这个问题,我们可以通过指针来绕开,通过访问 x 地址的方式来间接修改 x 的值,如下图:

        这里用 const 修饰的 x 叫常变量,表示 x 的本质还是变量,但是它不能被修改。上图中我们用 const 就是为了使值不被修改,这样就打破了 const 的限制,,所以我们应该让 p 拿到 x 的地址也不能修改 x。

1.2 const 修饰指针变量、

        const 修饰指针变量时,既可以放到 * 的左边(const int * x 或 int const * x),也可以放到 * 的右边(int * const x),但它们的意义不一样。

        

        从上图我们可以看到如下结论:

        const 如果放到 * 的左边,修饰的是指针指向的内容,保证指针指向的内容不能通过指针来改变,而指针变量本身的内容可以改变(也就是指针中存的地址);

        const 如果放到 * 的右边,修饰的是指针变量本身,保证了指针变量的内容不能修改(也就是指针中存的地址),但是指针指向的内容可以通过指针来改变;

        不仅如此,* 左右两边也可以同时加上 const 来修饰,这样指针指向的内容和指针本身都不能修改。

2. 野指针

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

2.1 野指针的成因

        1.指针位初始化:

#include <stdio.h>
int main()
{int *x;//局部变量指针x未初始化,默认为随机值*x = 20;return 0;
}

        2.指针越界访问:

#include <stdio.h>
int main()
{int arr[10] = {2};int* p = &arr[0];for(int i = 0;i <= 10;i++){*p(++) = 2;//此时循环了11次,超过了 arr 的范围,p就是野指针}return 0;
}

        3.指针指向的空间释放

#include <stdio.h>
int* csdn()
{int x = 3;return &x;
}
int main()
{int* p = csdn();//当返回主函数时 x 的空间被释放,此时p变为野指针return 0;
}

2.2 如何规避

        我们预防野指针的出现时,同样的,首先要对指针进行初始化,若我们开始不知道指针应该指向哪里,可以对指针赋值 NULL 这样,这个地址是无法使用的,读写改地址时会报错;其次,编写代码时要时刻检查代码,防止指针越界;最后,指针不再使用时将其及时置 NULL 因为约定俗成的⼀个规则就是:只要是NULL指针就不去访问, 同时使用指针之前可以判断指针是否为NULL。还要注意不要返回局部变量的地址。

3. assert 断言

        assert.h 头⽂件定义了宏 assert() ,⽤于在运行时确保程序符合指定条件,如果不符合,就报错终止运行。这个宏常常被称为“断⾔”。例如:assert (p != NULLL) 当代码运行到这一段时,验证变量 p 是否等于 NULL,若果不等于则程序继续执行,若等于则终止运行并给出报错信息提示。

        assert() 的使⽤对程序员是非常友好的,使用 assert() 有几个好处:它能自动标出文件和出问题的行号。还有⼀种⽆需更改代码就能开启或关闭 assert() 的机制:如果已经确认程序没有问题,不需要再做断言,就在 #include <assert.h>语句的前面,定义⼀个宏 NDEBUG。

#define NDEBUG
#include <assert.h>

        assert() 的缺点是,因为引⼊了额外的检查,增加了程序的运⾏时间。

4. 指针的使用和传址调用

4.1 strlen的模拟实现

        库函数 strlen 的功能是求字符串⻓度,统计的是字符串中 \0 之前的字符的个数。函数原型如下: size_t strlen ( const char * str );

        参考代码如下:

4.2 传值调用和传址调用

        学习指针后到底有什么作用呢?比如我们来写一个函数:交换两个整型变量的值。

        再没学习指针之前我们可能会写出这样的代码:

        我们发现这样的代码并没有完成任务,因为调用函数时形参 x 和 y 都分别建立了各自的空间,交换值时是在 x 和 y 的空间中交换的,与 a 和 b 没有关系,所以没有交换掉 a 和 b 的值。

        但是当我们用指针时就能很好的解决这个问题;

        我们用指针时指针变量 x 和 y 分别直接指向了 a 和 b 的空间,x和y中分别存放的是 a 和 b 的地址,再通过解引用操作符 * 就能直接访问 a 和 b 中的内容。这样就满足了题目的要求。

http://www.lryc.cn/news/594387.html

相关文章:

  • 网络地址和主机地址之间进行转换的类
  • 剑指offer66_不用加减乘除做加法
  • Spring Boot 订单超时自动取消的 3 种主流实现方案
  • 腾讯二面手撕题:BatchNorm和LayerNorm
  • 08_Opencv_基本图形绘制
  • 学成在线项目
  • Eureka+LoadBalancer实现服务注册与发现
  • 限流算法与实现
  • Shell脚本-tee工具
  • Kafka 在分布式系统中的关键特性与机制深度解析
  • kotlin Flow快速学习2025
  • PostgreSQL实战:高效SQL技巧
  • 【LeetCode刷题指南】--反转链表,链表的中间结点,合并两个有序链表
  • 基于单片机无线防丢/儿童防丢报警器
  • 数据结构 | 栈:构建高效数据处理的基石
  • 【2025最新版】PDFelement全能PDF编辑器
  • [硬件电路-58]:根据电子元器件的控制信号的类型分为:电平控制型和脉冲控制型两大类。
  • LockFile简要分析
  • 《镜语者》
  • RocketMQ学习系列之——MQ入门概念
  • 【基础】——股票市场基础知识宏观
  • 无 sudo 权限的环境下将 nvcc (CUDA Toolkit) 安装到个人目录 linux
  • 【c++】200*200 01灰度矩阵求所有的连通区域坐标集合
  • Numpy库,矩阵形状与维度操作
  • 本地部署 Claude 大语言模型的完整实践指南
  • 数据治理,治的是什么?
  • 建筑墙壁损伤缺陷分割数据集labelme格式7820张20类别
  • 【华为机试】169. 多数元素
  • Spring Cloud Gateway 电商系统实战指南:架构设计与深度优化
  • 最大子数组和问题-详解Kadane算法