C语言动态内存管理的实现

目录
  • 1. 摘要
  • 2. 为什么存在动态内存管理
  • 3. 动态内存函数
    • 3.1 malloc
    • 3.2 free
    • 3.3 calloc
    • 3.4 realloc
  • 4. 常见的动态内存错误
  • 5. 几个经典笔试题
  • 参考答案
  • 6. 参考文献

1. 摘要

本文主要详解C语言中的动态内存分配

2. 为什么存在动态内存管理

我们先来看一段变量的声明:

double x = 1.000000;
char str[] = "abcdef";

好的,上述变量的声明有何特点呢?

请思考一下,我的朋友。

对,没错,不管是双精度浮点数 x 还是字符数组str,它们都是临时变量,所以当我们为其开辟内存的时候,都是在栈区上进行的。那么既然是在栈区上进行开辟的,那么对应的就被称为自动变量,也叫局部作用变量,特点是进入作用域,系统为这个变量自动分配内存空间;离开作用域时,系统自动为其销毁内存空间。

还有什么特点?

太棒了,就是如你所说的那样,无论是x还是str,它们所占的内存大小都是由系统自动进行分配的,double为8个byte,str数组为7个byte(包含‘\0')。而且对于数组而言,我们在声明时就必须指定它的大小;创建局部作用变量之后,我们人为就无法改变它们的大小了。

那么你先在应该已经悟出了为什么会存在动态内存分配这一操作了吧,我的朋友。

有的时候,只有当程序运行的时候,我们才能知道我们需要开辟多大的内存空间,而事先无法知晓。那就试试动态内存分配吧。

别担心,我来教你。

3. 动态内存函数

函数是C语言的基本单元,为了实现动态内存分配,我们就需要调用C语言库中的动态内存函数。

动态内存函数能为我们在堆区开辟内存。

所引用的头文件为 <stdlib.h>

3.1 malloc

void *malloc( size_t size );

malloc函数的功能就是在静态区分配一块内存块给我们的程序

参数:内存大小(字节)

返回值:

开辟成功,返回指向开辟好的内存空间的指针,类型为void*,使用者根据实际情况,能在使用时将其强制类型转换成任意类型的指针开辟失败,返回空指针NULL,因此使用malloc时,一定要对返回值进行检查如果size是0,这是C标准未定义的,取决于编译器

3.2 free

void free( void *memblock );

free用来释放动态开辟的内存

  • 如果memblock指针指向的空间不是动态内存开辟的,这是未定义的
  • 如果memblock指针是NULL,则free什么事也不会做

例如,我们想动态开辟一块10个int类型大小的空间,因该遵循以下流程:

#include<stdio.h>
#include<stdlib.h>
int main()
{
	int* p = (int*)malloc(10 * sizeof(int));
	if(p != NULL)
	{
		//...你的操作...
	}
	free(p);
	p = NULL;
	return 0;
}

3.3 calloc

void *calloc( size_t num, size_t size );

calloc函数也是用来动态分配内存的,但与malloc存在两大区别:

  • 参数:需要传入两个参数,第一个参数为开辟内存单元的个数,第二个参数为每个内存单元的大小
  • calloc在返回地址前把申请到的所有内存空间的每个字节初始化为0,而malloc没有这步初始化操作

那让我们来看一下calloc的初始化,对以下代码进行调试:

#include<stdio.h>
#include<stdlib.h>
int main()
{
	int* p = (int*)calloc(10, sizeof(int));
	if (p != NULL)
	{
		;
	}
	free(p);
	p = NULL;
	return 0;
}

调试结果如图一:

可见,40个字节的值被初始化成了0

3.4 realloc

void *realloc( void *memblock, size_t size );

动态内存分配的一大特点就是,能在内存不够用,或者内存开辟得太大的时候,对于开辟内存的大小进行灵活的调整,即对于一个指针指向的内存进行重新的分配

参数:

  • memblock是要调整的内存的地址
  • size是调整之后的内存的大小(byte)

返回值:

  • 调整后指向新的内存的地址的指针
  • realloc在调整内存的基础上,会将原来内存中的数据迁移到新的内存上
  • 如果调整失败或者size=0且memblock不为NULL,返回NULL

realloc调整内存有2种情况:

  • 情况一:原有空间之后有足够大的空间
  • 情况二:原有空间之后没有足够大的空间

那么realloc是怎么处理这两种情况的呢?请看图二:

情况一:要拓展内存,直接在原有内存后面追加空间,原来的数据不发生改变
情况二:原有内存后面没有足够的空间,拓展方法是:指针指向一块新的足够大的内存空间,并将原来的数据复制到这块空间上去。这样返回的就是一个新的地址。

总结:所以在使用realloc的时候,建议用一个临时指针tmpptr来接收realloc的返回值,如果tmpptr不为NULL,那么就可以安心地用ptr去接收tmpptr了

4. 常见的动态内存错误

对NULL的解引用操作

void test()
{
	int* ptr = (int*)malloc(100);
	//如果此时开辟失败,ptr为NULL
	*ptr = 4;
	free(ptr);
}

对动态开辟空间的越界访问

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);
	p = NULL;
}

对非动态内存开辟的空间free

void test()
{
	int a = 0;
	int* pa = &a;
	free(a);
}

使用free释放一块动态开辟内存的一部分

void test()
{
	int* ptr = (int*)malloc(100);
	ptr++;
	free(ptr);
}

对同一块空间多次free

void test()
{
	int* ptr = (int*)malloc(100);
	free(ptr);
	free(ptr);
}

5. 几个经典笔试题

题目一:

void GetMemory(char* p)
{
	p = (char*)malloc(100);
}
void Test(void)
{
	char* str = NULL;
	GetMemory(str);
	strcpy(str, "hello world");
	printf(str);
}
//请问运行Test 函数会有什么样的结果?

题目二:

char* GetMemory(void)
{
	char p[] = "hello world";
	return p;
}
void Test(void) {
	char* str = NULL;
	str = GetMemory();
	printf(str);
}
//请问运行Test 函数会有什么样的结果?

题目三:

void GetMemory(char** p, int num)
{
	*p = (char*)malloc(num);
}
void Test(void)
{
	char* str = NULL;
	GetMemory(&str, 100);
	strcpy(str, "hello");
	printf(str);
}
//请问运行Test 函数会有什么样的结果?

题目四:

void Test(void)
{
	char* str = (char*)malloc(100);
	strcpy(str, "hello");
	free(str);
	if (str != NULL)
	{
		strcpy(str, "world");
		printf(str);
	}
}
//请问运行Test 函数会有什么样的结果?

参考答案

题目一:

GetMemory函数传参为值传递,Test函数中的str依旧为NULL,无法向NULL地址处拷贝字符串,printf也无法打印

malloc后未free

题目二:

数组p在栈区上创建,出了GetMemory函数p就销毁,str其实就成了野指针

题目三:

malloc后未free,str未置成NULL

题目四:

str动态分配的内存已经被释放了,但下面还敢继续使用str,这是一个野指针问题

6. 参考文献

1.《C Primer Plus》第6版 p396 - 401

到此这篇关于C语言动态内存管理的实现的文章就介绍到这了,更多相关C语言动态内存管理内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • C语言动态内存分配的详解

    C语言动态内存分配的详解 1.为什么使用动态内存分配 数组在使用的时候可能造成内存浪费,使用动态内存分配可以解决这个问题. 2. malloc和free C函数库提供了两个函数,malloc和free,分别用于执行动态内存分配和释放. (1)void *malloc(size_t size); malloc的参数就是需要分配的内存字节数.malloc分配一块连续的内存.如果操作系统无法向malloc提供更多的内存,malloc就返回一个NULL指针. (2)void free(void *poi

  • C语言 动态内存分配的详解及实例

    1. 动态内存分配的意义 (1)C 语言中的一切操作都是基于内存的. (2)变量和数组都是内存的别名. ①内存分配由编译器在编译期间决定 ②定义数组的时候必须指定数组长度 ③数组长度是在编译期就必须确定的 (3)但是程序运行的过程中,可能需要使用一些额外的内存空间 2. malloc 和 free 函数 (1)malloc 和 free 用于执行动态内存分配的释放 (2)malloc 所分配的是一块连续的内存 (3)malloc 以字节为单位,并且返回值不带任何的类型信息:void* mallo

  • c语言动态内存分配知识点及实例

    c语言怎么实现动态内存分配 我们经常会预先给程序开辟好内存空间,然后进行操作. int arr[5] ; 对这个数组我们在定义的时候必须给提前开辟好空间,并且在程序执行的过程中,这个开辟的内存空间是一直存在的,除非等到这个函数执行完毕,才会将空间释放.有个问题就是这个数组在程序中无法被修改. 这些问题给我们造成了一些使用上的不方便,所以,C中提供了malloc()函数. 关于malloc()函数,这个函数它接受一个参数:就是所需的内存的字节数.然后malloc()找到可用内存中那一个大小适合的块

  • C语言动态内存分配函数的实现

    在C中我们开辟内存空间有两种方式 : 1.静态开辟内存 :例如: int a;int b[10]; 这种开辟内存空间的特点是 所开辟的内存是在栈中开辟的固定大小的 ,如a是4字节 ,数组b是40字节 ,并且数组在申明时必须指定其长度 , 如果是全局数组的话,内存是在编译时分配好的,如果是局部变量数组的话,运行时在栈上静态分配内存.不管是全局数组还是局部数组,它们都有一个特点,那就是数组大小是确定的,是代码中写死的.那如果我们想在程序运行时才确定一个数组的大小 , 前两种在栈上分配内存的方法显然是

  • C语言创建链表错误之通过指针参数申请动态内存实例分析

    本文实例讲述了C语言创建链表中经典错误的通过指针参数申请动态内存,分享给大家供大家参考之用.具体实例如下: #include <stdio.h> #include <stdlib.h>// 用malloc要包含这个头文件 typedef struct node { int data; struct node* next;// 这个地方注意结构体变量的定义规则 } Node; void createLinklist(Node* pHder, int length) { int i =

  • C语言 动态内存分配详解

    C语言 动态内存分配详解 动态内存分配涉及到堆栈的概念:堆栈是两种数据结构.堆栈都是数据项按序排列的数据结构,只能在一端(称为栈顶(top))对数据项进行插入和删除. 栈(操作系统):由操作系统自动分配释放 ,存放函数的参数值,局部变量的值等.其操作方式类似于数据结构中的栈. 堆(操作系统): 一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收,分配方式倒是类似于链表. \在C语言中,全局变量分配在内存中的静态存储区,非静态的局部变量(包括形参)是分配在内存的动态存储区,该存储区被

  • C语言动态内存管理的实现

    目录 1. 摘要 2. 为什么存在动态内存管理 3. 动态内存函数 3.1 malloc 3.2 free 3.3 calloc 3.4 realloc 4. 常见的动态内存错误 5. 几个经典笔试题 参考答案 6. 参考文献 1. 摘要 本文主要详解C语言中的动态内存分配 2. 为什么存在动态内存管理 我们先来看一段变量的声明: double x = 1.000000; char str[] = "abcdef"; 好的,上述变量的声明有何特点呢? 请思考一下,我的朋友. 对,没错,

  • C语言动态内存管理分析总结

    目录 什么是动态内存分配 动态内存函数的介绍 free malloc calloc realloc 动态内存管理中常见的错误 对NULL指针的解引用操作 对动态开辟空间的越界访问 对非动态开辟内存使用free释放 使用free释放一块动态开辟内存的一部分 对同一块动态内存多次释放 动态开辟内存忘记释放(内存泄漏) 一些经典的笔试题 题目1 题目2 题目3 题目4 柔性数组 柔性数组的特点 柔性数组的优势 什么是动态内存分配 我们都知道在C语言中,定义变量的时候,系统就会为这个变量分配内存空间,而

  • C语言动态内存管理介绍

    目录 前言: C 语言为内存的分配和管理提供了几个函数: 1.malloc() 用法 2.calloc() 用法 3.realloc() 与 free() 用法 前言: 简单记录一下,内存管理函数 为什么使用动态内存呢? 简单理解就是可以最大限度调用内存 用多少生成多少,不用时就释放而静止内存不能释放 动态可避免运行大程序导致内存溢出 C 语言为内存的分配和管理提供了几个函数: 头文件:<stdlib.h> 注意:void * 类型表示未确定类型的指针  1.malloc() 用法  分配一块

  • 关于C语言动态内存管理介绍

    目录 1.为什么需要动态内存分配 2.有关动态内存函数介绍 2.1 malloc和free 2.2 calloc函数 2.3 realloc函数 3. 常见的动态内存错误 3.1 对NULL指针进行解引用操作 3.2 对动态开辟空间的越界访问 3.3 对非动态开辟内存使用free释放 3.4 使用free释放一块动态开辟内存的一部分 3.5 对同一块动态内存多次释放 3.6 动态开辟内存忘记释放(内存泄漏) 总结 1.为什么需要动态内存分配 关于这个问题,我们先看看我们之前是如何开辟内存的. i

  • C语言 动态内存管理全面解析

    目录 1. 为什么存在动态内存分配 2. 动态内存函数的介绍 2.1 malloc和free 2.2 calloc 2.3 realloc 3. 常见的动态内存错误 3.1 对NULL指针的解引用操作 3.2 对动态开辟空间的越界访问 3.3 对非动态开辟内存使用free释放 3.4 使用free释放一块动态开辟内存的一部分 3.5 对同一块动态内存多次释放 1. 为什么存在动态内存分配 *动态内存开辟在堆区* 我们已经掌握的开辟内存方式是类型直接定义变量,开辟的内存是固定的,像: int a=

  • 超详细分析C语言动态内存管理问题

    目录 一.为什么存在动态内存的分配 二.动态内存函数的介绍 2.1 malloc和free 2.2 calloc 2.3 realloc 三.常见的动态内存错误 3.1 对NULL指针的解引用操作 3.2 对动态开辟空间的越界访问 3.3 对非动态开辟内存使用free释放 3.4 对同一块动态内存多次释放 3.5 动态开辟内存忘记释放(内存泄漏) 四.几个经典的笔试题 五.C/C++程序的内存开辟 六.柔性数组 6.1 柔性数组的特点 6.2 柔性数组的使用 6.3 柔性数组的优势 上期结束了[

  • C语言动态内存管理深入探讨

    目录 1.动态内存开辟的原因 2.动态内存函数的介绍 2.1malloc和free 2.2calloc 2.3realloc 3.常见的动态内存错误 3.1对NULL指针的解引用操作 3.2对动态开辟空间的越界访问 3.3对非动态开辟内存使用free 3.4使用释放一块动态开辟内存的一部分 3.5对同一块动态内存多次释放 3.6动态开辟内存忘记释放(内存泄漏) 4.练习 4.1练习1 4.1练习2 4.3练习3 4.4练习4 5.C/C++程序的内存开辟 1.动态内存开辟的原因 常见的内存开辟方

  • C语言动态内存管理malloc柔性数组示例详解

    目录 1.1为什么存在动态内存管理 1.2动态内存管理函数 1.2.1malloc 1.2.2free 1.2.3calloc 1.2.4realloc 1.3动态内存管理函数易错点 1.3.1对NULL指针的解引用操作 1.3.2对动态开辟空间的越界访问 1.3.3对非动态开辟内存使用free释放 1.3.4使用free释放一块动态开辟内存的一部分 1.3.5对同一块动态内存多次释放 1.3.6动态开辟内存忘记释放(内存泄漏) 2.1常见相关笔试题 2.2C/C++语言中的内存开辟 2.3柔性

  • 一文带你搞懂C语言动态内存管理

    目录 一.malloc函数和free函数 二.calloc函数与malloc函数的异同 三.柔性数组 一.malloc函数和free函数 (1) 这个函数向内存申请一块连续可用的空间,并返回指向这块空间的指针. 如果开辟成功,则返回一个指向开辟好空间的指针. 如果开辟失败,则返回一个NULL指针,因此malloc的返回值一定要做检查. 返回值的类型是 void* ,所以malloc函数并不知道开辟空间的类型,具体在使用的时候使用者自己来决定. 如果参数 size为0,malloc的行为是标准是未

  • C语言初识动态内存管理malloc calloc realloc free函数

    目录 一.为什么存在动态内存分配 二.动态内存函数的使用 1.malloc函数 (1)malloc的定义 (2)malloc函数的注意事项 (3)malloc函数的使用 2.calloc函数 (1)calloc函数的定义 (2)calloc函数的注意事项 (3)calloc函数的使用 3.realloc函数 (1)realloc函数的定义 (2)realloc函数的注意事项 (3)realloc函数的使用 总结 一.为什么存在动态内存分配 在c语言中我们目前掌握的内存开辟方式有: int val

随机推荐