目录
一. 常见的动态内存错误
1.对NULL指针的解引用 *** 作
2.对动态开辟空间的越界访问
3.对非动态开辟内存使用free释放
4.使用free释放一块动态开辟内存的一部分
5.对同一块动态内存多次释放
6.动态开辟内存忘记释放(内存泄漏)
二、几个经典的笔试题
1.题目1
2.题目2
3.题目3
4.题目4
一. 常见的动态内存错误 1.对NULL指针的解引用 *** 作
int main()
{
int *p = (int *)malloc(INT_MAX/4);
*p = 20;//如果p的值是NULL,就会有问题
free(p);
return 0;
}
此代码是有问题的,我们不知道malloc函数返回值是不是空指针,如果开辟失败,则返回空指针,假设开辟失败,p为空指针(NULL),对p进行解引用 *** 作会产生问题(空指针不能进行解引用 *** 作)
改进:对p进行一个判断,判断怕是否为NULL
#include
#include
#include
int main()
{
int* p = (int*)malloc(INT_MAX / 4);
if (p == NULL)
{
perror("malloc");
return 1;
}
else
{
*p = 20;
}
free(p);
return 0;
}
2.对动态开辟空间的越界访问总结:在进行解引用 *** 作时,要对malloc函数返回值进行合理的判断(空指针不能进行解引用 *** 作)
int main()
{
int*p = (int*)malloc(20);
if (p == NULL)
return 1;
//使用
int i = 0;
for (i = 0; i < 20; i++)
{
*(p + i) = i;
//p[i] = i;
}
//释放
free(p);
p = NULL;
return 0;
}
这样的代码是有问题的,会造成越界访问。
for (i = 0; i < 20; i++)
{
*(p + i) = i;
//p[i] = i;
}
总共开辟20个字节,for一共循环20次,每次一个整形指针+i,循环20次超越边界,形成了越界访问
改进:最大只能访问5个整形(i < 5)
int main()
{
int*p = (int*)malloc(20);
if (p == NULL)
return 1;
//使用
int i = 0;
for (i = 0; i < 5; i++)
{
*(p + i) = i;
//p[i] = i;
}
//释放
free(p);
p = NULL;
return 0;
}
3.对非动态开辟内存使用free释放
int main()
{
int num = 10;
int* p = #
//.....
free(p);
p = NULL;
return 0;
}
4.使用free释放一块动态开辟内存的一部分程序代码有问题:非动态开辟内存使用free释放(此方法是不对的,代码就是错误的)比如嘴角起个泡,非要往脚趾头抹药——牛头不对马嘴
int main()
{
int* p = (int*)malloc(40);
if (p == NULL)
return 1;
int i = 0;
for (i = 0; i < 5; i++)
{
*p = i;
p++;
}
//释放
//在释放的时候,p指向的不再是动态内存空间的起始位置
free(p);
p = NULL;
return 0;
}
5.对同一块动态内存多次释放显然,代码是有问题的,重视空间管理(起始位置不可变),显然在释放的时候,p指向的不再是动态内存空间的起始位置
如果想要变位置,可以使用另外一个指针来改变位置,切记起始位置不可变
int main()
{
int* p = (int*)malloc(40);
if (p == NULL)
return 1;
int i = 0;
for (i = 0; i < 5; i++)
{
*(p + i) = i;
}
free(p);
free(p);
return 0;
}
此代码有错误,错误之处在于对同一块动态内存多次释放
改进:可以在第一个free后边加(p = NULL),因为free之后置为空,对空指针释放就相当于什么事没干
进而引出每次free之后置为NULL很重要!!!
int main()
{
int* p = (int*)malloc(40);
if (p == NULL)
return 1;
int i = 0;
for (i = 0; i < 5; i++)
{
*(p + i) = i;
}
free(p);
p = NULL;
free(p);
return 0;
}
6.动态开辟内存忘记释放(内存泄漏)
int* get_memory()
{
int* p = (int*)malloc(40);
//....
return p;
}
int main()
{
int *ptr = get_memory();
//使用
return 0;
}
此代码是错误的,动态开辟内存忘记释放(内存泄漏),不可以只顾申请,不释放
改进:函数会返回动态开辟空间的地址,记得在使用之后返回
//函数会返回动态开辟空间的地址,记得在使用之后返回
int* get_memory()
{
int* p = (int*)malloc(40);
//....
return p;
}
int main()
{
int *ptr = get_memory();
//使用
//释放
free(ptr);
ptr = NULL;
return 0;
}
二、几个经典的笔试题 1.题目1总结:忘记释放不再使用的动态开辟的空间会造成内存泄漏。
切记:动态开辟的空间一定要释放,并且正确释放 。
#include
void GetMemory(char* p)
{
p = (char*)malloc(100);
}
void Test(void)
{
char* str = NULL;
GetMemory(str);
strcpy(str, "hello world");
printf(str);
}
int main()
{
Test();
return 0;
}
此代码的问题:1.str里边还是NULL,拷贝不成功。strcpy:把 hello world 放到str中,必须对str进行解引用 *** 作,而空指针不可以解引用 *** 作
2.没有释放空间,造成内存泄漏
改进:
1.GetMemory函数帮忙申请100个字节的空间,最好把100个空间的地址放到str中,这样strcpy就可以把hello world拷贝到刚刚开辟的100个空间中
我们希望把malloc中开辟的100个字节的空间放到str中,GetMemory函数会改变str,需要把地址放到str中去改变str,GetMemory函数最好传str的地址(&str),如果不传地址,值传过去,p是str的一份临时拷贝,p的修改不会改变str
因为str是一个char*类型,&str就是二阶指针,对于p来说就是char** p(void GetMemory(char** p)),p得到的是str的地址,如果通过p找到str,则对p解引用(*p = (char*)malloc(100))
2.释放空间:free(str); str = NULL;
void GetMemory(char** p)
{
*p = (char*)malloc(100);
}
void Test(void)
{
char* str = NULL;
GetMemory(&str);
strcpy(str, "hello world");
printf(str);
//释放
free(str);
str = NULL;
}
int main()
{
Test();
return 0;
}
2.题目2
char* GetMemory(void)
{
char p[] = "hello world";
return p;
}
void Test(void)
{
char* str = NULL;
str = GetMemory();
printf(str);
}
int main()
{
Test();
return 0;
}
代码有问题:p是一个局部数组,进入函数创建,出函数销毁,所谓的销毁就是hello world还给 *** 作系统,地址不变
printf(str) :通过str内容找原来的空间(hello world),但是空间已经被销毁(没有使用权限),有可能被覆盖等等,如果坚持打印内容,抱歉,代码出问题
这是一个返回栈空间地址的问题
例如:
int test()
{
int a = 10;
return a;
}
int main()
{
int ret = test();
printf("%d\n", ret);
return 0;
}
代码没有问题
return a:返回栈空间的变量,没有返回地址
出范围销毁,在销毁之前会找一个寄存器,把10先放到寄存器中,然后销毁,返回之后再把寄存器里的值放到ret中
例如:
int* test()
{
int a = 10;
return &a;
}
int main()
{
int*p = test();
printf("hehe\n");
printf("%d\n", *p);
return 0;
}
3.题目3代码有问题:返回栈空间地址的问题
分析:创建变量a = 10,假设a的地址为0x0012ff40,把地址返回去,给了p,p为指针变量,里边接收到了地址,a的地址返回确实放到了p中,p中的地址有能力找到a的空间,但是出了函数空间,a已经不存在了,空间已经不属于a了,p中记住的地址已经没用了,去找原来的空间已经不存在了,此时p已经为野指针了,如果p通过地址访问原来的空间,则为非法访问
void GetMemory(char** p, int num)
{
*p = (char*)malloc(num);
}
void Test(void)
{
char* str = NULL;
GetMemory(&str, 100);
strcpy(str, "hello");
printf(str);
free(str);
str = NULL;
}
int main()
{
Test();
//......
return 0;
}
出现内存泄露的问题,没有释放空间
4.题目4void Test(void)
{
char* str = (char*)malloc(100);
strcpy(str, "hello");
free(str);
if (str != NULL)
{
strcpy(str, "world");
printf(str);
}
}
int main()
{
Test();
return 0;
}
代码有问题:str是野指针,这里就是非法访问
改进:free之后,一定要把指针置为空,否则指针就为野指针
void Test(void)
{
char* str = (char*)malloc(100);
if (str == NULL)
return;
strcpy(str, "hello");
free(str);
str = NULL;
if (str != NULL)
{
strcpy(str, "world");
printf(str);
}
}
int main()
{
Test();
return 0;
}
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)