内存分配(malloc()和free())

C语言的一个特性是接近底层,对于硬件的控制能力比其他高级动态语言要强。同时,C语言赋予程序员更大的自由度,更信任程序员。在内存的分配与释放上,我们知道非静态变量(块作用域,无链接,自动生存期)在程序进入到变量定义所在的地方(块或函数内)时分配内存,在离开块作用域时释放。对于静态变量,在程序加载到内存时,变量的内存分配到静态存储区,且直到程序运行结束(终止)时释放。这些都是程序执行过程中由程序自动控制的。
同时,C提供给程序员更大的权限,可以手动控制变量的内存分配和释放,相关的函数为malloc(),calloc()和free()。

手动分配内存malloc()和calloc()

malloc():函数原型:void malloc(size_t size),参数为要分配的内存字节数,返回值为指向void的指针,pointer-to-void,一般返回该段内存空间的首个字节。我们可以使用类型转化将分配的内存起始地址复制给一个指针变量,这样我们就可以操作这段内存空间内的数据,并在必要时候释放该段内存空间。
double
ptd;
ptd = (double ) malloc(30 sizeof(double));
我们首先声明一个指向double类型的指针变量ptd,然后使用malloc申请包含30个double类型的一段内存空间,并将其内存空间的起始地址赋值给ptd。我们甚至可以用变量n替换30这个常量,这样相当于我们可以动态创建一个可变数组,类似VLA。若malloc分配内存失败,则返回空指针NULL。


calloc()和malloc类似,函数原型为:void *calloc(size_t nitems, size_t size)。它有两个参数,第一个为要申请的内存单元数,第二个为每个内存单元的字节数。

使用free() 释放内存

一般使用malloc分配可一段内存空间后,需要在必要的时候手动释放掉,以防止内存泄露。free()和malloc()配合使用。
示例:

/* dyn_arr.c -- dynamically allocated array */
#include<stdio.h>
#include<stdlib.h> /* for malloc(), free()  */

int main(void)
{
    double * ptd;
    int max = 0;
    int number = 0;
    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 now points to an array of max elements */
    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;
}

输出:
What is the maximum number of type double entries?
5
Enter the values (q to quit):
20 30 35 25 40 80
Here are your 5 entries:
20.00 30.00 35.00 25.00 40.00
Done.

虽然我们输入了6个integer类型的数据,但实际输出只有5个,因为我们申请的这段内存空间为包含5个integer类型的数组。

free()的重要性

若使用malloc或calloc手动分配内存,且没有使用free释放掉该段内存,某些操作系统会自动释放掉这段内存,但不是所有的操作系统都支持这种特性。所以,不要依靠操作系统,而是要手动释放掉这段内存。
原因:来看下面这段代码:

int main()
{
    double glad[2000];
    int i;
    for (i = 0; i < 1000; i++)
        gobble(glad, 2000);
}

void gobble(double ar[], int n)
{
    double * temp = (double *) malloc(n * sizeof(double));
    /* free(temp);   // forgot to use free()   */
}

main函数每次调用gobble时,都会使用malloc手动申请2000个doube类型的内存空间,假设每个double类型占用8个字节(bytes)。那么执行到malloc处时,总共会申请16000字节的空间,而我们没有调用free函数手动释放掉这段内存空间,当该函数执行完毕时,指向这16000个字节空间的指针变量temp(块作用域,无链接,自动生存期)将会消失,但这16000个字节的内存空间仍然存在,且程序无法通过任何变量或方式访问该内存空间。
第二次调用gobble时,仍然会出现这种情况,直到for循环结束时,我们总共手动申请了1000 * 2000 * 8 = 16000000字节的内存空间,很有可能没到这么多内存时,内存已经消耗完毕。这种情况,我们称为内存泄漏。所以,我们要时刻记得使用free释放掉malloc手动分配的内存空间。

猜你喜欢

转载自www.cnblogs.com/jeffrey-yang/p/10263291.html