C语言之指针的基础与存储空间的分配-诺禾

1.指针基础
泛型指针与类型转换泛型指针和类型转换是用来跨越和覆盖C语言的类型系统的途径。泛型指针指向某一数据而不需要理会数据的具体类型。类型转换允许临时地改变数据的类型。函数指针指针指向可执行代码段或指向调用可执行代码段的信息块,而不是指向某种具体数据。它们把函数当做一小段数据来存储和管理。

C语言之指针的基础与存储空间的分配
Figure 2.1. An illustration of some operations with pointers

对于其他类型的任何变量,除非我们显式地指定过,否则我们都不应该假设它指向一个有效的地址。同样需要记住的是,在C语言中,我们无法改变的一个事实就是指针能够指向一个无效的地址。指向无效地址的指针有时被称为悬空指针。可能产生悬空指针的一些编程错误示例包括:将任意的整型变量强制转换为指针变量;操作超出数组边界的指针;释放一个或多个仍被引用的指针。

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

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

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;
}
C语言之指针的基础与存储空间的分配
Figure 2.2. Pointer operations in returning storage dynamically allocated in a function

有些时候,我们甚至会认为指针和动态存储空间分配是C语言领域中不太好的特性。特别是当生产了由动态内存分配所造成的内存泄漏问题时。内存泄漏问题的产生是由于动态分配了内存空间,但从未释放它(甚至在程序不再使用此数据空间时都不释放它)造成的。

特别是在重复执行代码时,这种泄漏问题会表现得尤为严重。好在我们可以采用统一的内存管理方法来大大减少此类问题。一种统一的内存管理方法例子就是本书中所用到的数据结构实例。 每种实例所遵循的理念是,由用户来管理存储空间以及与存储空间相关的实际的数据结构,而数据结构自身只用于维护数据内部变量的存储空间分配。所以,在数据结构中,只使用指针所指向数据变量,而不是此数据的私有副本。这种应用的一个重要意义在于,一个数据结构的实现并不依赖于它所存储的数据的类型和大小。同时,多个数据结构能够以单个数据形态表现,这个特性在组织大量数据时非常有用。

有些时候,我们甚至会认为指针和动态存储空间分配是C语言领域中不太好的特性。特别是当生产了由动态内存分配所造成的内存泄漏问题时。内存泄漏问题的产生是由于动态分配了内存空间,但从未释放它(甚至在程序不再使用此数据空间时都不释放它)造成的。特别是在重复执行代码时,这种泄漏问题会表现得尤为严重。好在我们可以采用统一的内存管理方法来大大减少此类问题。一种统一的内存管理方法例子就是本书中所用到的数据结构实例。每种实例所遵循的理念是,由用户来管理存储空间以及与存储空间相关的实际的数据结构,而数据结构自身只用于维护数据内部变量的存储空间分配。所以,在数据结构中,只使用指针所指向数据变量,而不是此数据的私有副本。这种应用的一个重要意义在于,一个数据结构的实现并不依赖于它所存储的数据的类型和大小。同时,多个数据结构能够以单个数据形态表现,这个特性在组织大量数据时非常有用。

猜你喜欢

转载自blog.csdn.net/yyone123/article/details/107822115