【动态内存开辟】

一、概述

 首先这儿介绍一本很好很好的书《c指针编程之道》根据这本书中的内容来学习这几个函数!!!

1.下面介绍第一个函数malloc,原型:void* malloc(unsigned int num_bytes),此函数在堆区可以占用一块空间,返回的是占用空间的第一个地址,可能开辟失败,一定判断是否开辟成功!开辟失败,返回NULL,对开辟成功的内存不做处理,也就是以前的随机值!

• 如果开辟成功,则返回⼀个指向开辟好空间的指针。
• 如果开辟失败,则返回⼀个 NULL 指针,因此malloc的返回值⼀定要做检查。
• 返回值的类型是 void* ,所以malloc函数并不知道开辟空间的类型,具体在使⽤的时候使⽤者⾃⼰来决定。
• 如果参数 size 为0,malloc的⾏为是标准是未定义的,取决于编译器。
2.free 此函数的原型是void free(void* ptr)
  如果ptr指向的空间不是堆区开辟的,free函数的行为是未定义的
  
如果ptr是NULL,则函数什么事情也不做!!!

1

int main()
{
	int* ptr = (int*)malloc(sizeof(int) * 10);
	//是否开辟成功
	if (!ptr)
	{
		perror("The malloc fail:");
		return 1;
	}
	//开辟成功
	for (int i = 0; i < 10; i++)
	{
		ptr[i] = i;
		printf("%d ", ptr[i]);
	}
	printf("\n");
	//释放内存
	ptr = NULL;
	return 0;
}
int main()
{
	int* ptr = (int*)malloc(0);
	if (!ptr)
	{
		perror("Fail:");
		return 1;
	}
	*ptr = 1;
	//虽然行为未定义
	//数据还是放进内存了!!!
	free(ptr);
	ptr = NULL;
	return 0;
}

3.calloc 原型是:void* calloc(unsigned num,unsigned size);
1

int main()
{
	int*ptr = (int*)calloc(10, sizeof(int));
	if (!ptr)
	{
		return 1;
	}
	for (int i = 0; i < 10; i++)
	{
		printf("%d ", ptr[i]);
	}
	free(ptr);
	ptr = NULL;
	return 0;
}

4.realloc 函数原型是void* realloc(void* ptr,size_size);理解此函数,注意两点,首先,此函数是扩容用的函数,如果原空间在堆区有足够大的空间,那么在后面直接开辟,如果没有足够大的空间,则另找一块空间,把原空间的内容复制到新空间进行扩容,并且会释放原来的空间.
1
1

int main()
{
	int* ptr = (int*)malloc(sizeof(int)*10);
	if (!ptr)
	{
		perror("malloc fail:");
		return 1;
	}
	for (int i = 0; i < 10; i++)
	{
		ptr[i] = i;
	}
	int* tmp = (int*)realloc(ptr, sizeof(int) * 11);
	if (!tmp)
	{
		return 1;
	}
	ptr = tmp;
	for (int i = 0; i < 11; i++)
	{
		printf("%d ", ptr[i]);
	}
	free(ptr);
	ptr = NULL;
	return 0;
}

二、常见动态内存错误

1.对NULL的解引用操作!

void test()
 {
 int *p = (int *)malloc(INT_MAX/4);
 *p = 20;//如果p的值是NULL,就会有问题
 //所以这儿一定要检测NULL
 free(p);
 }

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的时候越界访问
 }
 free(p);
 }

3.对⾮动态开辟内存使⽤free释放

void test()
 {
 	int a = 10;
 	int *p = &a;
 	free(p);//栈区内存不能释放,会自动释放!!!
 }

4.使⽤free释放⼀块动态开辟内存的⼀部分

void test()
 {
 int *p = (int *)malloc(100);
 p++;    //p已经移动了,不在指向首位置
 free(p);//p不再指向动态内存的起始位置
 }

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;
 }
 //一定要在内存用完,要free,不然会内存泄漏!!!
 }
int main()
 {
 test();
 while(1);
 }

三、 动态内存经典笔试题分析

1.题⽬1:

void GetMemory(char* p)
{
	p = (char*)malloc(100);
}
int main()
{
	char* str = NULL;  //创建了char*的变量,用来存储地址
	//所有的传参都是复制
	GetMemory(str);
	strcpy(str, "hello world");
	printf(str);
	return 0;
}

在这里插入图片描述
1
2.题目2

char *GetMemory(void)
 {
 char p[] = "hello world";
 return p;
 }
void Test(void)
 {
 char *str = NULL;
 str = GetMemory();
 printf(str);
 }

`

1
1
3.题目3

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

1
1
4.题目4

int main()
{
	char* str = (char*)malloc(100);
	strcpy(str, "hello");
	free(str);
	if (str != NULL)
	{
		strcpy(str, "world");
		printf(str);
	}
	return 0;
}

1

四、柔性数组

1
1

1

/*****************柔性数组使用******************/
struct S
{
	int n;
	int arr[0];
};


int main()
{
	//为柔性数组开辟40个字节的空间
	struct S* ps = (struct S*)malloc(sizeof(struct S) + 40);
	if (!ps)
	{
		perror("malloc fail:");
		return 1;
	}
	ps->n = 10;
	for (int i = 0; i < 10; i++)
	{
		ps->arr[i] = i;
	}
	for (int i = 0; i < ps->n; i++)
	{
		printf("%d ", ps->arr[i]);
	}
	free(ps);
	ps = NULL;
	return 0;
}
struct S
{
	int n;
	int* ps;
};

int main()
{
	struct S s;
	int* tmp = malloc(sizeof(int) * 10);
	if (!tmp)
	{
		perror("malloc fail:");
		return 1;
	}
	s.ps = tmp;
	s.n = 10;
	for (int i = 0; i < 10; i++)
	{
		(s.ps)[i] = i;
		printf("%d ", (s.ps)[i]);
	}
	free(s.ps);
	s.ps = NULL;
	return 0;
}

完结!!!

  • 8
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值