为何我的程序在递归调用子程序时会出现栈溢出错误?
调用子程序是需要分配一定的内存空间用以存放参数、函数返回值和局部变量等数据的。Pascal提供了一个全局静态的栈结构的内存段用以存放这些数据,每次调用子程序都会把所需的数据压入栈中,子程序结束后就把数据从栈中取回。由于栈的大小是在编译时设定的,不能在运行时再更改大小,因此当栈没有足够的剩余空间来存放调用子程序所需的数据时,就会出现栈溢出错误。
你可以通过参数编译指示$M来设置栈的大小,根据程序的需要来设置栈的大小是很重要的,因为栈太小则容易出现栈溢出错误,太大又会浪费内存。注意Borland/Turbo Pascal编译器是16位的编译器,你最多只能设置65520字节的栈空间。Free Pascal编译器是32位的,因此基本上没有限制。虽然也可以通过底层的方法来构造一个动态分配的栈空间,但方法比较复杂,不适合在信息学奥林匹克中使用。另外,栈大小设置在Linux下将会被忽略。
为何当我声明的全局变量的总尺寸超过64KB时会出现编译错误?
在Pascal中,一个主程序及其所有单元(包括System单元)的全局静态数据(包括全局变量、全局和局部类型常数、PChar常量和对象类型的虚拟方法表等)都被存放在一个单独的全局静态的数据段中。由于Borland/Turbo Pascal编译器是16位的编译器,这个数据段的大小不能超过64KB,否则将无法编译。解决的方法是尽可能少用全局静态变量,把一些比较大的全局静态数据改用动态方式存储,以减少全局静态空间的需求。
为何我不能定义大小超过64KB的数据类型和变量?
由于Borland/Turbo Pascal编译器是16位的编译器,它要求每个单独的数据类型和变量的大小都不能超过64KB,否则将无法编译。解决的方法是把数据分拆,并用动态方式存储分拆后的数据。例如,对于一个很大的一维数组,你可以把它拆为二维数组,然后用动态方式存储第二维数据。下面是一些简单的样例:
分拆前的数据类型 |
|
分拆后的数据类型 |
type TQueue = array[0..249999] of Byte; |
-> |
type TList = array[0..9999] of Byte; TQueue = array[0..24] of ^TList; |
type TRecord = record A, B, C: array[0..9999] of Longint; end; |
-> |
type TList = array[0..9999] of Longint; TRecord = record A, B, C: ^TList; end; |
我的程序可以申请多大的动态内存空间?
在Borland/Turbo Pascal中,如果你以DOS实模式编译程序,那么你的程序可以申请的最大动态内存空间为当前DOS常规内存剩余量和编译指示$M设置的最大堆空间这两个数的最小值,如果你以保护模式编译程序,那么的你的程序可以申请的最大动态内存空间就是扩充内存的剩余量。在Free Pascal中,要视具体环境的设置而定。注意,在很多时候,你的程序实际上并不能使用到理论上可用的最大内存空间,因为由不完全的内存释放操作产生的大量剩余内存碎片会由于每块碎片过小而无法利用。不过在信息学奥林匹克中很少会出现这种情况,因为在比赛中一般不会出现不完全的内存释放操作,许多程序甚至是不会关心内存的释放问题。
由于Borland/Turbo Pascal编译器是16位的编译器,因此它限定每次申请的内存空间的最大值为65528字节。注意,申请大小在65529至65535之间的内存空间是不安全的。