动态内存管理常用函数——malloc, free, calloc, realloc

一、malloc函数(与free成对出现)

void* malloc (size_t size);

1.头文件

# include <stdlib.h>

2.功能

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

3.对参数的解释

size即为要申请的空间的大小。

e.g:   

int* elems = (int*)malloc (10*sizeof(int));

即为开辟一个长度为10的int数组。

4.返回值

(1)如果开辟成功,则返回一个指向开辟好空间的指针。

(2)如果开辟失败,则返回一个NULL指针,因此malloc的返回值一定要做检查。

(3)返回值的类型是 void* ,所以malloc函数并不知道开辟空间的类型,具体在使用的时候使用者自己来决定(因此要使用强制类型转换)。

5.注意点

malloc函数分配空间后不会对其变量值进行初始化(变量值是随机的)。

二、free函数

void free (void* ptr);

1.头文件

# include <stdlib.h>

2.功能

用来释放动态开辟的内存。

3.对参数的解释

ptr指的是空间的首地址。

e.g:

int* elems = (int*)malloc (10*sizeof(int)); // 动态开辟一块内存
free(elems);                                // 释放此内存

4.注意点

(1)不要对局部变量进行free。

(2)空间释放只能从动态申请的首地址释放,不能从中途释放。

(3)释放的是ptr指向的空间,而不是p指针变量本身的空间

三、calloc函数

void* calloc (size_t num, size_t size);

1.头文件

# include <stdlib.h>

2.功能

申请一块空间,并将空间中的数据初始化为0(与malloc的不同之处)。

3.参数

num是块个数;size是块大小;num*size就是要申请的空间大小。

4.返回值

成功返回空间首地址;失败返回NULL。

四、realloc函数

void* realloc (void* ptr, size_t size);

1.头文件

# include <stdlib.h>

2.功能

对动态存储的空间在其基础上进行扩容。

3.参数

ptr是原先的空间首地址;size是要扩容到的空间大小。

4.返回值

成功有两种情况,第一种是原有空间足够大,那么就在原地址扩容成功,不释放该块空间;第二种是原有空间不够大,则会释放原先的空间,返回新的空间首地址;失败返回NULL。5

5.具体解释(分情况讨论)

(1)减少内存空间

e.g:

int* p = (int*)malloc(5*sizeof(int));
int* pp = (int*)realloc(p, 3*sizeof(int));

这样做就会使原来的内存空间减少。但是,这个仅仅只是改变索引,并没有影响原来malloc函数分配的内存空间地址

注意:free()函数的使用。对于刚刚申请的内存空间,使用free(p)和free(pp)都是可以的,但是不允许同时使用。因为他们的指向还是同一块内存空间。free(p)后,则p = nullptr,但pp的值不是NULL。(但是在释放之前,&p和&pp的值是一样的)。

(2)增加内存空间
​int* p = (int*)malloc(5*sizeof(int));
int* pp = (int*)realloc(p, 10*sizeof(int));

此类情况又分为以下两种情况:

#1#. 如果当前内存段后面有需要的内存空间,则直接扩展这段内存空间,realloc()将返回原指针。#2#. 如果当前内存段后面的空闲字节不够,那么就使用堆中的第一个能够满足这一要求的内存块,将目前的数据复制到新的位置,并将原来的数据块释放掉,返回新的内存块位置。

(如果申请失败,将返回NULL,此时,原来的指针仍然有效。)

注意:介于以上两种情况,明确realloc函数是对旧内存的操作,可能不需要重新寻找首地址开辟新内存,所以不能在realloc空间之后随便free。

五、具体应用代码

1.题目 

顺序表的基本操作

本题要求实现顺序表元素的增、删、查找以及顺序表输出共4个基本操作函数。L是一个顺序表,函数Status ListInsert_Sq(SqList &L, int pos, ElemType e)是在顺序表的pos位置插入一个元素e(pos应该从1开始),函数Status ListDelete_Sq(SqList &L, int pos, ElemType &e)是删除顺序表的pos位置的元素并用引用型参数e带回(pos应该从1开始),函数int ListLocate_Sq(SqList L, ElemType e)是查询元素e在顺序表的位次并返回(如有多个取第一个位置,返回的是位次,从1开始,不存在则返回0),函数void ListPrint_Sq(SqList L)是输出顺序表元素。实现时需考虑表满扩容的问题。

2.代码

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

#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
#define OVERFLOW -2

typedef int Status;
typedef int ElemType;

#define LIST_INIT_SIZE 100
#define LISTINCREMENT 10

typedef struct {
    ElemType* elem;
    int length;
    int listsize;
} SqList;

Status InitList_Sq(SqList& L) {
    L.elem = (ElemType*)malloc(LIST_INIT_SIZE * sizeof(ElemType)); // 申请内存空间
    if (!L.elem) exit(OVERFLOW);
    L.listsize = LIST_INIT_SIZE;
    L.length = 0;
    return OK;
}

Status ListInsert_Sq(SqList& L, int pos, ElemType e) {
    if (pos < 1 || pos > L.length + 1) return ERROR; 
    if (L.length >= L.listsize) {
        ElemType* newElem = (ElemType*)realloc(L.elem, (L.listsize + LISTINCREMENT) * sizeof(ElemType));                                                // 对数组进行扩容
        if (!newElem) exit(OVERFLOW);
        L.elem = newElem;
        L.listsize += LISTINCREMENT;
    }

    for (int i = L.length; i >= pos; i--) {
        L.elem[i] = L.elem[i - 1];
    }
    L.elem[pos - 1] = e;
    L.length++;
    return OK;
}

Status ListDelete_Sq(SqList& L, int pos, ElemType& e) {
    if (pos < 1 || pos > L.length) return ERROR; 
    e = L.elem[pos - 1];
    for (int i = pos; i < L.length; i++) {
        L.elem[i - 1] = L.elem[i];
    }
    L.length--;
    return OK;
}

int ListLocate_Sq(SqList L, ElemType e) {
    for (int i = 0; i < L.length; i++) {
        if (L.elem[i] == e) {
            return i + 1; 
        }
    }
    return 0; 
}

void ListPrint_Sq(SqList L) {
    for (int i = 0; i < L.length; i++) {
        printf("%d", L.elem[i]);
        if (i < L.length - 1) {
            printf(" ");
        }
    }
    printf("\n");
}

int main() {
    SqList L;

    if (InitList_Sq(L) != OK) {
        printf("InitList_Sq: 初始化失败!!!\n");
        return -1;
    }

    for (int i = 1; i <= 10; ++i)
        ListInsert_Sq(L, i, i);

    int operationNumber;
    scanf("%d", &operationNumber);

    while (operationNumber != 0) {
        int operationType;
        scanf("%d", &operationType);

        if (operationType == 1) {
            int pos, elem;
            scanf("%d%d", &pos, &elem);
            if (ListInsert_Sq(L, pos, elem) != OK) {
                printf("ERROR\n");
            }
        } else if (operationType == 2) {
            int pos;
            ElemType elem;
            scanf("%d", &pos);
            if (ListDelete_Sq(L, pos, elem) == OK) {
                printf("%d\n", elem);
            } else {
                printf("ERROR\n");
            }
        } else if (operationType == 3) {
            ElemType elem;
            scanf("%d", &elem);
            int pos = ListLocate_Sq(L, elem);
            if (pos >= 1 && pos <= L.length)
                printf("%d\n", pos);
            else
                printf("NOT FOUND\n");
        } else if (operationType == 4) {
            ListPrint_Sq(L);
        }
        operationNumber--;
    }

    free(L.elem); // 释放内存
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值