为什么要用指针?
假设您想制作一个文本编辑器——一种用于编辑普通ASCII文本文件的程序,如UNIX上的“vi”或Windows上的“记事本”。文本编辑器是很常用的软件,因为可想而知,它几乎是程序员使用最多的程序了。通过文本编辑器程序员才能和计算机“亲密接触”——您使用它输入并实现自己的创意。对于这么一个使用如此频繁又如此亲近的程序,您自然希望它是完美无缺的。于是许多程序员自己制作文本编辑器并进行定制,以适合个人的工作方式和偏好。
现在您要制作自己的编辑器了。考虑过所需的功能后,您开始思考编辑器使用的“数据结构”,即在内存中如何组织文件以供程序进行操作。您需要的是一种便于对输入信息进行简单快捷操作的存储方式。您确信将字符按行存储是一种可行的方法。根据前面学到的知识,现在可用的只有数组。您想:“一行一般是80个字符,一个文件一般不会超过1,000行。”于是您声明了一个二维数组,像这样:
char doc[1000][80];
此声明要求分配的数组有1,000行,每行80个字符。数组的规模是80,000个字符。
然而,当您对编辑器和它使用的数据结构进行了一些深入思考后,还会认识到下面三点:
- 有些文档的内容是长长的列表。每行很短,却有上千行。
- 有些特殊文本文件有很长的行。比如有的数据文件可能包含长达542个字符的行,每个字符好像是代表DNA片段中的一个氨基酸。
- 大多数现代编辑器都允许同时打开多个文件。
假如您设定最多可以同时打开10个文件,每行最多1,000个字符,每个文件最多50,000行。这时的声明就变成了:
char doc[50000][1000][10];
似乎看起来并不过分,可是您拿出计算器算一下50,000乘1,000乘10 就会发现数组包含了5亿个字符!如今的大多数计算机遇到这么大的数组的都会出问题。它们根本没有足够的RAM甚至虚拟内存空间来容纳这么庞大数组。即使是在最大的多用户系统上,如果多个用户要同时运行三四个这种编辑器程序的话,对系统也会造成严重的负担。
即使计算机可以承受这么大规模的数组,您也能看出这是对存储空间的巨大浪费。如果编辑器声明了一个5亿字符大小的数组,而绝大多数情况下打开的只是百行左右、四五千字节的文件的话,那么这确实是有些不合情理的。使用数组的一个问题是必须在开始就将它的每一维都声明成最大值,而各维最大值的乘积常常是一个非常大的数字。不仅如此,您如果需要编辑一个有2,000个字符的行的文件的话,又只能是无计可施了。其实,事先预计并处理文本文件每行的最大长度是不可能的,因为严格说来这一长度是无限的。
指针正好可以用来解决这个难题。使用指针您能够创建动态数据结构。这时内存将在程序运行的时候从堆上分配,而不用一开始就声明数组的最大规模。这样您就可以为每个文档准确地分配内存而不会产生浪费。而且,关闭一个文档时您还可以把它占用的内存返回给堆,以供程序的其他部分使用。使用指针,内存就可以在程序运行期间不断被回收利用。
顺便说一句,如果您读了上面的讨论后头脑中的一大疑惑是:“到底什么是字节呢?”,那么位和字节的原理这篇文章将有助于您理解相关的概念,包括“兆”、“吉”、“太”等等。请阅读那篇文章后再回来继续学习。