C语言学习:速通指针(2)
这里要学习的有以下内容
1. const修饰指针
2. 野指针
3. assert断⾔
4. 指针的使⽤和传址调⽤
那么从这里开始
1. const 修饰指针
const修饰变量
首先我们知道变量是可以修改的,如果把变量的地址交给⼀个指针变量,通过指针变量的也可以修改这个变量。 但是如果我们不希望这个变量被修改,那我们该怎么做呢?
那么在这里就可以使用const。const的作用就是保持变量不被更改。
#include int main()
{int m = 0;m = 20;//m是可以修改的 const int n = 0; n = 20;//n是不能被修改的 return 0;
}
上述代码中n是不能被修改的,其实n本质是变量,只不过被const修饰后,在语法上加了限制,只要我 们在代码中对n进⾏修改,就不符合语法规则,就报错,致使没法直接修改n。
那么在这里我害怕不小心将n修改所以给n加上const,但是我又需要对n进行修改那么给n加上const就一定写死无法更改了吗?
当然不是,这时我们可以绕过n,使⽤n的地址,去修改n就能做到了,虽然这样做是在打破语法规则。
#include int main()
{ const int n = 0;printf("n = %d\n", n); int* p = &n; *p = 20; printf("n = %d\n", n); return 0;
}
输出结果:
程序运⾏结果 我们可以看到这⾥⼀个确实修改了,但是我们还是要思考⼀下,为什么n要被const修饰呢?就是为了 不能被修改,如果p拿到n的地址就能修改n,这样就打破了const的限制,这是不合理的,所以应该让 p拿到n的地址也不能修改n,那接下来怎么做呢?
const 修饰指针变量 ⼀般来讲const修饰指针变量,可以放在*的左边,也可以放在*的右边,意义是不⼀样的。 int * p;//没有const修饰?
int const * p;//const 放在*的左边做修饰
int * const p;//const 放在*的右边做修饰
我们看下⾯代码,来分析具体分析⼀下:
#include<stdio.h>//代码1 - 测试⽆const修饰的情况
void test1()
{ int n = 10; int m = 20; int* p = &n; *p = 20;//可更改 p = &m; //可更改
}
//代码2 - 测试const放在*的左边情况
void test2()
{ int n = 10; int m = 20; const int* p = &n; *p = 20;//不可更改p = &m; //可更改
}
//代码3 - 测试const放在*的右边情况
void test3()
{ int n = 10; int m = 20; int * const p = &n; *p = 20; //可更改p = &m; //不可更改
}//代码4 - 测试*的左右两边都有const
void test4()
{ int n = 10; int m = 20; int const * const p = &n; *p = 20; //不可更改 p = &m; //不可更改
}int main()
{ //测试⽆const修饰的情况 test1(); //测试const放在*的左边情况 test2(); //测试const放在*的右边情况 test3(); //测试*的左右两边都有const test4(); return 0;
}
结论:const修饰指针变量的时候
• const如果放在*的左边,修饰的是指针指向的内容,保证指针指向的内容不能通过指针来改变。 但是指针变量本⾝的内容可变。
• const如果放在*的右边,修饰的是指针变量本⾝,保证了指针变量的内容不能修改,但是指针指 向的内容,可以通过指针改变。
2. 野指针
概念: 野指针就是指针指向的位置是不可知的(随机的、不正确的、没有明确限制的)
2.1 野指针成因
1. 指针未初始化
#include <stdio.h>int main()
{ int *p;//局部变量指针未初始化,默认为随机值 ,这时p就为野指针*p = 20; return 0;
}
2. 指针越界访问
#include <stdio.h>
int main()
{int arr[10] = {0};int *p = &arr[0];int i = 0;for(i = 0; i <= 11; i++)
{//当指针指向的范围超出数组arr的范围时,p就是野指针*(p++) = i;
}return 0;
}
2.2 如何规避野指针
2.2.1 指针初始化
如果明确知道指针指向哪⾥就直接赋值地址,如果不知道指针应该指向哪⾥,可以给指针赋值NULL. NULL 是C语⾔中定义的⼀个标识符常量,值是0,0也是地址,这个地址是⽆法使⽤的,读写该地址 会报错。
初始化如下:
#include <stdio.h>
int main()
{ int num = 10; int*p1 = #int*p2 = NULL; return 0;
}
2.2.2 ⼩⼼指针越界
⼀个程序向内存申请了哪些空间,通过指针也就只能访问哪些空间,不能超出范围访问,超出了就是 越界访问,也就成为了野指针
2.2.3 将指针置为空
在指针使用结束后要将指针置为NULL,避免他对代码以后的使用的过程中造成影响。
int main()
{int arr[10] = {1,2,3,4,5,6,7,8,9,10};int *p = &arr[0];int i = 0;for(i=0; i<10; i++)
{*(p++) = i;
}//此时p已经越界了,可以把p置为NULLp = NULL;//下次使⽤的时候,判断p不为NULL的时候再使⽤//...p = &arr[0];//重新让p获得地址if(p != NULL) //判断{//...}return 0;
}
2.2.4 避免返回局部变量的地址
如造成野指针的第3个例⼦,不要返回局部变量的地址。
3. assert 断⾔
assert.h 头⽂件定义了宏 assert() ,⽤于在运⾏时确保程序符合指定条件,如果不符合,就报 错终⽌运⾏。这个宏常常被称为“断⾔”。
assert(p != NULL);
上⾯代码在程序运⾏到这⼀⾏语句时,验证变量 p 是否等于 NULL 。如果确实不等于 NULL ,程序 继续运⾏,否则就会终⽌运⾏,并且给出报错信息提⽰。
assert() 宏接受⼀个表达式作为参数。
如果该表达式为真(返回值⾮零), assert() 不会产⽣ 任何作⽤,程序继续运⾏。
如果该表达式为假(返回值为零), assert() 就会报错,在标准错误 流 stderr 中写⼊⼀条错误信息,显⽰没有通过的表达式,以及包含这个表达式的⽂件名和⾏号。
使⽤ assert() 有⼏个好处:它不仅能⾃动标识⽂件和 出问题的⾏号,还有⼀种⽆需更改代码就能开启或关闭 assert() 的机制。
当我们已经确认程序没有问题,不需要再做断⾔,只需要在 #include 语句的前⾯,定义⼀个宏 NDEBUG 就可以了,无需再进行其他操作。
#define NDEBUG
#include <assert.h>
然后,重新编译程序,编译器就会禁⽤⽂件中所有的 assert() 语句。
当程序⼜出现问题,只需要移除这条 #define NDEBUG 指令(或者把它注释掉),再次编译,这样就重新启⽤了 assert() 语句。
然而assert也是有缺点的
assert() 的缺点是,因为引⼊了额外的检查,增加了程序的运⾏时间。
为了解决这个问题,⼀般我们可以在 Debug 中使⽤,在 Release 版本中选择禁⽤ assert 就⾏,
在 VS 这样的集成开发环境的 Release 版本中,assert就直接被优化掉了。这样在debug版本写有利于程序员排查问题, 在 Release 版本不影响⽤⼾使⽤时程序的效率。
4. 指针的使⽤和传址调⽤
4.1 传值调⽤和传址调⽤
学习指针的⽬的是使⽤指针解决问题,那什么问题,⾮指针不可呢?
例如:写⼀个函数,交换两个整型变量的值 ⼀番思考后,我们可能写出这样的代码:
#include <stdio.h>
void Swap1(int x, int y)
{int tmp = x;x = y;y = tmp;
}
int main()
{int a = 0;int b = 0;scanf("%d %d", &a, &b);printf("交换前:a=%d b=%d\n", a, b);Swap1(a, b);printf("交换后:a=%d b=%d\n", a, b);return 0;
}

我们发现在main函数内部,创建了a和b,(这里假设地址) :a的地址是0x00cffdd0,b的地址是0x00cffdc4。在调⽤ Swap1函数时,将a和b传递给了Swap1函数,在Swap1函数内部创建了形参x和y接收a和b的值,但是 x的地址是0x00cffcec,y的地址是0x00cffcf0,x和y确实接收到了a和b的值,不过x的地址和a的地址不 ⼀样,y的地址和b的地址不⼀样,相当于x和y是独⽴的空间,那么在Swap1函数内部交换x和y的值, ⾃然不会影响a和b,当Swap1函数调⽤结束后回到main函数,a和b实际上没有交换。Swap1函数在使⽤ 的时候,是把变量本⾝直接传递给了函数,这种调⽤函数的⽅式我们之前在函数的时候就知道了,这 种叫传值调⽤。
结论:实参传递给形参的时候,形参会单独创建⼀份临时空间来接收实参,对形参的修改不影响实 参。
在这里可以使用传址调用
#include <stdio.h>
void Swap2(int*px, int*py)
{int tmp = 0;tmp = *px;*px = *py;*py = tmp;
}
int main()
{int a = 0;int b = 0;scanf("%d %d", &a, &b);printf("交换前:a=%d b=%d\n", a, b);Swap2(&a, &b);printf("交换后:a=%d b=%d\n", a, b);return 0;
}

我们可以看到实现成Swap2的⽅式,顺利完成了任务,这⾥调⽤Swap2函数的时候是将变量的地址传 递给了函数,这样就直接改变了原地址处的数据。
这种函数调⽤⽅式叫:传址调⽤。
在这里可以使用这个方法来实现strlen函数的实现这里可以参看以前的博客:C语言学习:速通字符串函数-CSDN博客文章浏览阅读880次,点赞68次,收藏14次。在编程的过程中我们不免会对字符穿进行操作,那么我们就会经常使用字符串函数。那么这里我就给分享四个字符串函数。https://blog.csdn.net/2402_87907999/article/details/143661229?fromshare=blogdetail&sharetype=blogdetail&sharerId=143661229&sharerefer=PC&sharesource=2402_87907999&sharefrom=from_link
感谢观看,有兴趣的话,点赞,收藏,关注,来一波吧。制作过程中如有错误希望可以慷慨指出。最后有更多想法可以一起在评论区聊一聊,私信我也可以哦
相关文章:
C语言学习:速通指针(2)
这里要学习的有以下内容 1. const修饰指针 2. 野指针 3. assert断⾔ 4. 指针的使⽤和传址调⽤ 那么从这里开始 1. const 修饰指针 const修饰变量 首先我们知道变量是可以修改的,如果把变量的地址交给⼀个指针变量,通过指针变量的也可以修改这个变…...
windows 上ffmpeg编译好的版本选择
1. Gyan.dev Gyan.dev 是一个广受信赖的 FFmpeg 预编译库提供者,提供多种版本的 FFmpeg,包括静态和动态链接版本。 下载链接: https://www.gyan.dev/ffmpeg/builds/ 特点: 提供最新稳定版和开发版。 支持静态和共享(动态&…...
Java设计模式笔记(二)
十四、模版方法模式 1、介绍 1)模板方法模式(Template Method Pattern),又叫模板模式(Template Patern),在一个抽象类公开定义了执行它的方法的模板。它的子类可以按需重写方法实现,但调用将以抽象类中定义的方式进行。 2&…...
Vue CLI的作用
Vue CLI(Command Line Interface)是一个基于Vue.js的官方脚手架工具,其主要作用是帮助开发者快速搭建Vue项目的基础结构和开发环境。以下是Vue CLI的具体作用: 1、项目模板与快速生成 Vue CLI提供了一系列预设的项目模板&#x…...
短视频矩阵系统开发|技术源代码部署
短视频矩阵系统通过多账号运营管理、多平台视频智能分发等功能,助力企业实现视频引流、粉丝沉淀和转化。 短视频矩阵系统是一种创新的营销工具,它整合了多账号管理、视频智能分发、数据可视化等多种功能,为企业在短视频领域的发展提供了强大…...
Erlang socket编程(二)
模拟服务器和客户端通信 %%%------------------------------------------------------------------- %%% author Administrator %%% copyright (C) 2024, <COMPANY> %%% doc %%% %%% end %%% Created : 03. 12月 2024 22:28 %%%---------------------------------------…...
工业检测基础-线扫相机和面阵相机参数及应用
以下是工业面阵相机和线扫相机的重要参数、应用场景以及调节方法的科普: 重要参数 分辨率: 面阵相机:由相机所采用的芯片分辨率决定,常用的有500万、1200万、6500万等像素,一般用长宽表示。如19201080等,…...
【无标题】建议用坚果云直接同步zotero,其他方法已经过时,容易出现bug
created: 2024-12-06T16:07:45 (UTC 08:00) tags: [] source: https://zotero-chinese.com/user-guide/sync author: 数据与文件的同步 | Zotero 中文社区 Excerpt Zotero 中文社区,Zotero 中文维护小组,Zotero 插件,Zotero 中文 CSL 样式 数…...
基于STM32设计的智能宠物喂养系统(华为云IOT)_273
文章目录 一、前言1.1 项目介绍【1】项目开发背景【2】设计实现的功能【3】项目硬件模块组成【4】设计意义【5】国内外研究现状【6】摘要1.2 设计思路1.3 系统功能总结1.4 开发工具的选择【1】设备端开发【2】上位机开发1.5 参考文献1.6 系统框架图1.7 系统原理图1.8 实物图1.9…...
cesium truf 利用缓冲如何将一个点缓冲成一个方形
: 在Cesium中如果你想要一个更简单的方法将一个点缓冲成一个方形区域,你可以考虑以下步骤: 确定中心点:首先,你需要有一个中心点的经纬度坐标。计算边长:确定你想要缓冲的方形的边长,这里以10…...
HarmonyOS 5.0应用开发——Ability与Page数据传递
【高心星出品】 文章目录 Ability与Page数据传递Page向Ability传递数据Ability向Page传递数据 Ability与Page数据传递 基于当前的应用模型,可以通过以下几种方式来实现UIAbility组件与UI之间的数据同步。 使用EventHub进行数据通信:在基类Context中提供…...
【推荐算法】推荐系统的评估
这篇文章是笔者阅读《深度学习推荐系统》第五章推荐系统的评估的学习笔记,在原文的基础上增加了自己的理解以及内容的补充,在未来的日子里会不断完善这篇文章的相关工作。 文章目录 离线评估划分数据集方法客观评价指标P-R曲线ROC/AUCmAPNDCG A/B 测试分…...
鸿蒙:实现类似Android.9图的图片资源呈现
问题: 在鸿蒙中,是识别不了.9格式的图片资源的,那么如何实现.9图效果呢。? 解决方案: 首先需要将图片资源转为普通的png格式。如果是背景图的,需要换一种方式来处理,目前我所实现的方案是通过St…...
ros2人脸检测
第一步: 首先在工作空间/src下创建数据结构目录service_interfaces ros2 pkg create service_interfaces --build-type ament_cmake 然后再创建一个srv目录 在里面创建FaceDetect.srv(注意,首字母要大写) sensor_msgs/Image …...
Pillow:强大的Python图像处理库
目录 一、引言 二、Pillow 库的安装 三、Pillow 库的基本概念 四、图像的读取和保存 五、图像的基本属性 六、图像的裁剪、缩放和旋转 七、图像的颜色调整 八、图像的滤镜效果 九、图像的合成和叠加 十、图像的绘制 十一、示例程序:制作图片水印 十二、…...
微信小程序uni-app+vue3实现局部上下拉刷新和scroll-view动态高度计算
微信小程序uni-appvue3实现局部上下拉刷新和scroll-view动态高度计算 前言 在uni-appvue3项目开发中,经常需要实现列表的局部上下拉刷新功能。由于网上相关教程较少且比较零散,本文将详细介绍如何使用scroll-view组件实现这一功能,包括动态高度计算、下拉刷新、上拉加载等完整…...
为什么类 UNIX 操作系统通常内置编译器?为什么 Windows 更倾向于直接使用二进制文件?
操作系统是否内置编译器,取决于该系统的设计目标、用户群体以及常见的使用场景。以下是内置编译器和直接使用二进制的设计理念和原因的分析: 为什么类 UNIX 操作系统通常内置编译器? 面向开发者的需求: 类 UNIX 系统(如…...
吉林大学23级数据结构上机实验(第7周)
A 去火车站 寒假到了,小明准备坐火车回老家,现在他从学校出发去火车站,CC市去火车站有两种方式:轻轨和公交车。小明为了省钱,准备主要以乘坐公交为主。CC市还有一项优惠政策,持学生证可以免费乘坐一站轻轨&…...
实验13 使用预训练resnet18实现CIFAR-10分类
1.数据预处理 首先利用函数transforms.Compose定义了一个预处理函数transform,里面定义了两种操作,一个是将图像转换为Tensor,一个是对图像进行标准化。然后利用函数torchvision.datasets.CIFAR10下载数据集,这个函数有四个常见的…...
【开发文档】资源汇总,持续更新中......
文章目录 AI大模型数据集PytorchPythonUltralyticsOpenCVNetronSklearnCMakeListsNVIDIADocker刷题网站持续更新,欢迎补充 本文汇总了一些常用的开发文档资源,涵盖了常用AI大模型、刷题网站、Python、Pytorch、OpenCV、TensorRT、Docker 等技术栈。通过这…...
生成xcframework
打包 XCFramework 的方法 XCFramework 是苹果推出的一种多平台二进制分发格式,可以包含多个架构和平台的代码。打包 XCFramework 通常用于分发库或框架。 使用 Xcode 命令行工具打包 通过 xcodebuild 命令可以打包 XCFramework。确保项目已经配置好需要支持的平台…...
页面渲染流程与性能优化
页面渲染流程与性能优化详解(完整版) 一、现代浏览器渲染流程(详细说明) 1. 构建DOM树 浏览器接收到HTML文档后,会逐步解析并构建DOM(Document Object Model)树。具体过程如下: (…...
Java + Spring Boot + Mybatis 实现批量插入
在 Java 中使用 Spring Boot 和 MyBatis 实现批量插入可以通过以下步骤完成。这里提供两种常用方法:使用 MyBatis 的 <foreach> 标签和批处理模式(ExecutorType.BATCH)。 方法一:使用 XML 的 <foreach> 标签ÿ…...
如何更改默认 Crontab 编辑器 ?
在 Linux 领域中,crontab 是您可能经常遇到的一个术语。这个实用程序在类 unix 操作系统上可用,用于调度在预定义时间和间隔自动执行的任务。这对管理员和高级用户非常有益,允许他们自动执行各种系统任务。 编辑 Crontab 文件通常使用文本编…...
mac 安装homebrew (nvm 及git)
mac 安装nvm 及git 万恶之源 mac 安装这些东西离不开Xcode。及homebrew 一、先说安装git步骤 通用: 方法一:使用 Homebrew 安装 Git(推荐) 步骤如下:打开终端(Terminal.app) 1.安装 Homebrew…...
淘宝扭蛋机小程序系统开发:打造互动性强的购物平台
淘宝扭蛋机小程序系统的开发,旨在打造一个互动性强的购物平台,让用户在购物的同时,能够享受到更多的乐趣和惊喜。 淘宝扭蛋机小程序系统拥有丰富的互动功能。用户可以通过虚拟摇杆操作扭蛋机,实现旋转、抽拉等动作,增…...
Ubuntu系统复制(U盘-电脑硬盘)
所需环境 电脑自带硬盘:1块 (1T) U盘1:Ubuntu系统引导盘(用于“U盘2”复制到“电脑自带硬盘”) U盘2:Ubuntu系统盘(1T,用于被复制) !!!建议“电脑…...
LLaMA-Factory 微调 Qwen2-VL 进行人脸情感识别(二)
在上一篇文章中,我们详细介绍了如何使用LLaMA-Factory框架对Qwen2-VL大模型进行微调,以实现人脸情感识别的功能。本篇文章将聚焦于微调完成后,如何调用这个模型进行人脸情感识别的具体代码实现,包括详细的步骤和注释。 模型调用步骤 环境准备:确保安装了必要的Python库。…...
如何通过git命令查看项目连接的仓库地址?
要通过 Git 命令查看项目连接的仓库地址,您可以使用以下几种方法: 1. 查看所有远程仓库地址 使用 git remote -v 命令,它会显示项目中配置的所有远程仓库及其对应的 URL: git remote -v输出示例: origin https://…...
【题解-洛谷】P10480 可达性统计
题目:P10480 可达性统计 题目描述 给定一张 N N N 个点 M M M 条边的有向无环图,分别统计从每个点出发能够到达的点的数量。 输入格式 第一行两个整数 N , M N,M N,M,接下来 M M M 行每行两个整数 x , y x,y x,y,表示从 …...
