【C语言】动态内存管理

本文介绍了C语言中的动态内存管理函数,包括malloc用于分配内存,free用于释放内存,calloc用于初始化分配的内存,以及realloc用于调整内存大小。同时,文章列举了使用这些函数时常见的错误,如对NULL指针解引用、内存越界访问等,并提到了C99中的柔性数组概念。
摘要由CSDN通过智能技术生成

⚡Hello~这里是傾城49⚡

🐏不定期更新知识干货~🐏

🌈点个关注不迷路~🌈

文章目录

前言

动态内存函数的介绍

malloc

free

calloc

realloc

常见的错误

1.对NULL指针解引用

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

3.对非动态开辟内存使用free

4.使用free释放一块动态开辟空间

5对同一块动态内存多次释放

6.动态开辟内存忘记释放

C/C++程序中的内存开辟

柔性数组

特点

使用

总结



前言

当我们要创建一个目录,写一些东西,开辟一定的空间,但是写过一次后就不能再写了,因为开辟空间已经满了。这时候就需要用到动态内存,随时增加或删除内存。


动态内存函数的介绍

malloc

void * malloc ( size_t size )

向内存申请一块连续可用的空间,申请完后返回指向这块空间的指针。

  • malloc的返回值一定要检查是否为空指针。
  • malloc申请的空间没有初始化,直接返回起始地址。
  • 若参数size为0,则malloc的行为取决于编译器。


free

void * free ( void * ptr )

  • 释放申请的内存
  • 若参数ptr指向的空间不是动态开辟的,则free函数行为未定义
  • 若参数ptr为空指针,则函数无意义
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
int main()
{
	int* p = (int*)malloc(40);//放10个整型
	if (p == NULL)
	{
		printf("%s\n", strerror(errno));
	}
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		*(p + i) = i + 1;//存放1~10
	}
	//打印
	for (i = 0; i < 10; i++)
	{
		printf("%d ", *(p + i));
	}
	free(p);
	p = NULL;
	return 0;
}


calloc

void * calloc ( size_t num, size_t size )

  • num指开辟元素的个数
  • size指每个元素的大小
  • calloc申请的空间会把空间初始化为0,然后再返回起始地址。
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
int main()
{
	int* p = (int*)calloc(10, sizeof(int));
	if (p == NULL)
	{
		perror("calloc");
		return 1;
	}
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		printf("%d ", *(p + i));//10个0
	}
	free(p);
	p = NULL;
	return 0;
}


realloc

void * realloc ( void * ptr, size_t size )

  • realloc可调整开辟空间的大小
  • ptr为要调整的内存地址size为调整之后的大小
  • 返回值为调整之后的内存起始位置。
  • 若扩容空间时不够一个连续空间,则realloc会找一个满足空间大小的新的连续空间,旧空间的数据拷贝到新空间前面的位置。
  • 用新的指针接收数据。
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
int main()
{
	int* p = (int*)malloc(5 * sizeof(int));
	if (p == NULL)
	{
		printf("%s\n", strerror(errno));
		return 1;
	}
	int i = 0;
	for (i = 0; i < 5; i++)
	{
		*(p + i) = i + 1;
	}

	//增加空间
	int* ptr = (int*)realloc(p, 10 * sizeof(int));
	if (ptr != NULL)
	{
		p = ptr;
	}
	//打印
	for (i = 0; i < 10; i++)
	{
		printf("%d ", *(p + i));
	}
	
	free(p);
	p = NULL;
	return 0;
}

常见的错误

1.对NULL指针解引用

void test()
{
    int *p = (int*)malloc(4);
    *p = 20;//如果p的值是NULL,则会报错
    free(p);
    p = NULL;
}

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

void test()
{
    int i = 0;
    int *p = (int*)malloc(5*sizeof(int));
    if(p == NULL)
    {
        return;
    }
    for(i=0; i<=5; i++)
    {
        *(p+i) = i;//当i是5时越界访问
    }
    free(p);
    p = NULL;
}

3.对非动态开辟内存使用free

void test()
{
    int a = 100;//栈区
    int *p = &a;
    free(p);
    p = NULL;
}

4.使用free释放一块动态开辟空间

void test()
{
    int *p = (int*)malloc(5 * sizeof(int));
    int i = 0;
    for(i=0; i<5; i++)
    {
        *p = i;
        p++;
    }
    //循环完p的地址已经动了
    free(p);//释放的是起始位置
    p = NULL;
}

5对同一块动态内存多次释放

void test()
{
    int *p = (int*)malloc(5 * sizeof(int));
    if(p == NULL)
    {
        return;
    }
    
    free(p);

    free(p);
//若忘记前面释放过,则会报错
//可在释放后加上p=NULL
//free(NULL)无影响

}

6.动态开辟内存忘记释放

void test()
{
    int *p = (int*)malloc(5 * sizeof(int));

}

int main()
{
    test();
//导致内存泄漏
}

C/C++程序中的内存开辟

1.栈区(stack):在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。栈内存分配运输内置于处理器的指令集中,效率高,但是分配的内存容量有限。栈区主要存放运行函数而分配的局部变量、函数参数、返回数据、返回地址等。

2.堆区(heap):一般由程序员分配释放,若程序员不释放,程序结束时可能由OS回收。分配方式类似于链表。

3.数据段(静态区)(static):存放全局变量、静态数据。程序结束后由系统释放。

4.代码段:存放函数体(类成员函数和全局函数)的二进制代码。


柔性数组

C99中,结构中的最后一个元素允许是未知大小的数组,叫做【柔性数组】成员

struct S
{
    int a;
    int b[0];//大小未知 - 柔性数组成员
};

特点

  • 结构中的柔性数组成员前面必须至少有一个其他成员。
  • sizeof返回的这种结构大小不包括柔性数组的内存
  • 包含柔性数组成员的结构用malloc函数进行内存的动态分配,并且分配的内存应该大于结构的大小,以适应柔性数组的预期大小。
typedef struct S
{
    int a;
    int b[0];
}s;
printf("%d\n",sizeof(s));//4

使用

int i = 0;
s *p = (s*)malloc( sizeof(s) + 50 * sizeof(int) );
p->i = 100;
for(i=0; i<50; i++)
{
    p->b[i] = i;
}
free(p);
p = NULL;

柔性数组成员b,获得了50个整型元素的连续空间。


总结

以上就是动态内存管理的相关知识点~

  • 5
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值