2.2 存储分配

2.2 存储分配

当在C中声明一个指针时,与声明其它类型的变量类似,一定量的存储空间会分配给这个指针。通常情况下指针会占用一个机器字长的存储空间,但有些时候它们的大小也有所不同。因此,为了保证代码的可移植性,我们不应该假设每个指针都占有一个特定大小的存储空间。指针变量的大小通常与编译器的设定以及某些特定的C实现中的类型界定符有关。必须要记住的一点是:当我们声明了一个指针,仅仅只是为指针本身分配了空间,并没有为指针所引用的数据分配空间。而为数据分配存储空间有两种方法:一种是直接定义一个变量;另一种是在运行时动态的分配存储空间(例如:使用mallocrealloc)。 

当我们声明一个变量时,编译器会根据变量的类型预留足够的内存空间。变量的存储空间是系统自动分配的,但此存储空间不会在程序的整个生命周期中永久存在,这一点在处理指针类型的变量时尤为重要。自动分配存储变量是一种在进入或离开一个模块或函数时其存储空间能够自动的分配和释放的变量。例如:在函数f中,iptr被赋值为变量a的地址,当函数f返回时,iptr变成了一个悬空指针。为什么会这样?因为当函数f返回时,变量a已经从函数堆栈中弹出,变成了一个不合法的变量(见第3章)。

int f(int **iptr) 
{
    int a = 10;
    *iptr = &a;

    return 0;
}

在C语言中,当想要动态分配存储空间时,我们会得到一个指向一个堆存储空间的指针(见第3章)。此存储空间由我们自行管理,并且会一直存在,除非我们明确的将它释放。例如:下面这段代码用malloc分配的存储空间会一直有效直到我们调用函数free来释放它。所以,当函数g返回时此存储空间仍然有效(见图2.2),这一点与之前我们自动分配存储空间的变量完全不同。参数iptr是一个指向我们想要改变其内容的对象的指针(此对象也是一个指针),所以当g返回时,iptr指向了由malloc申请的地址空间。我们会在“作为函数参数的指针”部分进一步探讨这个问题。

#include <stdlib.h>

int g(int **iptr) 
{
    if ((*iptr = (int *)malloc(sizeof(int))) == NULL)
        return -1;

    return 0;
}

 

图2.2 函数中返回动态分配的存储空间的操作

有些时候,我们甚至会认为指针和动态存储空间分配是C语言领域中不太好的特性。特别是当生产了由动态内存分配所造成的内存泄漏问题时。内存泄漏问题的产生是由于动态分配了内存空间,但从未释放它(甚至在程序不再使用此数据空间时都不去释放它)造成的。特别是在执行重复性代码时,这种泄漏问题会表现的尤为严重。好在我们可以采用统一的内存管理方法来大大减少此类问题。 

一种统一的内存管理例子就是本书中所用到的数据结构实例。每种实例所遵循的理念是,由用户来管理存储空间以及与存储空间相关的实际的数据结构,而数据结构自身只用于维护数据内部变量的存储空间分配。所以在数据结构中,只使用指针所指向数据变量,而不是此数据的自身副本。这种应用的一个重要意义在于,一个数据结构的实现并不依赖于它所存储的数据的类型和大小。同时,一个复杂的数据结构能够以一个单一的数据形态表现,这个特性在生产大量数据时非常有用。

此外,本书还提供了如何初始化和销毁数据结构的操作。初始化可能会涉及很多步骤,其中之一便是内存分配。销毁数据结构通常包括删除它所有的数据,并释放数据结构所用到的内存。释放数据结构的内存往往也包含释放与数据结构本身相关联的所有内存。这里有一个例外,那就是让用户自己去管理数据的存储。因为每个数据结构在初始化的时候都需要使用由用户提供的初始化函数,因此数据存储的管理实际上是一种与具体应用相关的操作。

 

PS:

1、此书(Mastering Algorithms with C)译稿版权归本人(Love_Lei)及好友(bigship)共同所有,未经本人同意谢绝一切转载,并不得抄袭,模仿,盗版!更请大家监督盗版之人!

2、由于本人水平有限,如对译文有任何建议和异议,欢迎大家留言指正,我们共同讨论学习!谢谢!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值