C语言动态内存管理(上)

发布于:2025-03-17 ⋅ 阅读:(17) ⋅ 点赞:(0)

欢迎拜访雾里看山-CSDN博客
本篇主题:C语言动态内存管理(上)
发布时间:2025.3.16
隶属专栏C语言

在这里插入图片描述

为什么需要动态内存管理

静态分配的局限性

静态数组:int arr[100] 需要编译时确定,且空间开辟是固定的
自动变量:函数内定义的局部变量生命周期受限于函数栈帧

但是对于空间的需求,不仅仅是上述的情况。有时候我们需要的空间大小在程序运行的时候才能知道,那数组的编译时开辟空间的方式就不能满足了。这时候就只能试试动态存开辟了。

动态分配的优势

  • 运行时按需分配(如根据用户输入决定数据规模)
  • 灵活调整内存大小(动态扩容/缩容)
  • 突破栈空间限制(堆空间通常比栈大得多)
  • 实现跨函数的数据持久化(如链表节点)

动态内存函数

malloc

函数介绍

函数地址malloc
函数格式void* malloc (size_t size);
功能:分配一个大小字节的内存块,返回一个指向该块开头的指针。新分配的内存块的内容没有初始化,保留不确定的值。
返回值:如果成功,则返回一个指向函数分配的内存块的指针。如果函数分配请求的内存块失败,则返回空指针。
头文件strstr函数的声明在stdlib.h的头文件中,在使用时,要使用#include <stdlib.h>操作包含头文件。
特别注意

  1. 如果size为0,则返回值取决于特定的库实现(它可能是也可能不是空指针),但是返回的指针不能被解引用。
  2. 该指针的类型始终为void*,可以将其强制转换为所需的数据指针类型,以实现可解引用。

函数使用

#include <stdio.h>      
#include <stdlib.h>     

int main()
{
    int i, n;
    char* buffer;

    printf("How long do you want the string? ");
    scanf("%d", &i);

    buffer = (char*)malloc(i + 1);
    if (buffer == NULL) exit(1);

    for (n = 0; n < i; n++)
        buffer[n] = rand() % 26 + 'a';
    buffer[i] = '\0';

    printf("Random string: %s\n", buffer);
    free(buffer);

    return 0;
}

在这里插入图片描述

free

函数介绍

函数地址free
函数格式void free (void* ptr);
功能:释放了先前通过调用malloccallocrealloc分配的内存块,使其再次可用以进行进一步分配。
返回值void
头文件strstr函数的声明在stdlib.h的头文件中,在使用时,要使用#include <stdlib.h>操作包含头文件。
特别注意

  1. 如果ptr没有指向由上述函数分配的内存块,则会导致未定义的行为。
  2. 如果ptr是空指针,则该函数不执行任何操作。
  3. free函数没有改变ptr本身的值,因此它仍然指向相同的(现在无效的)位置。

函数使用

#include <stdlib.h>     

int main()
{
	int* buffer1, * buffer2, * buffer3;
	buffer1 = (int*)malloc(100 * sizeof(int));
	buffer2 = (int*)calloc(100, sizeof(int));
	buffer3 = (int*)realloc(buffer2, 500 * sizeof(int));
	free(buffer1);
	free(buffer3);
	return 0;
}

在这里插入图片描述

calloc

函数介绍

函数地址calloc
函数格式void* calloc (size_t num, size_t size);
功能:为包含num个元素的数组分配一块内存,每个元素的size为字节大小,并将其所有位初始化为零。
返回值:如果成功,则返回一个指向函数分配的内存块的指针。如果函数分配请求的内存块失败,则返回空指针。
头文件strstr函数的声明在stdlib.h的头文件中,在使用时,要使用#include <stdlib.h>操作包含头文件。
特别注意

  1. 如果size为0,则返回值取决于特定的库实现(它可能是也可能不是空指针),但是返回的指针不能被解引用。
  2. 该指针的类型始终为void*,可以将其强制转换为所需的数据指针类型,以实现可解引用。

函数使用

#include <stdio.h>      
#include <stdlib.h>     

int main()
{
    int* p = (int*)calloc(10, sizeof(int));
    if (p != NULL)
    {
        //使用空间
    }
    free(p);
    p = NULL;
    return 0;
}

在这里插入图片描述

realloc

函数介绍(C11标准)

函数地址realloc
函数格式void* realloc (void* ptr, size_t size);
功能:改变ptr所指向的内存块的大小。
返回值:如果成功,则返回一个指向函数分配的内存块的指针。如果函数分配请求的内存块失败,则返回空指针,表示ptr所指向的块没有被修改。
头文件strstr函数的声明在stdlib.h的头文件中,在使用时,要使用#include <stdlib.h>操作包含头文件。
特别注意

  1. 如果size为0,则返回值取决于特定的库实现:它可以是空指针,也可以是其他不能解引用的位置。
  2. 如果ptr是空指针,则该函数的行为类似于malloc,分配一个新的大小字节块并返回一个指向其起点的指针。
  3. 如果函数分配请求的内存块失败,则返回空指针,并且参数ptr指向的内存块不会被释放(它仍然有效,其内容不变)。
  4. 这个函数调整原内存空间大小的基础上,还会将原来内存中的数据移动到 的空间。
  5. realloc在调整内存空间的是存在两种情况:
    情况1:原有空间之后有足够大的空间
    情况2:原有空间之后没有足够大的空间
    在这里插入图片描述
    情况1:当是情况1 的时候,要扩展内存就直接原有内存之后直接追加空间,原来空间的数据不发生变化。
    情况2:当是情况2 的时候,原有空间之后没有足够多的空间时,扩展的方法是:在堆空间上另找一个合适大小的连续空间来使用。这样函数返回的是一个新的内存地址。
    由于上述的两种情况,realloc函数的使用就要注意一些。

函数使用

#include <stdio.h>      
#include <stdlib.h>    

int main()
{
	int* p = (int*)malloc(40);
	if (p == NULL)
	{
		perror("malloc");
		return 1;
	}
	//初始化为1~10
	int i = 0;
	for (i = 0; i < 10; i++) 
	{
		p[i] = i + 1;
	}
	//增加一些空间
	int* ptr = (int*)realloc(p, 8000);
	if (ptr != NULL)
	{
		p = ptr;
		ptr = NULL;
	}
	else
	{
		perror("realloc");
		return 1;
	}
	//打印数据
	for (i = 0; i < 20; i++)
	{
		printf("%d\n", p[i]);
	}
	//释放
	free(p);
	p = NULL;

	return 0;
}

在这里插入图片描述

⚠️ 写在最后:以上内容是我在学习以后得一些总结和概括,如有错误或者需要补充的地方欢迎各位大佬评论或者私信我交流!!!