常见内存错误
- 结构体成员指针未初始化
- 结构体成员指针未分配足够的内存
- 内存分配成功,但并未初始化(尤其字符串操作时)
- 内存操作越界
实例分析: 常见内存错误 1
#include <stdio.h>
#include <malloc.h>
void test(int* p, int size)
{
int i = 0;
for(i=0; i<size; i++)
{
printf("%d\n", p[i]);
}
free(p);
}
void func(unsigned int size)
{
int* p = (int*)malloc(size * sizeof(int));
int i = 0;
if( size % 2 != 0 )
{
return; // 此处将导致内存泄漏
}
for(i=0; i<size; i++)
{
p[i] = i;
printf("%d\n", p[i]);
}
free(p);
}
int main()
{
int* p = (int*)malloc(5 * sizeof(int));
test(p, 5);
free(p); // 指针 p 两次释放,运行奔溃
func(9);
func(10);
return 0;
}
输出:
0
0
0
0
0
*** glibc detected *** ./a.out: double free or corruption (fasttop): 0x08d29008 ***
======= Backtrace: =========
/lib/libc.so.6(+0x6c0c1)[0x63a0c1]
/lib/libc.so.6(+0x6d930)[0x63b930]
/lib/libc.so.6(cfree+0x6d)[0x63ea1d]
./a.out[0x804851f]
/lib/libc.so.6(__libc_start_main+0xe7)[0x5e4ce7]
./a.out[0x8048391]
======= Memory map: ========
00364000-00365000 r-xp 00000000 00:00 0 [vdso]
005ce000-00725000 r-xp 00000000 08:02 4645 /lib/libc-2.12.1.so
00725000-00727000 r--p 00157000 08:02 4645 /lib/libc-2.12.1.so
00727000-00728000 rw-p 00159000 08:02 4645 /lib/libc-2.12.1.so
00728000-0072b000 rw-p 00000000 00:00 0
00a2f000-00a49000 r-xp 00000000 08:02 102 /lib/libgcc_s.so.1
00a49000-00a4a000 r--p 00019000 08:02 102 /lib/libgcc_s.so.1
00a4a000-00a4b000 rw-p 0001a000 08:02 102 /lib/libgcc_s.so.1
00ee5000-00f01000 r-xp 00000000 08:02 4629 /lib/ld-2.12.1.so
00f01000-00f02000 r--p 0001b000 08:02 4629 /lib/ld-2.12.1.so
00f02000-00f03000 rw-p 0001c000 08:02 4629 /lib/ld-2.12.1.so
08048000-08049000 r-xp 00000000 08:05 524332 /home/delphi/桌面/a.out
08049000-0804a000 r--p 00000000 08:05 524332 /home/delphi/桌面/a.out
0804a000-0804b000 rw-p 00001000 08:05 524332 /home/delphi/桌面/a.out
08d29000-08d4a000 rw-p 00000000 00:00 0 [heap]
b7700000-b7721000 rw-p 00000000 00:00 0
b7721000-b7800000 ---p 00000000 00:00 0
b78ad000-b78ae000 rw-p 00000000 00:00 0
b78bb000-b78be000 rw-p 00000000 00:00 0
bfed0000-bfef1000 rw-p 00000000 00:00 0 [stack]
已放弃
实例分析: 常见内存错误 2
#include <stdio.h>
#include <malloc.h>
struct Demo
{
char* p;
};
int main()
{
struct Demo d1; // 结构体成员指针未初始化,造成野指针
struct Demo d2; // 结构体成员指针未初始化,造成野指针
char i = 0;
for(i='a'; i<'z'; i++)
{
d1.p[i] = 0; // 野指针被使用
}
d2.p = (char*)calloc(5, sizeof(char));
printf("%s\n", d2.p);
for(i='a'; i<'z'; i++)
{
d2.p[i] = i; // 内存越界
}
free(d2.p);
return 0;
}
输出:
段错误
内存操作的交通规则
- 动态内存申请之后,应该立即检查指针值是否为 NULL, 防止使用 NULL 指针。
int* p = (int*)malloc(56);
if(p != NULL)
{
// Do something here!
}
free(p);
- free 指针之后必须立即赋值为 NULL
int* p = (int*)malloc(20);
free(p);
p = NULL;
//...
if( p != NULL )
{
// Do something here
}
- 任何与内存相关的函数都必须带长度信息,防止内存越界
void print(int* p, int size)
{
int i = 0;
char buf[128] = {0};
snprintf(buf, sizeof(buf), "%s\n", "D.T.Software");
for(i=0; i<size; i++)
{
printf("%d\n", p[i]);
}
}
malloc 操作和 free 操作必须匹配,防止内存泄漏和多次释放。
void func()
{
int* p = (int*)malloc(20);
free(p);
}
int main()
{
int* p = (int*)malloc(40);
func();
free(p);
return 0;
}
内存泄漏对于需要长时间运行的设备是致命的 bug,但同时内存泄漏问题是不易被查找的。在编程时,尽量保证同一个函数中申请资源,同一个函数中释放资源。
小结
内存错误的本质源于指针保存的地址为非法值
- 指针变量未初始化,保存随机值
- 指针运算导致内存越界
内存泄漏源于 malloc 和 free 不匹配
- 当 malloc 次数多余 free 时,产生内存泄漏
- 当 malloc 次数少于 free 时,程序可能产生崩溃
以上内容参考狄泰软件学院系列课程,请大家保护原创!
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。