注:博客中内容主要来自《狄泰软件学院》,博客仅当私人笔记使用。
测试环境:Ubuntu 10.10
GCC版本:4.4.5
一、常见内存错误
1) 结构体成员指针未初始化
2) 结构体成员指针未分配足够的内存
3) 内存分配成功,但并未初始化
4) 内存操作越界
实例分析
常见内存错误
42-1.c
#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 ) //判断size是不是偶数
{
return; //这里可能产生内存泄露,导致35行无法释放free
}
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); //重复释放两次指针,导致内存崩溃
func(9);
func(10);
return 0;
}
操作:
1) gcc 42-1.c -o 42-1.out编译正确,打印结果:
0
0
0
0
0
*** Error in `./42-1.out': double free or corruption (fasttop): 0x09f09008 ***
Aborted (core dumped)
分析:
重复释放p指向的内存。
2) 注释掉free(p):
实例分析
常见内存错误
42-1.c
#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 ) //判断size是不是偶数
{
return; //这里可能产生内存泄露,导致35行无法释放free
}
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); //重复释放两次指针,导致内存崩溃
func(9);
func(10);
return 0;
}
gcc 42-1.c -o 42-1.out编译正确,打印结果:
0
0
0
0
0
0
1
2
3
4
5
6
7
8
9
分析:
func(10)内容没有打印,说明func(10)函数中申请的内存没被释放,造成内存泄露。
注:这个例子体现,多次释放内存和内存泄露
42-2.c
#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;
}
//内存越界,申请并初始化内存数据为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;
}
操作:
1) gcc 42-2.o 42-2.out编译错误:
42-2.c:18:3: error: ‘dl’ undeclared (first use in this function)
dl.p[i] = 0;
^
错误:dl没有被声明
42-2.c:18:3: note: each undeclared identifier is reported only once for each function it appears in
二、内存操作的交通规则
1) 动态内存申请之后,应该立即检查指针值是否为NULL,防止使用NULL指针。
int* p = (int*)malloc(56);
if(p != NULL)
{
//Do something here!
}
free(p);
2) free指针之后必须立即赋值为NULL(为了杜绝野指针,NULL的错误好查)。
int* p = (int*)malloc(20);
free(p);
p = NULL;
// ...
// ......
// .........
// ............
// ...............
if( p != NULL)
{
// Do something here!
}
3) 任何与内存操作相关的函数都必须带长度信息。
void print(int* p,int size) //size为长度信息
{
int i = 0;
char buf[128] = {0};
snprintf(buf,sizeof(buf),"%s","D.T.Software"); //sizeof(buf)内存长度信息
for(i = 0;i<size;i++)
{
printf("%d\n",p[i]);
}
}
4) malloc操作和free操作必须匹配,防止内存泄露和多次释放。
void func()
{
int* p = (int*)malloc(20); //二者匹配存在
free(p);
}
int main()
{
int* p = (int*)malloc(40); //二者匹配存在
func();
free(p);
return 0;
}
小结:
1) 内存错误的本质源于指针保存的地址为非法制
- 指针变量未初始化,保存随机值
- 指针运算导致内存越界
2) 内存泄露源于malloc和free不匹配
- 当malloc次数多于free时,产生内存泄露
- 当malloc次数少于free时,程序可能崩溃