动态内存管理

1.常见的动态内存错误

1.1对NULL指针的解引用
void test()
 {
 int *p = (int *)malloc(INT_MAX/4);
 *p = 20;//如果p的值是NULL,就会有问题
 free(p);
 }
1.2对动态开辟空间的越界访问
void test()
 {
 int i = 0;
 int *p = (int *)malloc(10*sizeof(int));
 if(NULL == p)
 {
 exit(EXIT_FAILURE);
 }
 for(i=0; i<=10; i++)
 {
 *(p+i) = i;//当i是10的时候p+i就会越界就会发生越界访问。
 }
 free(p);
 }
1.3对动态开辟内存使用free释放
void test()

 {
 int a = 10;
 int *p = &a;
 free(p);//ok?
 }
1.4使用free释放一块动态开辟内存的一部分
void test()
 {
 int *p = (int *)malloc(100);
 p++;
 free(p);//p不在指向动态内存的起始位置
 }
1.5对同一块动态内存多次释放
void test()
 {
 int *p = (int *)malloc(100);
 free(p);
 free(p);//重复释放
 }
1.6动态开辟内存忘记释放了(内存泄露)
void test()
 {
 int *p = (int *)malloc(100);
 if(NULL != p)
 {
 *p = 20;
 }
 }
int main()
 {
 test();
 while(1);
 }

关于这一点我们要记住,忘记释放不在使用的空间会造成内存泄漏。

切记,动态开辟的空间一定要释放,并且正常释放。 

下面还有一些题,我们来练习一下:

2.动态内存经典笔试题分析

2.1题目

请问test函数会有怎样的结果?

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
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.有malloc但是没有free函数释放空间,这样就会导致内存泄漏。

2. 这串代码是打印不出数据的,因为程序崩溃了,为什么会崩溃?我会讲解一下。

GetMomory函数传递的是值所以对形参的修改影响不到实参,所以这串代码

void GetMemory(char* p)
 {
     p = (char*)malloc(100);
 }

p的改动返回不到实参的结果,再出这个代码之后p申请的空间就会销毁。最终p还是一个空指针,如果对NULL再进行解引用的话,就会导致程序崩溃。

如果要进行修改的话,就是下面的样子:进行传址操作

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
void GetMemory(char** p)
 {
	 *p = (char*)malloc(100);
 }
 void Test(void)
 {
	 char* str = NULL;//1.我创建的是str这个变量,给他放入一个空指针
     GetMemory(&str);//2.我调用GetMemory函数,这里我传的是str指针变量,这个str虽然说是一个地址,但是它指向只是首元素的地址,我们的传址操作是传递整个str的地址所以要对str进行取地址操作。
	 strcpy(str, "hello world");
	 printf(str);
     free(str);
     str = NULL;
 }
 int main()
 {
	 test();
	 return 0;
 }

就是这样。 其实还有一种比较简单的方式可以使用:

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
char* GetMemory()//如果换成这样的方式,传参就没有意义了,就可以不用传参
 {
	 char* p = (char*)malloc(100);直接写成这样就行了。
     return p;
 }

 void Test(void)
 {
	 char* str = NULL;
     str = GetMomory();

	 strcpy(str, "hello world");
	 printf(str);
     free(str);
     str = NULL;
 }
 int main()
 {
	 test();
	 return 0;
 }
2.2题目: 

我们来看一下,这个题目test函数的结果是什么:

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
char* GetMemory(void)
 {
	 char p[] = "hello world";
	return p;
 }
 void Test(void)
 {
	 char* str = NULL;
	 str = GetMemory();
	 printf(str);
 }
 int main()
 {
	 test();
	 return 0;
 }

这串代码会不会打印出hello world呢? 有可能,为什么会有可能呢?接下来我会讲解一下:

首先我们创建了一个空指针str,然后调用GetMomory函数,在GetMemory函数中我们创建了一个字符数组p,这个数组里面的元素是hello world,最后返回数组名,我们知道数组名是首元素的地址,也就是直接返回了首元素的地址,就是h的地址,之后我们就会把这个地址赋给str,但是呢,p是getmemory函数里面的局部变量,你如果一出getmemory函数的话,这个p就会销毁。p所指向的空间就会还给操作系统,但是str指向的地址还是这个地址,只不过变成野指针了,如果p指向的那块空间,没有被占用就能打印出来,如果被占用的话就打印不出来。

下面我在给一个简单的代码,和上面的代码错误是一样的。

int * test()
{
  int n = 10;
return &n; 
}

int main()
{
  int *p = test();
  printf("%d\n",*p);
  return 0;
}

 这两串代码在性质上是一样的。但是呢,这串代码打印出来就是10,其实这就是巧合,就是释放的空间刚好没有被覆盖掉。

如果在printf("%d\n",*p);前面加上printf("hehe\n");打印出来就不是10了。

2.3题目:
void GetMemory(char** p, int num)
{
	*p = (char*)malloc(num);
}
void Test(void)
{
	char* str = NULL;
	GetMemory(&str, 100);
	strcpy(str, "hello");
	printf(str);
}
 int main()
 {
	 test();
	 return 0;
 }

这传代码有没有问题?有,就是忘记释放空间了,导致内存泄漏。

下面这样改造完就可以了。

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;
 }
2.4题目:

我已经在题目中进行讲解

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
void Test(void)
{
	char* str = (char*)malloc(100);//melloc申请了100个字节的空间。str指向这块空间。 
	strcpy(str, "hello");//我们再把hello拷贝到str这块空间上去
	free(str);//我们对str进行释放,就是把str指向的空间还给操作系统了,这块空间就没有使用权限了。但是这块空间在内存中还在,
	if (str != NULL)//str不等于空
	{
		strcpy(str, "world");//这里就是把world这个字符串覆盖到hello上去,但是我们没有str这块空间的访问权限了,这里就是属于非法访问。
		printf(str);
	}
}
 int main()
 {
	 test();
	 return 0;
 }

 

  • 18
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值