[c语言日寄]越界访问:意外的死循环
【作者主页】siy2333
【专栏介绍】⌈c语言日寄⌋:这是一个专注于C语言刷题的专栏,精选题目,搭配详细题解、拓展算法。从基础语法到复杂算法,题目涉及的知识点全面覆盖,助力你系统提升。无论你是初学者,还是进阶开发者,这里都能满足你的需求!
【食用方法】1.根据题目自行尝试 2.查看基础思路完善题解 3.学习拓展算法
【Gitee链接】资源保存在我的Gitee仓库:https://gitee.com/siy2333/study
文章目录
- 前言
- 一、案例
- 二、越界访问
- 什么是越界访问
- 越界访问一般发生在什么地方
- 数组操作
- 指针操作
- 字符串操作
- 动态内存分配
- 结构体和联合体操作
- 函数调用和参数传递
- 系统调用和库函数
- 并发和多线程
- 网络编程
- 三、如何避免越界访问
- 数组操作
- 指针操作
- 字符串操作
- 动态内存分配
- 结构体和联合体操作
- 四、回归案例分析
- 总结
前言
越界访问是一种常见的程序错误,本篇文章将基于一个案例,从什么是数组越界,数组越界经常发生在什么地方,如何预防数据越界三方面来详细介绍该错误。
一、案例
查看以下c语言代码,试写出其运行结果,并说明理由:
#include <stdio.h>
int main()
{int i = 0;int arr[] = { 1,2,3,4,5,6,7,8,9,10 };for (i = 0; i <= 12; i++){arr[i] = 0;//数组越界访问printf("%d\t",i);}return 0;
}
这个代码非常简洁,我们可以很容易的发现其中i的范围是1-12,但是arr数组的大小只有10个int类型,出现了越界访问。
我们在vs2022中,在debug、x86环境下,运行该代码,结果如下:
没错,出现了死循环。但是,为什么呢?
二、越界访问
什么是越界访问
越界访问(Out-of-Bounds Access),也称为缓冲区溢出或越界读写,是一种常见的程序错误。它指的是程序试图访问超出其分配的内存空间的数据。这种行为可能会导致程序崩溃或者被利用来进行恶意攻击。
越界访问一般发生在什么地方
数组操作
- 数组索引超出范围:这是最常见的越界访问类型。例如,对于一个大小为10的数组,尝试访问第11个元素(索引为10)就会导致越界。
- 循环控制不当:在循环中,如果循环条件或索引更新逻辑有误,可能会导致索引超出数组范围。例如:
int arr[10];
for (int i = 0; i <= 10; i++) { // 错误:i <= 10arr[i] = i;
}
指针操作
- 未初始化的指针:如果指针没有被正确初始化,它可能指向一个随机的内存地址,解引用这样的指针会导致越界访问。
- 野指针:指针指向了一个已经被释放或从未分配的内存区域。
- 指针偏移错误:通过指针进行偏移操作时,如果偏移量计算错误,可能会导致指针指向无效的内存地址。
int arr[10];
int* ptr = arr;
ptr += 11; // 错误:ptr指向了数组范围之外
*ptr = 42; // 越界访问
字符串操作
- 字符串长度错误:在处理字符串时,如果字符串长度计算错误,可能会导致越界访问。例如,使用strcpy时,目标字符串的缓冲区大小不足以容纳源字符串,就会导致越界。
- 字符串函数使用不当:使用如strcpy、strcat等不安全的字符串函数,而不是strncpy、strncat等安全的函数,容易导致越界。例如:
char dest[10];
char src[] = "Hello, World!";
strcpy(dest, src); // 错误:src长度超过dest的大小
动态内存分配
- 分配大小错误:在使用malloc、calloc或realloc分配内存时,如果分配的大小不足以满足需求,可能会导致越界访问。
- 释放后使用:释放了动态分配的内存后,仍然尝试访问该内存区域,会导致越界访问。例如:
int* ptr = (int*)malloc(10 * sizeof(int));
free(ptr);
*ptr = 42; // 错误:ptr指向的内存已经释放
结构体和联合体操作
- 结构体成员访问错误:如果结构体的成员访问逻辑有误,可能会导致越界访问。例如,访问结构体中不存在的成员。
- 联合体使用不当:联合体中的成员共享同一块内存,如果访问联合体成员时没有正确处理,可能会导致越界访问。
函数调用和参数传递
- 函数参数错误:传递给函数的参数如果超出预期范围,可能会导致函数内部的越界访问。例如,传递给函数的数组指针和数组大小参数不匹配。
- 递归调用错误:在递归函数中,如果递归条件或递归深度控制不当,可能会导致越界访问。
系统调用和库函数
- 系统调用参数错误:在调用系统函数时,如果传递的参数不正确,可能会导致越界访问。例如,使用read或write系统调用时,传递的缓冲区大小参数错误。
- 库函数使用不当:使用标准库函数时,如果参数不正确或使用方式不当,可能会导致越界访问。例如,使用memcpy时,目标缓冲区大小不足以容纳源数据。
并发和多线程
- 线程同步错误:在多线程环境中,如果线程同步机制不正确,可能会导致多个线程同时访问同一块内存,从而导致越界访问。
- 线程局部存储错误:如果线程局部存储的使用不当,可能会导致越界访问。
网络编程
- 网络数据处理错误:在处理网络数据时,如果数据长度计算错误或缓冲区管理不当,可能会导致越界访问。例如,接收的网络数据长度超过缓冲区大小。
- 协议解析错误:在解析网络协议时,如果协议解析逻辑有误,可能会导致越界访问。
三、如何避免越界访问
数组操作
- 检查索引范围:在访问数组元素之前,始终检查索引是否在合法范围内。
int arr[10];
for (int i = 0; i < 10; i++) {arr[i] = i;
}
- 使用安全的数组操作函数:在C语言中,可以使用如strncpy、strncat等安全的字符串操作函数,而不是strcpy、strcat等可能导致越界的函数。
char dest[10];
char src[] = "Hello, World!";
strncpy(dest, src, sizeof(dest) - 1);
dest[sizeof(dest) - 1] = '\0'; // 确保字符串以null字符结尾
指针操作
- 初始化指针:确保指针在使用前被正确初始化。
int* ptr = NULL;
ptr = (int*)malloc(10 * sizeof(int));
if (ptr == NULL) {// 处理内存分配失败的情况
}
- 检查指针有效性:在解引用指针之前,检查指针是否指向有效的内存地址。
if (ptr != NULL) {*ptr = 42;
}
- 避免野指针:释放指针后,立即将其设置为NULL,以避免后续误用。
free(ptr);
ptr = NULL;
字符串操作
使用安全的字符串函数:使用如strncpy、strncat等安全的字符串操作函数,而不是strcpy、strcat等可能导致越界的函数。
char dest[10];
char src[] = "Hello, World!";
strncpy(dest, src, sizeof(dest) - 1);
dest[sizeof(dest) - 1] = '\0'; // 确保字符串以null字符结尾
动态内存分配
- 检查分配大小:在使用malloc、calloc或realloc分配内存时,确保分配的大小足以满足需求。
int* ptr = (int*)malloc(10 * sizeof(int));
if (ptr == NULL) {// 处理内存分配失败的情况
}
- 释放后不再使用:释放了动态分配的内存后,立即将指针设置为NULL,以避免后续误用。
free(ptr);
ptr = NULL;
结构体和联合体操作
- 检查结构体成员访问:在访问结构体成员时,确保成员存在且访问逻辑正确。
struct {int a;int b;
} s;
s.a = 10; // 正确
// s.c = 20; // 错误:结构体中没有成员c
- 正确使用联合体:联合体中的成员共享同一块内存,确保访问联合体成员时逻辑正确。
union {int a;char b[4];
} u;
u.a = 0x12345678;
// 正确访问联合体成员
四、回归案例分析
我们在第八行添加一个断点,并对代码进行调试:
我们在监视窗口下,逐步观察值的变化:
可以看到,我们的前十次for循环是正常运行的:
那么问题就出现在数组越界后了,我们可以修改监视窗口,使得arr[10]、arr[11]、arr[12]也可以显示出来。
此时,我们可以发现,arr[10]、arr[11]是随机值,但是arr[12]储存了一个值。当我们执行到arr[12]被修改时,监视如下:
没错!i的值被改变了!那么我们可以猜测,i的值是否就是储存在arr[12]处?使用监视验证这个猜想:
答案出来了,可以看见arr[12]的地址和i的地址一模一样,即因为数组越界访问,使得i的值永远无法达到跳出循环的条件。
因此,出现了死循环现象。
总结
通过本文的案例分析,我们深入探讨了数组越界访问这一常见错误。越界访问不仅会导致程序崩溃,还可能引发安全漏洞。本文从越界访问的定义、常见场景及预防方法三个方面进行了详细阐述。在案例中,通过调试,我们发现数组越界访问导致循环变量 i 的值被意外修改,从而引发死循环。
关注窝,每三天至少更新一篇优质c语言题目详解~
[专栏链接QwQ] :⌈c语言日寄⌋CSDN
[关注博主ava]:siy2333
感谢观看~ 我们下次再见!!
相关文章:

[c语言日寄]越界访问:意外的死循环
【作者主页】siy2333 【专栏介绍】⌈c语言日寄⌋:这是一个专注于C语言刷题的专栏,精选题目,搭配详细题解、拓展算法。从基础语法到复杂算法,题目涉及的知识点全面覆盖,助力你系统提升。无论你是初学者,还是…...

【c++11】包装器
🔥个人主页:Quitecoder 🔥专栏:c笔记仓 包装器(Wrapper) 是一个常见的编程设计模式,通常用于封装或“包装”某个现有的对象、函数、数据结构或者操作,以提供额外的功能或简化接口。…...
信息学奥赛一本通 1422:【例题1】活动安排
【题目链接】 ybt 1422:【例题1】活动安排 【题目考点】 1. 贪心 【解题思路】 该题属于区间选点问题,ybt 1324:【例6.6】整数区间 是给定一些区间,选择一些点使得每个区间范围内至少有1个点。 本题为:给定一些区…...

数据库、数据仓库、数据湖有什么不同
数据库、数据仓库和数据湖是三种不同的数据存储和管理技术,它们在用途、设计目标、数据处理方式以及适用场景上存在显著差异。以下将从多个角度详细说明它们之间的区别: 1. 数据结构与存储方式 数据库: 数据库主要用于存储结构化的数据&…...
llama.cpp LLM_CHAT_TEMPLATE_DEEPSEEK_3
llama.cpp LLM_CHAT_TEMPLATE_DEEPSEEK_3 1. LLAMA_VOCAB_PRE_TYPE_DEEPSEEK3_LLM2. static const std::map<std::string, llm_chat_template> LLM_CHAT_TEMPLATES3. LLM_CHAT_TEMPLATE_DEEPSEEK_3References 不宜吹捧中国大语言模型的同时,又去贬低美国大语言…...
深度学习的应用场景及常用技术
深度学习作为机器学习的一个重要分支,在众多领域都有广泛的应用,以下是一些主要的应用场景及常用技术。 1.应用场景 1. 计算机视觉 图像分类 描述:对图像中的内容进行分类,识别出图像中物体所属的类别。例如,在安防领…...

小程序项目-购物-首页与准备
前言 这一节讲一个购物项目 1. 项目介绍与项目文档 我们这里可以打开一个网址 https://applet-base-api-t.itheima.net/docs-uni-shop/index.htm 就可以查看对应的文档 2. 配置uni-app的开发环境 可以先打开这个的官网 https://uniapp.dcloud.net.cn/ 使用这个就可以发布到…...
网件r7000刷回原厂固件合集测评
《网件R7000路由器刷回原厂固件详解》 网件R7000是一款备受赞誉的高性能无线路由器,其强大的性能和可定制性吸引了许多高级用户。然而,有时候用户可能会尝试第三方固件以提升功能或优化网络性能,但这也可能导致一些问题,如系统不…...

微信登录模块封装
文章目录 1.资质申请2.combinations-wx-login-starter1.目录结构2.pom.xml 引入okhttp依赖3.WxLoginProperties.java 属性配置4.WxLoginUtil.java 后端通过 code 获取 access_token的工具类5.WxLoginAutoConfiguration.java 自动配置类6.spring.factories 激活自动配置类 3.com…...

[STM32 - 野火] - - - 固件库学习笔记 - - -十三.高级定时器
一、高级定时器简介 高级定时器的简介在前面一章已经介绍过,可以点击下面链接了解,在这里进行一些补充。 [STM32 - 野火] - - - 固件库学习笔记 - - -十二.基本定时器 1.1 功能简介 1、高级定时器可以向上/向下/两边计数,还独有一个重复计…...

后台管理系统通用页面抽离=>高阶组件+配置文件+hooks
目录结构 配置文件和通用页面组件 content.config.ts const contentConfig {pageName: "role",header: {title: "角色列表",btnText: "新建角色"},propsList: [{ type: "selection", label: "选择", width: "80px&q…...
8.原型模式(Prototype)
动机 在软件系统中,经常面临着某些结构复杂的对象的创建工作;由于需求的变化,这些对象经常面临着剧烈的变化,但是它们却拥有比较稳定一致的接口。 之前的工厂方法和抽象工厂将抽象基类和具体的实现分开。原型模式也差不多&#…...
Python-基于PyQt5,pdf2docx,pathlib的PDF转Word工具(专业版)
前言:日常生活中,我们常常会跟WPS Office打交道。作表格,写报告,写PPT......可以说,我们的生活已经离不开WPS Office了。与此同时,我们在这个过程中也会遇到各种各样的技术阻碍,例如部分软件的PDF转Word需要收取额外费用等。那么,可不可以自己开发一个小工具来实现PDF转…...
13 尺寸结构模块(size.rs)
一、size.rs源码 // Copyright 2013 The Servo Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution. // // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or // http://www.apache.org/licenses/LICENSE…...

STM32单片机学习记录(2.2)
一、STM32 13.1 - PWR简介 1. PWR(Power Control)电源控制 (1)PWR负责管理STM32内部的电源供电部分,可以实现可编程电压监测器和低功耗模式的功能; (2)可编程电压监测器(…...
CSS 样式化表格:从基础到高级技巧
CSS 样式化表格:从基础到高级技巧 1. 典型的 HTML 表格结构2. 为表格添加样式2.1 间距和布局2.2 简单的排版2.3 图形和颜色2.4 斑马条纹2.5 样式化标题 3. 完整的示例代码4. 总结 在网页设计中,表格是展示数据的常见方式。然而,默认的表格样式…...

【python】tkinter实现音乐播放器(源码+音频文件)【独一无二】
👉博__主👈:米码收割机 👉技__能👈:C/Python语言 👉专__注👈:专注主流机器人、人工智能等相关领域的开发、测试技术。 【python】tkinter实现音乐播放器(源码…...
javascript常用函数大全
javascript函数一共可分为五类: •常规函数 •数组函数 •日期函数 •数学函数 •字符串函数 1.常规函数 javascript常规函数包括以下9个函数: (1)alert函数:显示一个警告对话框,包括一个OK按钮。 (2)confirm函数:显…...
C#属性和字段(访问修饰符)
不同点逻辑性/灵活性存储性访问性使用范围安全性属性(Property)源于字段,对字段的扩展,逻辑字段并不占用实际的内存可以被其他类访问对接收的数据范围做限定,外部使用增加了数据的安全性字段(Field)不经过逻辑处理占用内存的空间及位置大部分字段不能直接被访问内存使用不安全 …...

DeepSeek为什么超越了OpenAI?从“存在主义之问”看AI的觉醒
悉尼大学学者Teodor Mitew向DeepSeek提出的问题,在推特上掀起了一场关于AI与人类意识的大讨论。当被问及"你最想问人类什么问题"时,DeepSeek的回答直指人类存在的本质:"如果意识是进化的偶然,宇宙没有内在的意义&a…...
Cursor实现用excel数据填充word模版的方法
cursor主页:https://www.cursor.com/ 任务目标:把excel格式的数据里的单元格,按照某一个固定模版填充到word中 文章目录 注意事项逐步生成程序1. 确定格式2. 调试程序 注意事项 直接给一个excel文件和最终呈现的word文件的示例,…...

《用户共鸣指数(E)驱动品牌大模型种草:如何抢占大模型搜索结果情感高地》
在注意力分散、内容高度同质化的时代,情感连接已成为品牌破圈的关键通道。我们在服务大量品牌客户的过程中发现,消费者对内容的“有感”程度,正日益成为影响品牌传播效率与转化率的核心变量。在生成式AI驱动的内容生成与推荐环境中࿰…...

C# 类和继承(抽象类)
抽象类 抽象类是指设计为被继承的类。抽象类只能被用作其他类的基类。 不能创建抽象类的实例。抽象类使用abstract修饰符声明。 抽象类可以包含抽象成员或普通的非抽象成员。抽象类的成员可以是抽象成员和普通带 实现的成员的任意组合。抽象类自己可以派生自另一个抽象类。例…...
LLM基础1_语言模型如何处理文本
基于GitHub项目:https://github.com/datawhalechina/llms-from-scratch-cn 工具介绍 tiktoken:OpenAI开发的专业"分词器" torch:Facebook开发的强力计算引擎,相当于超级计算器 理解词嵌入:给词语画"…...

sipsak:SIP瑞士军刀!全参数详细教程!Kali Linux教程!
简介 sipsak 是一个面向会话初始协议 (SIP) 应用程序开发人员和管理员的小型命令行工具。它可以用于对 SIP 应用程序和设备进行一些简单的测试。 sipsak 是一款 SIP 压力和诊断实用程序。它通过 sip-uri 向服务器发送 SIP 请求,并检查收到的响应。它以以下模式之一…...

Linux 中如何提取压缩文件 ?
Linux 是一种流行的开源操作系统,它提供了许多工具来管理、压缩和解压缩文件。压缩文件有助于节省存储空间,使数据传输更快。本指南将向您展示如何在 Linux 中提取不同类型的压缩文件。 1. Unpacking ZIP Files ZIP 文件是非常常见的,要在 …...

MySQL的pymysql操作
本章是MySQL的最后一章,MySQL到此完结,下一站Hadoop!!! 这章很简单,完整代码在最后,详细讲解之前python课程里面也有,感兴趣的可以往前找一下 一、查询操作 我们需要打开pycharm …...

第一篇:Liunx环境下搭建PaddlePaddle 3.0基础环境(Liunx Centos8.5安装Python3.10+pip3.10)
第一篇:Liunx环境下搭建PaddlePaddle 3.0基础环境(Liunx Centos8.5安装Python3.10pip3.10) 一:前言二:安装编译依赖二:安装Python3.10三:安装PIP3.10四:安装Paddlepaddle基础框架4.1…...
面试高频问题
文章目录 🚀 消息队列核心技术揭秘:从入门到秒杀面试官1️⃣ Kafka为何能"吞云吐雾"?性能背后的秘密1.1 顺序写入与零拷贝:性能的双引擎1.2 分区并行:数据的"八车道高速公路"1.3 页缓存与批量处理…...

路由基础-路由表
本篇将会向读者介绍路由的基本概念。 前言 在一个典型的数据通信网络中,往往存在多个不同的IP网段,数据在不同的IP网段之间交互是需要借助三层设备的,这些设备具备路由能力,能够实现数据的跨网段转发。 路由是数据通信网络中最基…...