动态内存
c语言还有一个功能:动态内存分配,它依赖指针的概念,为在代码中使用指针提供了很强的激励机制,它允许在执行程序时动态内存分配。
在CPU内部存在堆栈,堆区域用于动态分配内存,由程序员完全掌控。栈区域主要保存函数参数和局部变量。在执行完该函数后,存储参数和局部变量的存储空间会完全释放。
动态内存分配:malloc()函数
在运行时分配内存最简单的标准函数是malloc()
,需要调用stdlib.h
。
函数原型:
_CRTIMP void * __cdecl malloc(size_t);
参数说明:函数会返回一个void*
类型的指针;
动态内存分配的一条例子:
int *pNumber = (int *)malloc(100);
返回的void*
类型的数据能指向任意的类型的指针,然而不能取消对void
指针的引用;因此,将void*
转换成int*
,防止报错。
如果因为某种原因分配内存失败,malloc()
会返回NULL
;
int *pNumber = (int *)malloc(100);
if(!pNumber)
{
//分配内存失败;
}
释放动态内存
在动态分配内存时,应该在不需要时,释放掉内存空间;如果未能及时释放,会造成内存泄漏;堆上的内存会在程序结束时,自动释放内存。
内存泄漏(Memory Leak)是指程序中己动态分配的堆内存由于某种原因程序未释放或无法释放,造成系统内存的浪费,导致程序运行速度减慢甚至系统崩溃等严重后果。
要释放动态分配的内存,必须能访问到引用的内存块的地址。
free(pNumber);
pNumber = NULL;
在释放指针指向的堆内存时,必须确保它不被另一个地址覆盖;
代码示例:
#include <STDIO.H>
#include <stdlib.h>
#include <stdbool.h>
int main(void)
{
unsigned long long *pPrimes = NULL;
unsigned long long trial;
bool found = false;
int total;
int count;
int i;
printf("How many primes would you like - you'll get at least 4?");
scanf("%d",&total);
total = total < 4 ? 4 : total;
pPrimes = (unsigned long long*)malloc(total*sizeof(unsigned long long));
if(!pPrimes)
{
printf("end");
return 1;
}
*pPrimes = 2ULL;
*(pPrimes + 1 ) = 3ULL;
*(pPrimes + 2 ) = 5ULL;
count = 3;
trial = 5ULL;
while (count < total)
{
trial += 2ULL;
for (i = 1;i < count;++i)
{
if (!(found = (trial % *(pPrimes + i))))
break;
}
if(found)
*(pPrimes + count++) = trial;
}
for ( i = 0; i < total; ++i)
{
printf("%100u",*(pPrimes + i));
if(!(i+1)%5)
printf("\n");
}
printf("\n");
free(pPrimes);
pPrimes = NULL;
return 0;
}
How many primes would you like - you’ll get at least 4?25
2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97
请按任意键继续. . .
用calloc()函数分配内存
在stdlib.h
头文件中声明的calloc()
函数相比于malloc()
函数有两个优点:第一,把内存分配给固定大小的数组;第二,初始化了所分配的内存,所有位为0;
函数原型
_CRTIMP void * __cdecl calloc(size_t, size_t);
它的用法与malloc()
相似
int *pNumber = (int *)calloc(75,sizeof(int));//申请了75个int类型的内存
if(!pNumber)
{
//分配内存失败;
}
拓展动态内存
realloc()
函数可以重用或拓展以前用malloc()
或calloc()
(或者realloc()
)分配的内存。
realloc()
函数需要两个参数,一个是包含地址的指针,该地址由malloc()
或calloc()
或者realloc()
返回;另一个是重新分配的字节数;
代码示例:
#include <STDIO.H>
#include <STDLIB.H>
int main(void)
{
char*p = NULL;
p=(char*)malloc(100);
if(p)
printf("MemoryAllocatedat:%x\n",p);
else
printf("NotEnoughMemory!\n");
getchar();
p=(char*)realloc(p,256);
if(p)
printf("MemoryReallocatedat:%x\n",p);
else
printf("NotEnoughMemory!\n");
free(p);
p = NULL;
return 0;
}
MemoryAllocatedat:6b1160
MemoryReallocatedat:6b1030
Press any key to continue
使用动态分配的基本原则
- 避免分配大量的小内存块。分配堆上的内存需要一定的系统开销,所以分配多给小的内存块比分配几个大的内存块开销要大;
- 仅在需要的时候分配.只要堆上使用完了内存块,就释放它;
- 总是确保释放已分配的内存。
- 在释放内存之前,确保不会无意中覆盖堆上已分配的内存的地址,负责程序会出现内存泄漏。