目录
1. C语言
头文件
#include <stdlib.h>
1.1 malloc
函数功能:
分配所需的内存空间,并返回一个指向它的指针。
void *malloc(size_t size)
参数:
size--内存块的大小,以字节为单位。
返回值:
该函数返回一个指针 ,指向已分配大小的内存。如果请求失败,则返回 NULL。
示例:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main()
{
char *str = (char*)malloc(15);
strcpy(str, "runoob");
printf("String = %s, Address = %u\n", str, str);
free(str);
return(0);
}
1.2 calloc
函数功能:
分配所需的内存空间,并返回一个指向它的指针。
malloc和calloc之间的不同点是:malloc 不会设置内存为零,而 calloc 会设置分配的内存为零。
函数原型:
void *calloc(size_t nitems, size_t size)
函数参数:
nitems -- 要被分配的元素个数。
size -- 元素的大小。
返回值:
该函数返回一个指针,指向已分配的内存首地址。如果请求失败,则返回 NULL。
示例:
#include <stdio.h>
#include <stdlib.h>
int main()
{
int i, n;
int *a;
printf("要输入的元素个数:");
scanf("%d",&n);
a = (int*)calloc(n, sizeof(int));
printf("输入 %d 个数字:\n",n);
for(i = 0 ; i < n ; i++)
{
scanf("%d",&a[i]);
}
printf("输入的数字为:");
for( i=0 ; i < n ; i++ )
{
printf("%d ",a[i]);
}
free (a); // 释放内存
return(0);
}
1.3 realloc
函数功能:
尝试重新调整之前调用 malloc 或 calloc 所分配的 ptr 所指向的内存块的大小。
realloc 函数可以根据实际需要,对当前使用的内存大小进行调整。
函数原型:
void *realloc(void *ptr, size_t size)
函数参数:
ptr -- 指针指向一个要重新分配内存的内存块,该内存块之前是通过调用 malloc、calloc 或 realloc 进行分配内存的。
如果为NULL,则会分配一个新的内存块,且函数返回一个指向它的指针。此时realloc等同于malloc函数
size -- 内存块的新的大小,以字节为单位。
如果大小为 0,且 ptr 指向一个已存在的内存块,则 ptr 所指向的内存块会被释放,并返回一个空指针。
返回值:
该函数返回一个指针 ,指向重新分配大小的内存。如果请求失败,则返回 NULL。
示例:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char *str;
/* 最初的内存分配 */
str = (char*) malloc(15);
strcpy(str, "runoob");
printf("String = %s, Address = %p\n", str, str);
/* 重新分配内存 */
str = (char*)realloc(str, 25);
strcat(str, ".com");
printf("String = %s, Address = %p\n", str, str);
free(str);
return(0);
}
执行结果:
String = runoob, Address = 0x7fa2f8c02b10
String = runoob.com, Address = 0x7fa2f8c02b10
从执行结果可以看出,使用realloc分配的地址只是改变了地址空间的大小,其地址没有发生变化
补充说明:
如果要申请更大的内存,realloc函数内部要分两种情况进行处理:
- 情况1:原有内存后面有足够的空闲内存空间可用,那么扩展内存时会在原有内存之后直接追加空间,原来内存中的数据不发生变化。
- 情况2:原有内存后面没有足够大的内存空间可用,这时 realloc 函数会在堆空间上另找一个合适大小的连续空间来使用,函数返回这个新的内存地址;并且realloc 函数会将原来内存中的数据自动拷贝到新的内存空间中。
2. C++
new和delete
2.1 new的原理
new对象:
- 对于简单类型,直接调用operator new分配内存;
- 对于复杂结构,先调用operator new分配内存,然后在分配的内存上调用构造函数;
new数组:
- 对于简单类型,new[]计算好大小后调用operator new;
- 对于复杂数据结构,new[]先调用operator new[]分配内存,然后在p的前四个字节写入数组大小n,然后调用n次构造函数
- 即:针对复杂类型,new[]会额外存储数组大小。假设指针p指向new[]分配的内存,因为要4字节存储数组大小,实际分配的内存地址为[p-4],系统记录的也是这个地址
4.2 delete的原理
delete对象:
- 对于简单类型,默认只是调用free函数
- 对于复杂类型,先调用析构函数,再调用operator delete
delete数组:
- 对于简单类型,delete和delete[]相同
- 假设指针p指向new[]分配的内存,因为要4字节存储数组大小,实际分配的内存地址为[p-4],系统记录的也是这个地址。delete[]实际释放的就是p-4指向的内存。而delete会直接释放p指向的内存,这个内存根本没有被系统记录,所以会崩溃。
4.3 delete[] 如何知道释放内存的大小
需要在 new [] 一个对象数组时,需要保存数组的维度,C++ 的做法是在分配数组空间时多分配了 4 个字节的大小,专门保存数组的大小,在 delete [] 时就可以取出这个保存的数,就知道了需要调用析构函数多少次了。