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

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

3天内不再提示

关于C程序中10个与内存有关的常见错误

Dp1040 来源:一起学嵌入式 2023-06-20 10:41 次阅读

与内存有关的错误,属于那种最令人惊恐的错误。在时间和空间上,经常在距离错误源一段距离之后才表现出来。将错误的数据写到错误的位置,你的程序可能在最终失败之前运行了一段时间。

下面列举并分析了与内存有关的几种错误:

1、间接引用坏指针

如果间接引用一个指向没有任何意义的数据的指针,那么操作系统会以段异常终止程序。如果向只读区域中写入数据,这些区域会以保护异常终止这个程序。

一个常见的经典示例是scanf错误。这个函数用处是从标准输入读入一个整数到一个变量,正确的写法是传递给scanf一个格式串和变量的地址:

scanf("%d", &value);

然而,常见的书写错误如下:

scanf("%d", value);

这种情况下,scanf将把value内容解释为一个地址,并试图将一个字写到这个位置。这会导致程序出现异常,有时会立即终止;有时会在相当长的时间后造成灾难性、令人困惑的后果。

2、读未初始化的内存

常见的错误是假设堆内存被初始化为零:

int *matvec(int **A, int *x, int n)
{
int i, j;
int *y = (int *)malloc(n * sizeof(int));

for(i = 0; i < n; i++)
    {
        for(j = 0; j < n; j++)
        {
            y[i] += A[i][j] * x[j]
        }
    }
    return y;
}
示例中不应该假设新申请的内存地址(y指向的地址)被初始化为零;正确的做法是显式地将y[i]设置为零,或者使用calloc申请内存。

3、栈缓冲区溢出

如果一个程序不检查输入字符串的大小就写入栈中目标缓冲区,那么这个程序就会出现缓冲区溢出的错误,如下程序:

void buff()
{
char buf[64];

gets(buf);
return;
}
这个函数会出现缓冲区溢出错误,因为gets函数只是简单复制一个任意长度的字符串到缓冲区,不限制输入串的大小。解决这个问题的方法是,可以用限制了输入串大小的fgets函数。

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

常见的错误是,假设指向对象的指针和它们所指向的对象是相同大小的,示例程序:

int **makeArray(int n, int m)
{
int i;
int **A = (int **)malloc(n * sizeof(int)); /* 注意此处语句,存在问题 */

for(i = 0; i < n; i++)
    {
        A[j] = (int *)malloc(m * sizeof(int));
    }
    return A;
}
此程序的目的是创建一个由n个指针组成的数组,每个指针都指向一个包含m个int的数组。然而,第4行程序代码将sizeof(int *)写成了sizeof(int),代码实际上创建的是一个int的数组。

这段代码只有在int和指向int的指针大小相同的机器上运行良好,否则就会出现错误。

5、内存越界

这种错误会越界覆盖原有内存的数据,导致出错:

int **makeArray(int n, int m)
{
int i;
int **A = (int **)malloc(n * sizeof(int)); /* 注意此处语句,存在问题 */

for(i = 0; i <= n; i++) /* 注意循环终止条件 */
    {
        A[j] = (int *)malloc(m * sizeof(int));
    }
    return A;
}
程序在第6行和第8行试图初始化这个数组的n+1个元素,这个过程会覆盖A数组后面的某个内存位置。

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

如果不太注意C操作符的优先级和结合性,我们就会错误地操作指针,而不是指针所指向的对象。如果想要减少某个指针指向的整数的值,代码书写如下:

*ptr--;

然而,因为一元运算符“--”和“*”的优先级相同,且从右向左结合。那么上述代码实际的效果为*(ptr--),即减少的是指针自己的值,而不是它所指向的整数的值。

如果对优先级和结合性有疑问的时候,就用括号。修正后的代码如下:

(*ptr)--;

7、误解指针运算

这类错误是忘记指针的算术运算操作是如何进行,是以指针指向的对象的大小为单位进行的,而这种大小单位并不一定是字节。 例如,扫描一个int的数组,并返回一个指向val首次出现的指针:

int *search(int *p, int val)
{
while(*p && *p != val)
{
p += sizeof(int);
}
return p;
}
每次循环时,第5行都把指针加了4(一个整数的字节数),函数就不正确地扫描了数组中每4个整数。

8、引用不存在的变量

有的C程序员不太理解栈的规则,有时会引用不再合法的局部变量,如下所示:

int *stackref()
{
int val;

return &val;
}

这个函数返回一个指针(假设为ptr),指向栈里的一个局部变量,然后弹出它的栈帧。尽管ptr仍然指向一个合法的内存地址,但它已经不再指向一个合法的变量了。

以后在程序中调用其他函数时,内存将重用它们的栈帧。如果程序赋值给*ptr,那么它可能实际上正在修改另一个含的栈帧中的数据,从而潜在地带来灾难性的后果。

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

引用已经被释放了的堆块中的数据会导致出错。例如:

int *heapref(int n, int m)
{
int i;
int *x, *y;

x = (int *)malloc(n * sizeof(int)); /* 申请内存 */

...

free(x); /* 释放内存 */

y = (int *)malloc(m * sizeof(int));
for(i = 0; i < m; i++)
    {
        y[i] = x[i]++;
    }

    return y;
}

当程序在第15行引用x[i]时,数组x可能已经是某个其他已分配堆块的一部分了,其内容也许被重写了。导致程序运行结果与预期不符合,出现错误。

10、引起内存泄漏

内存泄漏是缓慢、隐形的杀手,当程序员不小心忘记释放已分配的内存块,而在堆里创建了垃圾时,会发生这种问题。如下:

void leak(int n)
{
int *x = (int *)malloc(n * sizeof(int));

return;
}
如果经常调用这个函数,渐渐地堆里会充满了垃圾,造成内存泄漏。另外,有时也会引起程序终止或其他问题。

小结

以上总结了C程序中,管理和使用内存常见的错误类型,并举例进行了说明。在实际的编程中,应该避免出现这些错误,否则会出现意想不到的后果。





审核编辑:刘清

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

    关注

    180

    文章

    7530

    浏览量

    128763
收藏 人收藏

    评论

    相关推荐

    在C和C++语言开发中内存直接操作的方法

    指针释放引起的错误:释放同一个内存块两次,或释放一块未曾使用malloc分配的内存,或释放仍在使用中的内存,或释放一个无效的指针。一个极为常见
    的头像 发表于 05-09 10:56 8785次阅读
    在C和C++语言开发中<b class='flag-5'>内存</b>直接操作的方法

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

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

    C程序10个与内存有关常见错误

    内存有关错误,属于那种最令人惊恐的错误。在时间和空间上,经常在距离错误源一段距离之后才表现出来。将错误的数据写到
    发表于 06-20 10:41 568次阅读

    图像处理程序 读AVI出现一内存错误 大牛请进!

    本人在做一机器视觉的程序用一算法读一段视频每帧图片视频格式为AVI的但是运行开始的几次都没有问题一般三四次以后就会出现一报错 下面附
    发表于 04-03 15:42

    任哲UCOS入门教程内存存有任务代码和任务堆栈理解不了

    截图中说到了内存存有任务代码和任务堆栈,这个我怎么理解不了。内存一般就是RAM吧,但我们的任务代码不是都存在ROM吗。我怎么感觉
    发表于 05-08 06:36

    【原创】常见内存错误及对策

    校验也起不了作用,没有被 初始化的指针变量,内部是一非NULL的乱码assert是一宏,而不是函数,包含在assert.h头文件。如果其后面括号里的值为假,则程序终 止运行,并提
    发表于 08-24 11:34

    linux的共享内存是指什么?共享内存有哪些优缺点

    什么是进程?进程有哪几种状态?共享内存是指什么?共享内存有哪些优缺点?
    发表于 02-28 09:32

    LabVIEW内存已满的错误

    内存空间,必须关闭引用。您可以在LabVIEW关闭引用阅读更多有关信息。相关信息如果LabVIEW无法为阵列分配足够大的内存块,则此错误
    发表于 04-11 21:32

    关于NAND闪存有哪些观念是错误的?

    在半导体业,有非常多与接口标准、性能规格、功能特性和设计的真实可能性有关联的假设、术语和误解。因此,弄清事实很重要。本文将阐明关于NAND闪存的错误观念。
    发表于 08-30 14:39 846次阅读

    双通道内存有什么好处

    双通道内存是一种能够让电脑性能增加的技术,说白了是用多个内存由串联方式改良为并联方式,以得到更大的内存带宽。本视频主要详细介绍了双通道内存有什么好处。
    的头像 发表于 11-08 15:29 3.5w次阅读

    虚拟内存有什么用

    虚拟内存有什么用?虽说内存的大小会直接影响我们电脑的运行的程序个数和运行速度,但是当内存的容量剩余很少的时候,再运行电脑程序的时候,电脑就会
    的头像 发表于 03-14 14:55 1.4w次阅读

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

      本文将带您了解一些良好的和内存相关的编码实践,以将内存错误保持在控制范围内。内存错误是 C 和 C++ 编程的祸根:它们很普遍,认识其严
    的头像 发表于 02-14 13:10 2957次阅读

    C程序中管理和使用内存常见错误类型

    内存有关错误,属于那种最令人惊恐的错误。在时间和空间上,经常在距离错误源一段距离之后才表现出来。将错误的数据写到
    的头像 发表于 06-20 10:43 341次阅读

    常用的解决内存错误的方法

    1. 内存管理功能问题 由于C++语言对内存有主动控制权,内存使用灵活和效率高,但代价是不小心使用就会导致以下内存错误: • memory
    的头像 发表于 11-10 15:29 750次阅读
    常用的解决<b class='flag-5'>内存</b><b class='flag-5'>错误</b>的方法

    ug内部错误内存访问违例怎么解决

    ug内部错误内存访问违例怎么解决 内部错误内存访问违例是编程中常见的问题,它们可能会导致应用程序
    的头像 发表于 12-27 16:27 3317次阅读