0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

C程序中常见的与内存相关的错误及其解决办法

STM32嵌入式开发 来源:STM32嵌入式开发 2023-06-14 17:13 次阅读

C语言入门程序员来说,管理和使用虚拟存储器可能是个困难的,容易出错的任务。与存储器有关的错误属于那些最令人惊恐的错误,因为它们经常在时间和空间上,都在距错误源一段距离之后,才表现出来。

将错误的数据编写到错误的位置,你的程序可能在最终失败之前运行了好几个小时,且使程序中止的位置距离错误的位置已经很远了。

1、间接引用坏指针

在进程的虚拟地址空间中有较大的漏洞,没有映射到任何有意义的数据。如果我们试图间接引用一个指向这些洞的指针,那么操作系统就会以段异常终止我们的程序。

而且,虚拟存储器的某些区域是只读的。试图写这些区域将造成以保护异常终止这个程序。

间接引用坏指针的一个常见示例是经典的scanf错误。假设我们想要使用scanf从stdin读一个整数到变量。做这件事情正确的方法是传递给scanf一个格式串和变量的地址:

ea36476a-0a92-11ee-962d-dac502259ad0.png     

然而,对于c语言程序员初学者而言,很容易传递val的内容,而不是它的地址:

ea4a0b38-0a92-11ee-962d-dac502259ad0.png     

在这种情况下,scanf将把val的内容解释为一个地址,并试图将一个字写到这个位置。在最好的情况下,程序立即以异常终止。

在最糟糕的情况下,val的内容对应于虚拟存储器的某个合法的读/写区域,于是我们就覆盖了存储器,这通常会在相当以后造成灾难性的、令人困惑的后果。

2、读未初始化的存储器

虽然.bss存储器位置(诸如未初始化的全局C变量)总是被加载器初始化为零,但是对于堆存储器却并不是这样的。一个常见的错误就是假设堆存储器被初始化为零:

ea61e03c-0a92-11ee-962d-dac502259ad0.png     

在这个示例中,程序员不正确地假设向量y被初始化为零。正确的实现方式是在for循环时将y[i]设置为零,或使用calloc。

3、允许栈缓冲区溢出

如果一个程序不检查输入串的大小就写入栈中的目标换成区,那么这个程序就会有缓冲区溢出错误。例如,下面的函数就有缓冲区错误,因为gets函数拷贝一个任意长度的串到缓冲区。为了纠正这个错误,我们必须使用fgets函数,这个函数限制了输入串的大小:

ea77efda-0a92-11ee-962d-dac502259ad0.png

4、假设指针和它们指向的对象是相同大小的

一种常见的错误是假设指向对象的指针和它们所指向的对象是相同大小的:

ea8547ca-0a92-11ee-962d-dac502259ad0.png     

这里的目的是创建一个由n个指针组成的数组,每个指针都指向一个包含m个int的数组。然而,因为程序员将int **A = (int **)malloc(n * sizeof(int));中将sizeof(int)写成了sizeof(int),代码实际创建的是一个int的数组。这段代码只有在int和指向int的指针大小相同的机器上运行良好。

但是,如果我们在像Alpha这样的机器上运行这段代码,其中指针大于int,那么在for(i = 0; i < n; i++)  A[i] = (int *)malloc(m * sizeof(int));将写到超过A数组末端的地方。因为这些字中的一个很可能是分配块的边界标记脚部,所以我们可能不会发现这个错误,而没有任何明显的原因。

5、造成错位错位

错位错误是另一种很常见的覆盖错误发生的原因:

ea991b7e-0a92-11ee-962d-dac502259ad0.png     

这是前面程序的另一个版本。这里我们创建了一个n个元素的指针数组,但是随后试图初始化这个数组的n+1个元素,在这个过程中覆盖了A数组后面的某个存储器。

6、引用指针,而不是它所指向的对象

如果我们不太注意C操作符的优先级和结合性,我们就会错误地操作指针,而不是期望操作指针所指向的对象。比如,考虑下面的函数,其目的是删除一个有*size项的二叉堆里的第一项,然后对剩下的*size-1项重新建堆。

eaa59a70-0a92-11ee-962d-dac502259ad0.png    

*size—目的是减少size指针指向的整数的值。然而,因为一元—和*运算符优先级相同,从右向左结合,所以代码实际减少的是指针自己的值,而不是它所指向的整数的值。

如果幸运的话,程序会立即失败,但是更有可能发生的是,当程序在它执行过程的很后面产生一个不正确的结果时,我们只能在那里抓脑袋了。这里的原则是如果你对优先级和结合性有疑问,就使用括号。使用表达式(*size)--。

7、误解指针运算

另一种常见的错误是忘记了指针的算术操作是以它们指向的对象的大小为单位来进行的,而这种大小单位并不一定是字节。例如,下面函数的目的是扫描一个int的数组,并返回一个指针,指向val的首次出现:

eaadef90-0a92-11ee-962d-dac502259ad0.png

8、引用不存在的变量

没有太多经验的C程序员不理解栈的规则,有时会引用不再合法的本地变量,如下列所示:

eac44b8c-0a92-11ee-962d-dac502259ad0.png     

这个函数返回一个指针,指向栈里的一个局部变量,然后弹出它的栈帧。尽管p仍然指向一个合法的存储器地址,但是它已经不再指向一个合法的变量了。

当以后在程序中调用其他函数时,存储器将重用它们的帧栈。后来,如果程序分配某个值给*p,那么它可能实际正在修改另一个函数的帧栈中的一个条目,从而带来潜在地灾难性的、令人困惑的后果。

9、引用空闲堆块中的数据

一个相似的错误是引用已被释放了的堆块中的数据。如下面的示例,示例中分配了一个整数数组x,之后释放了块x,最后又引用了它。

ead02362-0a92-11ee-962d-dac502259ad0.png

10、引起存储器泄漏

存储器泄漏是缓慢、隐形的杀手,当程序员不小心忘记释放已分配块,而在堆里创建了垃圾时,会发生这种问题。例如,下面的函数分配了一个堆块x,然后不释放它就返回。

eae5f37c-0a92-11ee-962d-dac502259ad0.png     

如果leak经常被调用,堆里就会充满了垃圾,最糟糕的情况下,会占有整个虚拟地址空间。对于像守护进程和服务器这样的程序来说,存储器泄漏是特别严重的,根据定义这些程序是不会终止的。




审核编辑:刘清

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 存储器
    +关注

    关注

    38

    文章

    7485

    浏览量

    163790
  • C语言
    +关注

    关注

    180

    文章

    7604

    浏览量

    136738
  • 虚拟机
    +关注

    关注

    1

    文章

    914

    浏览量

    28167

原文标题:C程序中常见的与内存相关的错误

文章出处:【微信号:c-stm32,微信公众号:STM32嵌入式开发】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    C程序中常见的与内存相关错误

    C语言入门程序员来说,管理和使用虚拟存储器可能是个困难的,容易出错的任务。与存储器有关的错误属于那些最令人惊恐的错误,因为它们经常在时间和空间上,都在距
    发表于 06-14 17:13 354次阅读
    <b class='flag-5'>C</b><b class='flag-5'>程序</b><b class='flag-5'>中常见</b>的与<b class='flag-5'>内存</b><b class='flag-5'>相关</b>的<b class='flag-5'>错误</b>

    声卡硬件维修的常见问题及解决办法

    声卡硬件维修的常见问题及解决办法 常见故障一:声卡无声   出现这种故障常见的原因有:
    发表于 02-23 14:25 2552次阅读

    垂直热风整平中常见问题解决办法

    垂直热风整平中常见问题解决办法   热风整平又叫喷锡,它的工作原理是利用热风将印制板表面及孔内多余焊料去掉,剩余焊料均
    发表于 03-02 09:35 791次阅读

    开发中常遇电磁兼容EMC问题及解决办法

    开发中常遇电磁兼容EMC问题及解决办法 下面产品开发中常见的一些EMC问题: 一
    发表于 04-17 11:32 733次阅读

    物理内存使用率高的原因及解决办法

    主要讲解的就是物理内存使用率高的原因以及他的解决办法。导致物理内存使用率高有几种可能,而最常见的则有两种:一是安装不好的程序
    发表于 05-03 17:14 9368次阅读
    物理<b class='flag-5'>内存</b>使用率高的原因及<b class='flag-5'>解决办法</b>

    Absinthe2.0越狱iOS5.1.1常见错误解决办法

    Absinthe2.0越狱中可能会遇到一些问题,本内容介绍了Absinthe2.0越狱iOS5.1.1常见错误解决办法
    发表于 09-12 15:03 4695次阅读

    Matlab编程常见错误解决办法

    Matlab编程常见错误解决办法求人不如求己
    发表于 03-16 15:58 0次下载

    一文知道Zynq平台运行SDK程序错误解决办法

    Zynq平台运行SDK程序错误解决办法,具体的跟随小编一起来了解一下。
    的头像 发表于 07-14 06:05 8104次阅读

    KEIL C编译器中常见的警告与错误信息的详细解决办法资料概述

    本文档的主要内容详细介绍的是KEIL C编译器中常见的警告与错误信息的详细解决办法资料概述。
    发表于 11-07 17:43 14次下载

    内存条兼容异常问题的原因及其解决办法

    经常使用电脑的朋友都知道,电脑如果出现滴滴声的 电脑开机 故障就是内存条出现了问题。但是如果类似迅雷等软件突然出现问题时,大多数朋友可能就不会想到是由于内存出现了兼容性的问题了。下面,我就向大家介绍一下内存条兼容异常问题的原因
    发表于 06-14 10:53 1.1w次阅读

    C语言常见内存错误及解决方法

      本文将带您了解一些良好的和内存相关的编码实践,以将内存错误保持在控制范围内。内存错误
    的头像 发表于 02-14 13:10 3297次阅读

    java内存溢出的几种原因和解决办法

    内存,但是如果程序中存在内存泄漏(Memory Leak)或者使用不当的数据结构等问题,仍然有可能导致内存溢出。下面将详细介绍Java内存
    的头像 发表于 11-23 14:44 6175次阅读

    codeblocks环境错误解决办法

    CodeBlocks是一款常用的集成开发环境,用于编写、编译和调试CC++等程序。然而,有时在使用CodeBlocks时可能会遇到一些错误或问题。本文将为你提供一些
    的头像 发表于 11-26 09:37 7123次阅读

    常见MCU故障及解决办法

    微控制器单元(MCU)是现代电子设备中的核心组件,负责处理和控制各种功能。然而,由于各种原因,MCU可能会出现故障。以下是一些常见的MCU故障及其解决办法: 1. 电源问题 故障现象: MCU无法
    的头像 发表于 11-01 13:41 1573次阅读

    RS232串口通信中常见问题及解决办法

    RS232串口通信中常见问题及解决办法主要包括以下几个方面: 一、物理连接问题 问题 :串口线未插稳或接口松动。 解决办法 :重新插拔串口线,确保连接牢固。同时检查插头和针脚是否损坏,如有损坏需更换
    的头像 发表于 11-21 09:32 1129次阅读