【C语言】动态内存管理

 动态内存管理

1、动态内存所开辟的空间都是在堆上开辟的;

【C语言】动态内存管理_第1张图片


malloc函数

1、可以向内存申请一块连续可用的空间,并返回这块空间的指针;

2、开辟成功,返回指向空间的指针;

3、开辟失败,返回NULL;

4、malloc申请的空间释放:1、free释放(主动);2、程序退出,操作系统回收(被动释放);

【C语言】动态内存管理_第2张图片

#include 
#include 
int main()
{
	// 开辟一块malloc空间
	int* p = (int*)malloc(10 * (sizeof(int)));
	// 判断malloc是否为空
	if (p == NULL)
	{
		// 打印出错误原因
		perror("malloc");
		return 1;
	}
	// 使用malloc开辟的空间
	for (int i = 0; i < 10; i++)
	{
		printf("%d ", *(p + i)); // 未初始化
	}
	return 0;
}

free函数

1、用来释放动态开辟的内存;

2、free的参数的空间不是动态开辟的空间,那free的行为是未定义的;

3、free的参数是NULL指针,函数什么都都不做;

【C语言】动态内存管理_第3张图片


#include 
#include 
int main()
{
	// 开辟一块malloc空间
	int* p = (int*)malloc(10 * (sizeof(int)));
	// 判断malloc是否为空
	if (p == NULL)
	{
		// 打印出错误原因
		perror("malloc");
		return 1;
	}
	// 使用malloc开辟的空间
	for (int i = 0; i < 10; i++)
	{
		*(p + i) = i;
		printf("%d ", *(p + i));
	}
	
	// free释放空间
	free(p);
	p = NULL; // 最后将指针制为空指针

	return 0;
}

calloc函数

1、calloc也是开辟空间的;

2、calloc会将开辟好的空间全部初始化为0;

【C语言】动态内存管理_第4张图片

#include 
#include 
int main()
{
	// 开辟一块calloc空间
	int* q = (int*)calloc(10, sizeof(int));
	if (q == NULL)
	{
		perror("calloc");
		return 1;
	}
	for (int i = 0; i < 10; i++)
	{
		printf("%d ", *(q + i)); // 全都初始化为了0
	}
	free(q);
	q = NULL;
	return 0;
}

 realloc函数

1、realloc函数使用来追加空间的;

2、realloc的返回值不能用追加到指定空间接收;(因为如果追加空间失败,则会导致以前开辟的空间也置为空);

3、如果后续空间被占用,不能直接使用;realloc则会找一块新的空,一次性开辟够;并将就空间中的数据拷贝到新空间中,还会将就得空间释放掉,返回新空间的地址;

4、realloc追加的空间内存放的是随机值;

5、realloc函数的第一个参数如果是一个空指针,那么就等价于malloc函数;

【C语言】动态内存管理_第5张图片

#include 
#include 
int main()
{
	// 开辟一块calloc空间
	int* q = (int*)calloc(10, sizeof(int));
	if (q == NULL)
	{
		perror("calloc");
		return 1;
	}
	// 使用realloc追加空间
	// q = (int*)realloc(q, 10 * sizeof(int));
	// 这样写是会出问题的,最好不用自己接收;
	int* q1 = (int*)realloc(q, 10 * (sizeof(int)));
	if (q1 == NULL)
	{
		perror("realloc");
		return 1;
	}
	for (int i = 0; i < 20; i++)
	{
		printf("%d ", *(q + i)); // realloc追加的空间值是随机值
	}
	free(q);
	free(q1);
	q = NULL;
	q1 = NULL;
	return 0;
}

 动态内存常见错误

1、对NULL指针的解引用操作;

  • 不对动态内存开辟空间的返回值进行判断,就对该指针进行解引用操作,就会出现错误;

2、对动态内存的越界访问;

3、对非动态的内存free释放;

4、使用free释放动态内存的一部分;

  • 使用动态内存保证指针的起始位置不变;

5、对同一块动态内存空间多次释放;

  • 所以要保证在free完之后将指针置为空指针,这样多次释放就不会报错了;

6、忘记释放动态内存空间(内存泄漏);


 笔试题

题目1:未free、解引用NULL指针

源代码:

#include 
#include 
#include 
void GetMemory(char* p)
{
	p = (char*)malloc(100); // 没有内存释放,并且形参不会改变实参;
}
void Test(void)
{
	char* str = NULL;
	GetMemory(str);
	strcpy(str, "hello world"); // 对NULL指针解引用;
	printf(str);
}
int main()
{
	Test();
	return 0;
}

修改后的代码1:

#include 
#include 
#include 
void GetMemory(char** p)
{
	*p = (char*)malloc(100); // 没有内存释放,并且形参不会改变实参;
	// 这里通过解引用找到首元素地址
}
void Test(void)
{
	char* str = NULL;
	GetMemory(&str); // 所以这里传地址过去,通过形参改变实参;
	strcpy(str, "hello world"); // 对NULL指针解引用;
	printf(str);
	// 使用完后,对动态内存空间进行释放
	free(str);
	str = NULL;
}
int main()
{
	Test();
	return 0;
}

修改后的代码2:


#include 
#include 
#include 
void* GetMemory()
{
    char* p;
	return p = (char*)malloc(100); // 没有内存释放,并且形参不会改变实参;
	// 将地址传回去
}
void Test(void)
{
	char* str = NULL;
	str = GetMemory(); 
	strcpy(str, "hello world"); // 对NULL指针解引用;
	printf(str);
	// 最后释放
	free(str);
	str = NULL;
}
int main()
{
	Test();
	return 0;
}

 题目2:野指针

注意:

局部变量出了当前函数就会销毁,千万千万不能返回变量地址,也就是不能返回栈空间地址,那么所接收的指针就成为了野指针;地址是带回来了,但是空间却销毁了;

char* GetMemory(void)
{
	char p[] = "hello world";
	return p;
}
void Test(void)
{
	char* str = NULL;
	str = GetMemory(); // str成了野指针了
	printf(str);
}

【C语言】动态内存管理_第6张图片


 题目3:未free(存在内存泄漏)

这个代码和题目1改造后的代码很像, 只是少了释放动态内存空间,存在内存泄漏;

#include 
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;
}

 题目4:free后未置为NULL

#include 
void 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;
}

代码错误注释:

#include 
void Test(void)
{
	char* str = (char*)malloc(100); 
	// 未判断NULL
	strcpy(str, "hello");
	free(str);
	// 应该在后面将str置为NULL
	if (str != NULL)
	{
		strcpy(str, "world"); // 先释放了空间,所以这里的str成了野指针
		printf(str);
	}
}
int main()
{
	Test();
	return 0;
}

C/C++的内存开辟

还未写完

你可能感兴趣的:(c语言,数据结构,开发语言)