IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> C程序中与内存有关的常见错误 -> 正文阅读

[C++知识库]C程序中与内存有关的常见错误

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

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

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++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2021-12-28 22:43:27  更:2021-12-28 22:45:49 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 11:13:22-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码