电子常识
malloc函数和free函数
假设您的程序在执行过程中需要分配一定量的内存。您可以随时调用malloc函数从堆中申请一块内存。在操作系统为您的程序预留出这块内存,之后您就可以随意使用它了。用完之后,要使用free函数将这块内存返回给操作系统进行回收。以后其他程序还可以按自己的需要预留这块内存。
作为例子,下面的代码演示了最简单的使用堆的方法:
int main() {int *p;p = (int *)malloc(sizeof(int));if (p==0) {printf("错误:内存不足n");return 1; }*p=5;printf("&dn", *p);free(p);return 0;}
程序的开始调用了malloc函数,这个函数做了三件事:
下图显示了调用malloc之后的内存状态:
接着程序用if (p==0)检查指针p以确定分配申请成功(此行也可写成if (p==NULL)甚至if (!p))。如果分配失败(p等于零),则程序终止,否则程序将分配的内存块初始化为5,然后打印内存块的值,接着调用free函数将内存块返还给堆,最后退出。
前面的章节有一段代码是将p赋值为一个现成整数i的地址,而本例中的代码和那段代码实际上并无不同。区别只是在于:对于变量i的内存,它是程序预分配内存空间的一部分,有两个名字i和*p;而对于从堆上分配的内存,它只有一个名字*p,且是在程序运行中分配的。两个常见的问题是:
下面两段程序显示了两种不同的使用指针的正确方法,旨在区分指针和指针的值在使用上的区别:
void main() {int*p, *q;p=(int *)malloc(sizeof(int));q=p;*p=10;printf("%dn", *q);*q=20; printf("%dn", *q);}
此程序的最后输出结果是代码第4行打印的10和代码第6行打印的20。下面是一个内存状态示意图:
下面这个程序稍有不同:
void main() {int *p, *q;p=(int *)malloc(sizeof(int));q=(int *)malloc(sizeof(int)); *p=10;*q=20;*p=*q;printf("%dn", *p);}
此程序的最后输出结果是代码第6行打印的20。下面是它的内存状态示意图:
注意,编译器会接受*p=*q,因为*p和*q都是整数。这条语句的意思是说:“将q指向的整数传送到p指向的整数中去。”被传送的是数值。编译器也会接受p=q,因为p和q都是指针且指向相同的类型(若s为指向字符的指针则p=s是不允许的,因为它们指向不同类型)。p=q这条语句的意思是说:“将p指向和q相同的内存位置。”换句话说,q指向的地址被传送到了p,因此两个指针指向相同的地址。被传送的是地址。
从这些例子可以知道,初始化指针的方式有四种。在程序中声明一个指针时(如int *p),它开始处于未初始化状态。它可能指向任何位置,因此对它的解引用(取出指针指向的地址中的内容)是错误的。初始化指针就是将其指向一个已知的内存地址。
p=0;
或:
p=NULL;
此语句完成的操作是将零赋给p。指针p指向的地址为零。一般用下面的示意图表示这种情况:
任何指针都可设为指向零地址。虽然p指向零地址,但是它却不指向任何真正的内存块。此指针保存的零值只是一个标志。可以像下面语句这样使用它:
if (p==0) {...}
或:
while (p!=0){...}
系统会识别零值,如果您无意中解引用一个零指针,系统会报错。例如下列代码:
p=0;*p=5;
程序一般会崩溃。指针p不指向内存块而是零地址,所以不能为*p赋值。后面我们讲到链表时,零指针将被作为一个标志使用。
malloc命令用于分配一个内存块。当此内存块不再需要时还可以将其释放。释放的内存块可以被后来的malloc语句重新分配,这样系统就可以回收内存。释放内存的命令叫做free,它接受一个指针作为参数。free命令完成两件事情:
free语句只是将指针还原为未初始化状态并使内存块在堆上重新变成可用状态。
下例显示了如何使用堆。它分配了一块整数内存,写入数据然后输出,最后废除此内存块:
#includeint main() {int *p;p=(int *)malloc (sizeof(int));*p=10;printf("%d n",*p);free(p);return 0;}
此代码其实只适用于在C中演示分配、使用和释放内存块的过程。malloc用于分配一块指定大小的内存,本例中是sizeof(int)字节(4字节)。C语言的sizeof命令以字节为单位返回任何类型的大小。代码中完全可以写成malloc(4),因为在大部分机器上sizeof(int)等于4个字节。但是使用sizeof可以大大增强代码的可移植性和可读性。
malloc函数返回一个指向被分配内存块的指针。这是一个通用指针,若不经类型转换即使用一般会导致编译器发出类型警告。类型转换(int *)将malloc返回的通用指针转换为一个“指向整数的指针”,即与p一致。C中的free语句将内存块返还给堆以供重新使用。
第二个例子说明的函数和前一例相同,但是用结构体代替了整数。C代码如下:
#includestruct rec {int i;float f;char c;}; int main() {struct rec *p;p=(struct rec *) malloc (sizeof(struct rec));(*p).i=10; (*p).f=3.14; (*p).c='a'; printf("%d %f %c n",(*p).i,(*p).f,(*p).c); free(p); return 0;}
请注意这行:
(*p).i=10;
很多人不明白为什么不能写成:
*p.i=10;
答案是这和C语言的操作符优先级有关。5+3*4的结果是17,不是32,因为在大多数计算机语言中*比+有更高的优先级。C语言中,操作符.比*有更高的优先级,所以要使用括号保持正确的操作顺序。
但是大部分人觉得总是输入(*p).i太麻烦了,因此C提供了一种简洁记法。下面的两条语句完全等效,而第二条的输入更加简便:
(*p).i=10; p->i=10;
阅读别人代码的时候,您会发现第二种记法比第一种更常用。
全部0条评论
快来发表一下你的评论吧 !