内存可以分为5个区域:堆、栈、全局/静态存取区、常量存储区和自由存储区。
栈区(stack):函数执行时,局部变量、函数形参和临时变量都是在栈区获得内存的,由编译器自动完成的,函数执行结束时这些存储单元自动被释放。栈内存的分配运算内置于处理器的指令集中,效率很高,但分配的内存容量有限;
堆区(heap):一般由程序员分配释放,若程序员不释放,则可能会引起内存泄漏(memory leak),C 标准函数库提供了许多函数来实现对堆上内存管理,其中就包括接下去要讲的:malloc函数,calloc函数、realloc函数和free函数,使用这些函数需要包含头文件stdlib.h。
动态内存分配(dynamic memory allocation),从堆区分配指定字节(byte)的内存。
函数原型:
void* malloc (size_t size);
其中形参size为需要分配的内存字节数,分配成功的话,函数返回已分配内存的首地址;反之,返回NULL。
需要注意的是,函数的返回值类型是 void *,所以在使用 malloc() 时通常需要进行强制类型转换,将 void 型指针转换成我们需要的类型,例如:
int *p = (int *)malloc(sizeof(int)*10); // 分配10个int类型的内存空间
另外,通过该函数分配得到的内存空间是未被初始化的,内存的值是未知的。因此,一般在使用该内存空间之前,要调用另一个函数memset()来将其初始化为0。
函数原型:
void *memset(void *p, int c, size_t n);
其中,形参p为所操作的内存空间的首地址,c为赋给每个字节的值,n为操作内存空间的字节数;memset()函数是以字节为单位进行赋值的,所赋值的范围是0x00~0xFF。若想要对一个double或int型的数组赋值时,就特别需要注意。memset()函数也是一种对较大的结构体或数组进行清零的比较快的方法。
例如:
memset(a, 0, 20) //把一个char a[20]清零
注意:通过malloc()函数得到的堆内存必须使用memset()函数来初始化。
#include
#include
#include
int main()
{
int *p=NULL;
p=(int *)malloc(sizeof(int)*10);
if(NULL==p){
printf("Can't get memory!\n");
return -1;
}
printf("%d\n",*p); //输出分配的空间上的值
memset(p,0,sizeof(int)*10); //将p指向的空间清0
printf("%d\n",*p); //输出分配的空间上的值
*p=10;
printf("%d\n",*p); //输出分配的空间上的值
return 0;
}
calloc()函数与malloc()函数的功能相类似,都是从堆内存中分配空间,原型:
void* calloc (size_t num, size_t size);
calloc() 在内存中动态地分配了 num*size 个字节长度的连续内存空间,并且每个字节的值都初始化为0。
返回值与malloc()函数类似,可以参考malloc()函数。
calloc()函数与malloc函数的一个显著不同时是,calloc()得到的内存空间是经过初始化的,其内容全为0,calloc()函数适合为数组申请空间,可以将size设置为数组元素的空间长度,将n设置为数组的容量。
#include
#include
int main()
{
int *pData;
int i=4,n=0;
pData = (int*) calloc (i,sizeof(int));
if (pData==NULL) {
printf("Can't get memory!\n");
return -1;
}
for (n=0;nprintf ("%d\n",pData[n]);
}
return 1;
}
realloc()函数的功能比malloc()函数和calloc()函数的功能更为丰富,可以实现内存分配和内存释放的功能,其原型为:
void* realloc (void* ptr, size_t size);
其中ptr必须为需要重新分配的堆内存空间指针,即由malloc函数、calloc函数或realloc函数分配空间的指针;size 为新的内存空间的大小,size 可比原来的大或者小,还可以不变。当 malloc()、calloc() 分配的内存空间不够用时,就可以用 realloc() 来调整已分配的内存。
a.如果 ptr 为 NULL,它的效果和 malloc() 相同,即分配 size 字节的内存空间。
b.如果 size 的值为 0,那么 ptr 指向的内存空间就会被释放,但是由于没有开辟新的内存空间,所以会返回空指针;类似于调用 free()。
(1)realloc()函数可以对给定的指针所指的空间进行扩大或者缩小,无论是扩张或是缩小,原有内存的中内容将保持不变。当然,对于缩小,则被缩小的那一部分的内容会丢失。realloc()并不保证调整后的内存空间和原来的内存空间保持同一内存地址。相反,realloc()函数返回的指针很可能指向一个新的内存地址;
(2)我们知道realloc()函数是从堆上分配内存的,当扩大一块内存空间时,realloc()会试图直接从堆上现存的数据后面的那些字节中获得附加的字节,如果能够满足,函数直接返回的指针不变;如果数据后面的字节不够,那么就会使用堆区第一个足够大小的可用内存空间,现存的数据然后就被拷贝至新的位置,而老块则放回到堆上。这句话传递的一个重要的信息就是数据可能被移动。
#include
#include
int main()
{
char *p,*q;
p = (char *)malloc(10);
q = p;
p = (char *)realloc(p,10); //重新分配堆内存
printf("p=0x%x\n",p);
printf("q=0x%x\n",q);
return 1;
}
#include
#include
int main()
{
char *p,*q;
p = (char *)malloc(10);
q = p;
p = (char *)realloc(p,10000); //重新分配堆内存
printf("p=0x%x\n",p);
printf("q=0x%x\n",q);
return 1;
}
就先讲到这里吧~