C语言之动态内存分配

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

一般的内存开辟方式只能开辟固定大小的内存空间,动态内存分配方式可以动态开辟内存,更加灵活。

动态内存分配函数

malloc()

函数原型

void *malloc(size_t size); //(size_t指内存块大小,以字节为单位)

函数功能

分配所需的内存空间,并返回一个指向它的指针

注意

开辟成功后,malloc会返回一个void*指针,不能直接解引用,它可以被强转为所需的数据指针类型
开辟失败后,malloc会返回一个NULL指针,所以malloc以后一定要进行检查

示例

int* p = (int*)malloc(20);    //开辟一个20字节的内存空间,并且强转为int型
if (p == NULL)
{
    printf("%s\n", strerror(errno));
    return 1;
}

开辟成功,我们发现开辟的空间里面放的使一些随机值

对分配的内存初始化后,里面的随机值发生变化

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

calloc()

函数原型

void *calloc(size_t nitems, size_t size);
//nitems-- 要被分配的元素个数。size -- 元素的大小。

函数功能

分配所需的内存空间,并返回一个指向它的指针。malloccalloc 之间的不同点是,malloc 不会设置内存为零,而 calloc 会设置分配的内存为零。

注意

开辟成功后,calloc会返回一个void*指针,不能直接解引用,它可以被强转为所需的数据指针类型
开辟失败后,calloc会返回一个NULL指针,所以malloc以后一定要进行检查

示例

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

开辟成功,我们发现里面的值已经被初始化为0

我们进行初始化

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

realloc()

函数原型

void *realloc(void *ptr, size_t size)
//ptr -- 指针指向一个要重新分配内存的内存块,该内存块之前是通过调用 malloc、calloc 或 realloc 进行分配内存的。如果为空指针,则会分配一个新的内存块,且函数返回一个指向它的指针。
//size -- 内存块的新的大小,以字节为单位。如果大小为 0,且 ptr 指向一个已存在的内存块,则 ptr 所指向的内存块会被释放,并返回一个空指针。

函数功能

函数尝试重新调整之前调用 malloccalloc 所分配的 ptr 所指向的内存块的大小。

注意

开辟成功后,calloc会返回一个void*指针,不能直接解引用,它可以被强转为所需的数据指针类型
开辟失败后,calloc会返回一个NULL指针,所以malloc以后一定要进行检查

示例

void test()
{
    char* str;

    /* 最初的内存分配 */
    str = (char*)malloc(15);
    strcpy(str, "小谢");
    printf("String = %s,  Address = %p\n", str, str);

    /* 重新分配内存 */
    str = (char*)realloc(str, 25);
    strcat(str, "%同学");
    printf("String = %s,  Address = %p\n", str, str);

    free(str);
    str=NULL;
}

注意:

  1. 原空间后面还有多余的空间的话,在原空间后面开辟新的空间

  1. 原空间后没有对于的空间的话,重新找一片空间开辟。

free()

函数原型

void free(void *ptr)
//ptr -- 指针指向一个要释放内存的内存块,该内存块之前是通过调用 malloc、calloc 或 realloc 进行分配内存的。如果传递的参数是一个空指针,则不会执行任何动作。

函数功能

释放之前调用 calloc、malloc 或 realloc 所分配的内存空间。

常见的动态内存错误

    • 对NULL指针进行操作

//1. 对NULL指针进行操作
int* p1 = (int*)malloc(10 * sizeof(int));
//没有对开辟的空间进行检查,如果申请空间失败就是对空指针操作
//assert(p1);    //应进行检查
for (int i = 0; i < 10; i++)
{
    *(p1 + i) = i;
}
free(p1);
p1=NULL;
    • 对动态开辟空间的越界访问

//2. 对动态开辟空间的越界访问
int* p2 = (int*)malloc(10 * sizeof(int));  
assert(p2);
for (int i = 0; i <= 10; i++)    //初始化11个整数
{
    *(p2 + i) = i;
}
free(p2)
p2=NULL;
    • free释放非动态开辟的内存

//5. free释放非动态开辟的内存
int a[10] = { 0 };
free(a);
    • 使用free释放了动态开辟空间的一部分

//4. 使用free释放了动态开辟空间的一部分
int* p4 = (int*)calloc(10, sizeof(int));
//int* temp=p4;
for (int i = 0; i < 5; i++)
{
    *p4++ = i;
}
free(p4);
//free(temp);
temp=NULL;
    • 忘记释放动态开辟的空间

//3. 忘记释放动态开辟的空间
int* p3 = (int*)malloc(10 * sizeof(int));
assert(p3);
for (int i = 0; i <= 10; i++)
{
    *(p3 + i) = i;
}
//free(p2);    //忘记释放
//p2=NULL;
    • 对同一块空间进行多次释放

//6. 对同一块空间进行多次释放
int* p6 = (int*)malloc(20);
free(p6);
//解决方案,在free(p6)后对p6进行复制为NULL,这样即使再次free(p6)也是对空指针操作
//p6=NULL;
free(p6);
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小谢%同学

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值