C语言动态内存分配及其函数

目录

一,为什么用动态内存分配

二.malloc函数

(1)malloc函数介绍

(2)注意事项

三.calloc函数

四.realloc函数

(1)realloc函数介绍

(2)注意事项


一,为什么用动态内存分配

在C语言中,我想要创建一个个可变长度的的数组, 那我该怎么做呢?

试着创建一个可变大小的结构体数组。

代码:

struct S {
	char name[20];
	int age;
};

int main() {
	int n = 0;
	scanf("%d", &n);
	struct S arr[n];
	return 0
}

 结果VS编译器报了错误

这难道是编译器的问题? 

在linux环境下我继续尝试了上面的代码

 

 代码运行成功了!!

这是为什么呢?

原来C语言C99标准中增加了 linux支持,在linux是可以创建变长数组(数组长度可变的).

如果我们一定要在VS中使用可变数组呢?那么得用使用动态内存分配函数了!!

二.malloc函数

(1)malloc函数介绍

malloc的参数是一个int类型,指的是所需开辟内存的字节大小

malloc会返回一个指向开辟空间的指针.如果开辟失败,会返回空指针

malloc的返回类型是void*,返回的是内存起始地址

举例:

使用malloc函数向内存申请10个整形的空间,

    #include<stdilb.h>

    #include<string.h>

    #include<errno.h>

    int* p=(int*) malloc(10*sizeof(int));
    if (p==NULL)
    {
        printf("%s\n", strerror(errno));
    }

由于malloc函数返回值是void*,如果是需要一个整形指针接收,要使用(int*)进行强制类型转换,

如果开辟失败,则打印出出错信息,

如果开辟成功,则创建这个内存,p指针指向了这段内存的起始地址

画画图:

内存布局:

可以看到,生成的都是cd cd的内存地址

 

用这段内存打印出0-9:


int main() {
	int* p=(int*) malloc(10*sizeof(int));
	if (p==NULL)
	{
		printf("%s\n", strerror(errno));
	}
	else
	{
		int i = 0;
		for (i = 0; i < 10; i++)
		{
			*(p + i) = i;
		}
		for (i = 0; i < 10; i++)
		{
			printf("%d ", *(p + i));
		}
		*(p + 1) = 1;
	}

	free(p);

	return 0;
}

妥妥的打印了出来 

 

(2)注意事项

1.开辟的内存不能超过最大空间,否则会返回空指针!

试下开辟INT_MAX个字节的空间, 这个数字是几十亿级的

尝试下,结果是失败的,报错信息是空间不够足

 说明开辟空间时,内存需要足够的大,而且判断是否开辟成功能让代码变的更加的安全!!

2. 当动态申请的空间不再使用的时候,应该还给操作系统

也就是在使用完内存后,需要用free函数,释放出去.

三.calloc函数

(1)calloc函数介绍

calloc的第一个参数是元素的个数,第二个参数是每个元素的长度

calloc开辟空间,但是各个字节初始化都是0

calloc会返回一个指向开辟空间的指针.如果开辟失败,会返回空指针

calloc的返回类型是void* ,返回的是内存起始地址

举例:

使用calloc函数向内存申请10个整形的空间.并打印出存放的元素.

    #include<stdilb.h>

    #include<string.h>

    #include<errno.h>

    int* p = (int*)calloc(10, sizeof(int));
    if (p==NULL)
    {
        printf("%s\n", strerror(errno));
    }
    else
    {
        int i = 0;
        for ( i = 0; i < 10; i++)
        {
            printf("%d ", *(p + i));
        }
    }

 可以看到,打印出的都是0

内存布局: 

 

 

四.realloc函数

(1)realloc函数介绍

调整动态开辟内存空间的大小

第一个参数是开辟内存对应的指针,第一个参数是添加需要调整的大小

举例:

我需要用内存分配打印出0-9的数字,而我只开辟了20字节的大小的空间

    int *p=(int*)malloc(20);
    if (p==NULL)
    {
        printf("%s\n", strerror(errno));
    }
    else
    {

        int i = 0;
        for ( i = 0; i < 5; i++)
        {
            *(p + i) = i;
        }
    }

假设这里,20个字节不能满足我们的使用了,希望我们能够有40个字节的空间,这里就可以使用realloc来调整动态开辟的空间

打印出来,后面五个为随机值

 

 

我们用realloc调整空间

    p = realloc(p, 40);

    if (p != NULL)
    {
        int i = 0;
        for (i = 5; i < 10; i++)
        {
            *(p + i) = i;
        }
        for (i = 0; i < 10; i++)
        {
            printf("%d ", *(p + i));
        }
    }

打印出来

(2)注意事项

1.如果p指向空间之后有足够的内存空间可以追加,则直接追加,后返回p

 比如,我们要开辟了这个20个字节的空间

开辟成功后地址是0x00945f68

可以看到,调整内存大小后,地址还是0x00945f68,则说明realloc返回的还是p原来的地址

2.如果p指向的空间之后没有足够的内存空间可以追加,则realloc函数会重新找一个新的内存区开辟一块满足需求的空间,并且把原来内存中的数据拷贝回来,释放旧的内存空间,返回新开辟空间的内存地址.

 00c55f68

 继续开辟20个字节的空间,不过这块空间准备调整成4000个字节

 执行后,可以看到内存地址已经发生了变化!!这说明函数已经开辟了另一块空间,指针p指向了该空间

 可以看到,原来的数据是没有发生变化的

3.得用新的变量来接收realloc函数的返回值,以免p被丢弃

    int* ptr = realloc(p, 4000);

	if (ptr != NULL)
	{
		p = ptr;
		int i = 0;
		for (i = 5; i < 10; i++)
		{
			*(p + i) = i;
		}
		for (i = 0; i < 10; i++)
		{
			printf("%d ", *(p + i));
		}
	}

### C语言中动态分区分配算法的函数流程图 #### alloc() 函数流程图 该函数用于分配内存给请求者。当有新的进程需要内存空间时,`alloc()`会遍历空闲分区列表寻找合适的分区。 1. **输入参数** - `size`: 请求的内存量。 2. **处理逻辑** - 初始化指向空闲分区表头节点的指针。 - 使用循环遍历整个空闲分区链表。 - 对于每个分区判断其大小是否满足需求以及是否适合当前使用的分配策略(如首次适应、最佳适应等)[^1]。 - 如果找到合适的空间,则分割此区域并更新相应的记录;如果未找到则返回错误码或提示失败消息。 3. **输出结果** - 成功情况下返回新创建的子分区首地址及其实际尺寸; - 失败情况下的适当响应。 ```mermaid graph TD; A[Start Alloc Function] --> B{Is there enough space?}; B -- Yes --> C[Find Suitable Partition]; C --> D{Does it fit the strategy?}; D -- No --> E[Continue Searching]; D -- Yes --> F[Split and Update Records]; F --> G(Return Address & Size); B -- No --> H(Return Error Message); ``` #### free() 函数流程图 这个函数负责释放不再被占用的内存块回到系统的可用资源池里去。 1. **输入参数** - `address`: 要释放的内存起始位置。 2. **处理逻辑** - 定位到指定地址对应的已用区段。 - 将这块区域的状态标记为空闲,并将其加入到空闲分区链表头部或者尾部取决于具体实现方式。 - 合并与相邻的其他空闲区块形成更大的连续区间以便后续更高效的再利用[^2]. 3. **输出结果** - 返回成功标志或其他反馈信息。 ```mermaid graph TD; A[Begin Free Process] --> B(Locate Used Block by Address); B --> C(Mark as Free State); C --> D{Can Merge with Neighbors?}; D -- Yes --> E[Merge Adjacent Blocks]; D -- No --> F(Directly Insert into Idle List); E --> G(Return Success Flag); F --> G; ``` 上述两个主要的操作构成了完整的动态分区分配机制,在C语言环境下可以通过定义特定的数据结构比如PCB(process control block) 和 链表来维护这些元数据[^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值