malloc()函数
C可以在程序运行时分配更多的内存,主要通过malloc()
函数,该函数接受一个参数:所需的内存字节数。
malloc()
函数会找到合适的空闲内存块,这样的内存是匿名的。也就是说,malloc()
分配内存,但是不会为其赋名。然而,它确实返回动态分配内存块的首字节地址。因此,可以把该地址赋给一个指针变量,并使用指针访问这块内存。因为char
表示1字节,malloc()
的返回类型通常被定义为指向char
的指针。
然而,从ANSI C标准开始,C使用一个新的类型:指向void
的指针。该类型相当于一个“通用指针”。
malloc()
函数可用于返回指向数组的指针、指向结构的指针等,所以通常该函数的返回值会被强制转换为匹配的类型。
如果malloc()
分配内存失败,将返回空指针。
我们试着用malloc()
创建一个数组。除了用malloc()
在程序运行时请求一块内存,还需要一个指针记录这块内存的位置。例如,考虑下面的代码:
double * ptd;
ptd = (double *) malloc(30 * sizeof(double));
注意,指针ptd
被声明为指向一个double
类型,而不是指向内含30个double
类型值的块。回忆一下,数组名是该数组首元素的地址。因此,如果让ptd
指向这个块的首元素,便可像使用数组名一样使用它。也就是说,可以使用表达式ptd[0]
访问该块的首元素,ptd[1]
访问第2个元素,以此类推。
现在,我们有3种创建数组的方法:
- 声明数组时,用常量表达式表示数组的维度,用数组名访问数组的元素。可以用静态内存或自动内存创建这种数组。
- 声明变长数组(C99新增的特性)时,用变量表达式表示数组的维度,用数组名访问数组的元素。具有这种特性的数组只能在自动内存中创建。
- 声明一个指针,调用malloc(),将其返回值赋给指针,使用指针访问数组的元素。该指针可以是静态的或自动的。
使用第2种和第3种方法可以创建动态数组(dynamic array))。这种数组和普通数组不同,可以在程序运行时选择数组的大小和分配内存。
在C99之前,不能这样做:
double item[n]; /* C99之前:n不允许是变量 */
但是,可以这样做,这比变长数组更灵活。
ptd = (double *) malloc(n * sizeof(double)); /* 可以 */
free()函数
通常,malloc()
要与free()
配套使用。
free()
函数的参数是之前malloc()
返回的地址,该函数释放之前malloc()
分配的内存。因此,动态分配内存的存储期从调用malloc()
分配内存到调用free()
释放内存为止。
设想malloc()
和free()
管理着一个内存池。每次调用malloc()
分配内存给程序使用,每次调用free()
把内存归还内存池中,这样便可重复使用这些内存。
不能用free()
释放通过其他方式(如,声明一个数组)分配的内存。
malloc()
和free()
的原型都在stdlib.h
头文件中。
free
不能释放同一块内存两次。
下面是malloc
的使用例子:
/* dyn_arr.c -- 动态分配数组 */
#include <stdio.h>
#include <stdlib.h> /* 为 malloc()、free()提供原型 */
int main(void)
{
double * ptd;
int max;
int number;
int i = 0;
puts("What is the maximum number of type double entries?");
if (scanf("%d", &max) != 1) {
puts("Number not correctly entered -- bye.");
exit(EXIT_FAILURE);
}
ptd = (double *) malloc(max * sizeof(double));
if (ptd == NULL) {
puts("Memory allocation failed. Goodbye.");
exit(EXIT_FAILURE);
}
/* ptd 现在指向有max个元素的数组 */
puts("Enter the values (q to quit):");
while (i < max && scanf("%lf", &ptd[i]) == 1){
++i;
}
printf("Here are your %d entries:\n", number = i);
for (i = 0; i < number; i++) {
printf("%7.2f ", ptd[i]);
if (i % 7 == 6)
putchar('\n');
}
if (i % 7 != 0)
putchar('\n');
puts("Done.");
free(ptd);
return 0;
}
输出结果如下:
注意,
free()
函数位于程序的末尾,它释放了malloc()
函数分配的内存。free()
函数只释放其参数指向的内存块。一些操作系统在程序结束时会自动释放动态分配的内存,但是有些系统不会。为保险起见,请使用free()
,不要依赖操作系统来清理。在函数末尾处调用
free()
可避免内存泄露的问题发生。
calloc()函数
分配内存还可以使用calloc()
,典型的用法如下:
long * newmem;
newmem = (long *)calloc(100, sizeof (long));
和malloc()
类似,在ANSI之前,calloc()
也返回指向char
的指针;在ANSI之后,返回指向void
的指针。如果要存储不同的类型,应使用强制类型转换运算符。
calloc()
函数接受两个无符号整数作为参数(ANSI规定是size_t
类型)。第1个参数是所需的存储单元数量,第2个参数是存储单元的大小(以字节为单位)。在该例中,long
为4字节,所以,前面的代码创建了100个4字节的存储单元,总共400字节。
calloc()
函数还有一个特性:它把块中的所有位都设置为0(注意,在某些硬件系统中,不是把所有位都设置为0来表示浮点值0)。
free()
函数也可用于释放calloc()
分配的内存。
存储类别和动态内存分配
存储类别和动态内存分配有何联系?我们来看一个理想化模型。可以认为程序把它可用的内存分为 3部分:一部分供具有外部链接、内部链接和无链接的静态变量使用;一部分供自动变量使用;一部分供动态内存分配。
静态存储类别所用的内存数量在编译时确定,只要程序还在运行,就可访问存储在该部分的数据。该类别的变量在程序开始执行时被创建,在程序结束时被销毁。
然而,自动存储类别的变量在程序进入变量定义所在块时存在,在程序离开块时消失。因此,随着程序调用函数和函数结束,自动变量所用的内存数量也相应地增加和减少。这部分的内存通常作为栈来处理,这意味着新创建的变量按顺序加入内存,然后以相反的顺序销毁。
动态分配的内存在调用malloc()
或相关函数时存在,在调用free()
后释放。这部分的内存由程序员管理,而不是一套规则。所以内存块可以在一个函数中创建,在另一个函数中销毁。正是因为这样,这部分的内存用于动态内存分配会支离破碎。也就是说,未使用的内存块分散在已使用的内存块之间。另外,使用动态内存通常比使用栈内存慢。
总而言之,程序把静态对象、自动对象和动态分配的对象存储在不同的区域。
标签:malloc,函数,ptd,free,分配内存,内存,数组 From: https://www.cnblogs.com/wwjj4811/p/16647905.html