一、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;
}