C语言学习第31篇---内存操作经典问题实例分析
都是从项目经验中提炼出的问题
但凡程序出现了一些问题,多半和内存有关!!!所有资料电子版可以通过置顶文章获取
内存操作经典问题实例分析一
野指针
1.指针变量中的值是非法的内存地址,进而形成野指针
2.野指针不是NULL指针,是指向不可用内存地址的指针
3.NULL指针并无危害,很好判断,也很好调试(只有NULL指针而已)
4.C语言中无法判断一个指针所保存的地址是否合法
野指针的由来(项目开发中出现了崩溃,出现了重启,肯定是有野指针)
1.局不指针变量没有初始化(指针的初始化时非常重要的)
2.指针所指向的变量在指针之前被销毁
3.使用已经释放的指针
4.进行了错误的指针运算
5.进行了错误的强制类型转换
实验1:野指针
-
#include <stdio.h>
-
-
#include <malloc.h>
-
-
int main()
-
-
{
-
-
int* p1 = (int*)malloc(40); //
-
-
int* p2 = (int*)1234567; //进行了错误的类型转换
-
-
int i = 0;
-
-
-
for(i=0; i<40; i++)
-
-
{
-
-
*(p1 + i) = 40 - i;//申请了40个字节,不是40个整型变量,肯定会有野指针,这里内存越界了
-
-
}
-
-
free(p1); //这里只是归还内存,后边的使用都是野指针,最好的方法是 p1 = NULL;
-
-
-
for(i=0; i<40; i++)
-
-
{
-
-
p1[i] = p2[i]; //野指针的实例,之前已经释放了
-
-
}
-
-
-
return 0;
-
-
}
杜绝的基本原则:
1.绝不返回局部变量和局部数组的地址
2.任何变量在定义后必须初始化为0
3.字符数组必须确认0结束符之后才能成为字符串
4.任何使用与内存操作相关的函数必须指定长度信息
实验2
-
#include <stdio.h>
-
-
#include <string.h>
-
-
#include <malloc.h>
-
-
struct Student
-
-
{
-
-
char* name;
-
-
int number;
-
-
};
-
-
char* func()
-
-
{
-
-
char p[] = "D.T.Software";
-
-
return p;
-
-
}
-
-
void del(char* p)
-
-
{
-
-
printf("%s\n", p);
-
-
free(p);
-
-
}
-
-
int main()
-
-
{
-
-
struct Student s; 0//这里没有初始化,已经有问题了
-
-
char* p = func(); //指针指向局部数组,已经产生野指针了
-
-
strcpy(s.name, p); //两个都是野指针
-
-
s.number = 99;
-
-
p = (char*)malloc(5);
-
-
strcpy(p, "D.T.Software");// 这里内存越界了,上边只分配了5个字节
-
-
del(p);
-
-
return 0;
-
-
}
-
小结:
1.内存错误使实际产品开发中最常见的错误,然而绝大多数bug是可以通过遵循最常见的编程原理和规范来避免的
2.因此,在学习的时候要牢记和理解内存操作的基本原则,目的和意义
内存操作经典问题实例分析二
常见内存错误
1.结构体成员未初始化
2.结构体成员指针未分配足够的内存
3.内存分配成功,但是并未初始化
4.内存操作越界
实例1:
-
#include <stdio.h>
-
-
#include <string.h>
-
-
#include <malloc.h>
-
-
struct Student
-
-
{
-
-
char* name;
-
-
int number;
-
-
};
-
-
char* func()
-
-
{
-
-
char p[] = "D.T.Software";
-
-
return p;
-
-
}
-
-
void del(char* p)
-
-
{
-
-
printf("%s\n", p);
-
-
free(p);
-
-
}
-
-
int main()
-
-
{
-
-
struct Student s; 0//这里没有初始化,已经有问题了
-
-
char* p = func(); //指针指向局部数组,已经产生野指针了
-
-
strcpy(s.name, p); //两个都是野指针
-
-
s.number = 99;
-
-
p = (char*)malloc(5);
-
-
strcpy(p, "D.T.Software");// 这里内存越界了,上边只分配了5个字节
-
-
del(p);
-
return 0;
-
-
}
总结经验:
1.在哪个函数申请的内存就在哪个函数释放
2.内存越界不是很好调试,因为有可能需要很久时间才会爆发出来
-
#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);
-
-
func(9);
-
-
func(10);
-
-
return 0;
-
-
}
-
实例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; //这里的野指针直接造成段错误 Segmentation fault (core dumped)
-
-
}
-
-
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.动态申请内存之后,应该立刻检查指针值是否为NULL,防止使用NULL指针
-
int*p = (int*)malloc(56);
-
-
if(p != NULL)
-
-
{
-
-
//dO something here!!!
-
-
}
-
-
free(p);
2.free指针之后必须立即赋值为NULL
1》避免野指针
2》也可以防止多次释放同一个指针(内存),因为free函数有保护,参数是空什么都不做(指针)
-
int*p = (int*)malloc(20);
-
-
free(p);
-
-
p = NULL;
-
-
//..
-
-
//...
-
-
//...
-
-
//..
-
-
//...............
-
-
if(p != NULL)
-
-
{
-
-
//Do something here
-
-
}
3.任何与内存的操作相关的函数都必须带长度信息
1》预防内存越界---数组,字符串,。。。都得带上长度信息
-
void print(int* p,int size)
-
-
{
-
-
int i = 0;
-
-
char buf[128] = {0};
-
-
-
-
snprintf(buf,sizeof(buf),"%s","KANGKANG"); //这里是利用函数内部的检查机制
-
-
-
-
for(i = 0;i<size;i++)
-
-
{
-
-
printf("%d\n",p[i]);
-
-
}
-
-
}
4.malloc操作和free操作必须匹配,防止内存泄露和多次释放
1》语法上确实支持跨函数释放内存,但是一旦使用肯定会出错
-
void func()
-
-
{
-
-
int* p = (int*)malloc(20);
-
-
-
-
free(p);
-
-
}
-
-
int main()
-
-
{
-
-
int*p = (int*)malloc(40);
-
-
func();
-
-
free();
-
-
-
-
return 0;
-
-
}
小结:
1.内存错误的本质源于指针保存的地址为非法值
---指针变量未初始化,保存随机值
---指针运算导致内存越界
1.内存泄露源于malloc和free不匹配
---当malloc次数多余free时,会造成内存泄露
---当malloc次数少余free时,程序可能崩溃
文章来源: allen5g.blog.csdn.net,作者:CodeAllen的博客,版权归原作者所有,如需转载,请联系作者。
原文链接:allen5g.blog.csdn.net/article/details/89113979
- 点赞
- 收藏
- 关注作者
评论(0)