C-动态内存分配

1.动态内存分配是什么

    C语言中的动态内存分配是指在程序运行时根据需要动态地分配和释放内存空间。这与静态内存分配相对,静态内存分配是在编译时确定内存分配的大小。

2.为什么要进行动态内存分配

    我们已经掌握的内存开辟⽅式有:

int val = 20;//在栈空间上开辟四个字节
char arr[10] = {0};//在栈空间上开辟10个字节的连续空间
但是上述的开辟空间的⽅式有两个特点:
空间开辟⼤⼩是固定的。
数组在申明的时候,必须指定数组的⻓度,数组空间⼀旦确定了⼤⼩不能调整
但是对于空间的需求,不仅仅是上述的情况。有时候我们需要的空间⼤⼩在程序运⾏的时候才能知
道,那数组的编译时开辟空间的⽅式就不能满⾜了。
C语⾔引⼊了动态内存开辟,让程序员⾃⼰可以申请和释放空间,就⽐较灵活了。

3.C语言中动态内存分配函数

下面的四个动态内存函数都需要引入头文件<stdlib.h>

    malloc

malloc 是我们见得最多的动态内存函数。

int *ptr1 = (int *)malloc(10 * sizeof(int));
  1. int *ptr1: 这声明了一个指针变量 ptr1,它指向整型数据。

  2. malloc(10 * sizeof(int)): 这部分调用了 malloc() 函数来分配内存空间。malloc() 函数接受一个参数,即要分配的字节数。在这里,我们请求分配的内存空间大小是 10 个整型数据的大小。sizeof(int) 表示一个整型数据的字节数。因此,10 * sizeof(int) 表示了我们要分配的内存空间的总字节数。

  3. (int *): 这部分是对 malloc() 返回的指针进行类型转换。malloc() 返回的是 void * 类型的指针,我们将其转换为 int * 类型,以便与 ptr1 的类型匹配。

总结起来,这句代码的作用是:分配了能够存储 10 个整型数据的内存空间,并将该内存空间的首地址存储在 ptr1 指针变量中。

这个函数向内存申请⼀块连续可⽤的空间,并返回指向这块空间的指针。

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

    free

free函数⽤来释放动态开辟的内存。
如果参数 ptr 指向的空间不是动态开辟的,那free函数的⾏为是未定义的。
如果参数 ptr 是NULL指针,则函数什么事都不做。
malloc和free都声明在 stdlib.h 头⽂件中。
#include <stdio.h>
#include <stdlib.h>

int main() {
    // 使用malloc动态分配10个整数的内存空间
    int *ptr = (int *)malloc(10 * sizeof(int));
    if (ptr == NULL) {
        printf("内存分配失败!\n");
        return 1;
    }

    // 使用动态分配的内存空间进行一些操作
    for (int i = 0; i < 10; ++i) {
        ptr[i] = i * 10;
    }

    // 打印动态分配的内存空间中的值
    printf("动态分配的内存空间中的值:\n");
    for (int i = 0; i < 10; ++i) {
        printf("%d ", ptr[i]);
    }
    printf("\n");

    // 使用完动态分配的内存空间后,释放内存
    free(ptr);
    ptr = NULL;
    return 0;
}

在这个示例中,首先使用 malloc() 分配了一个包含 10 个整数的内存空间,然后通过循环对这些动态分配的内存进行了一些操作。最后,通过调用 free() 函数释放了动态分配的内存空间。

使用 free() 函数时,只需将要释放的内存块的指针作为参数传递给该函数即可。注意,使用 free() 释放的内存块应该是通过 malloc()calloc()realloc() 分配的内存空间,否则行为是未定义的。

在释放完内存后,将指针变量 ptr 置为空指针是一个良好的编程习惯,这有助于避免悬空指针的问题。悬空指针是指在释放内存后,未将指针置为空,导致该指针仍然指向之前分配的内存地址,但该内存空间已经被释放,因此访问该指针可能会导致未定义的行为。

因此,通常建议在释放内存后,将指针置为空指针,即 ptr = NULL;。这样,即使后续代码中存在误用已释放的指针,由于指针已经被置为空,程序在尝试使用该指针时会触发空指针异常,从而更容易发现和调试问题。

    calloc

函数的功能是为 num 个⼤⼩为 size 的元素开辟⼀块空间,并且把空间的每个字节初始化为0。
与函数 malloc 的区别只在于 calloc 会在返回地址之前把申请的空间的每个字节初始化为0,其余的功能与malloc并无二异,如果空间开辟成功会返回指向这片空间的指针,如果开辟失败会返回NULL。
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stdlib.h>
int main()
{
	int* p = (int*)calloc(10, sizeof(int));
	if (NULL != p)
	{
		int i = 0;
		for (i = 0; i < 10; i++)
		{
			printf("%d ", *(p + i));
		}
	}
	free(p);
	p = NULL;
	return 0;
}

相比  malloc ,它只是把分配的空间全部初始化为  0,所以如果要求对申请的空间进行初始化,使用calloc函数即可。

    realloc

ptr 是要调整的内存地址
size 调整之后新⼤⼩
返回值为调整之后的内存起始位置。
这个函数调整原内存空间⼤⼩的基础上,还会将原来内存中的数据移动到 新 的空间。
realloc函数的出现让动态内存管理更加灵活。
有时会我们发现过去申请的空间太⼩了,有时候我们⼜会觉得申请的空间过⼤了,那为了合理的使用内存,我们⼀定会对内存的⼤⼩做灵活的调整。那 realloc 函数就可以做到对动态开辟内存⼤
⼩的调整。
int *ptr3 = (int *)realloc(ptr1, 20 * sizeof(int));
  1. int *ptr3: 这是一个指针变量 ptr3,它被声明为指向整数的指针。

  2. (int *): 这是一个类型转换操作符,它将 realloc() 函数返回的指针从 void * 类型转换为 int * 类型,以便与 ptr3 的类型匹配。

  3. realloc(ptr1, 20 * sizeof(int)): 这是调用 realloc() 函数来重新调整之前分配的内存块的大小。realloc() 函数接受两个参数:第一个参数是之前分配的内存块的指针,第二个参数是重新调整后的大小(以字节为单位)。在这里,我们将之前分配的内存块 ptr1 的大小调整为可以容纳 20 个整数的内存空间,每个整数的大小是 sizeof(int) 字节。

  4. 整个表达式的结果就是一个指向重新分配的内存空间的指针,该内存空间可以容纳 20 个整数。

需要注意的是,realloc() 函数可能会将之前分配的内存块移动到新的位置,或者在原地扩展内存块的大小。因此,如果调用 realloc() 函数成功,应该将返回的指针赋值给原指针变量(ptr1),以确保我们仍然可以访问到调整后的内存块。如果调用失败,返回值为 NULL,原来的内存块保持不变。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值