【问题标题】:Dynamic array in Turbo PascalTurbo Pascal 中的动态数组
【发布时间】:2017-02-28 21:27:08
【问题描述】:

我正在做我的学校项目,我想使用动态(非静态)数组。我使用过 ObjectPascal,所以我习惯了一些语法。但现在我正在使用旧的 TurboPascal 编程(我在 Windows 上使用 Turbo Pascal 7)。

它似乎不知道 ObjectPascal,所以我想,你 Turbo Pascal 不知道动态数组。

谁能告诉我,我的理论是否正确?我试图谷歌,但我没有成功。 基本上我在问“Turbo Pascal 7 中的动态数组怎么样”? 谢谢大家的反应。

【问题讨论】:

  • 可以用指针实现“动态数组”。谷歌为它。
  • TP7 没有像 Delphi 中的 ObjectPascal 那样的动态数组。但是,当时的一个技巧是将数组声明为整数数组 [0..0],然后使用 GetMem 为您喜欢的任何大小的数组分配空间并通过指针访问它。这可能是@darkl 的想法。
  • 是的,我找到了带有指针的动态数组,但我一点也不喜欢它,我一直在寻找更“优雅”的方法。感谢您的快速帮助。
  • 需要使用TP7吗?
  • @MartynA 不确定他们为什么不使用 Free Pascal。还是 FPC 许可限制了教育用途?

标签: pascal dynamic-arrays delphi turbo-pascal


【解决方案1】:

正如 MartynA 所说,Turbo Pascal 中没有动态数组类型。您需要使用指针手动分配内存,使用范围检查时要小心。

通常你定义一个数组类型

TYPE
  TArrayT = array[0.. ((65535-spillbytes) div sizeof(T))-1] of T;

其中spillbytes 是一个用于小量扣除的常量,因为您不能使用整个64k,请查看编译器接受的内容。 (可能这个推论是针对 64k 块内的 heapmanager 结构)

然后你定义一个指针

  PArrayT= ^TArrayT;

还有一个变量

  var 
     P : PArrayT;
      

然后您使用 getmem 分配 nreelement 元素;

 getmem(P,SizeOf(T) * nrelements);

并可选地用零填充它们以初始化它们:

 fillchar(p^,SizeOf(T) * nrelements,#0);

您可以使用访问元素

 p^[index]

要释放它们,请使用与 getmem 行完全相反的 freemem。

 freemem(P,Sizeof(T)*nrelements);

这意味着您必须将分配的元素数量保存在某处。这已在 Delphi 和 FPC 中修复/解决。

另外请记住,您无法再通过范围检查找到错误。

如果您想要大于 64k 的数组,这是可能的,但仅限于限制,并且更重要的是确切的 TP 目标(dos、dos-protected 或您使用的 Windows)我建议您搜索在线 SWAG 存档有很多例子。当然,我也建议你去 FreePascal/Lazarus,在那里你可以简单地做:

 var x : array of t;
 begin
    setlength(x,1000000);

不用额外的代码就可以完成它,忘记所有这些废话。

【讨论】:

  • TP7 有对象,因此动态数组类型(对于一种类型)可以包装在对象中。这就是我会做的。隐藏所有丑陋的细节,使它们很好用。该对象可以具有访问方法,例如function Get(Index): Integerprocedure Put(Index, Value: Integer);等。初始长度可以在构造函数中设置:constructor Init(Len: Integer);等。
  • 可以将 TP tcollection(它更像 Delphi TList 而不是 Delphi TCollection)并将其更改为整数。但无论哪种方式都是对严重过时的代码的投资,最好转移到动态数组甚至在 16 位 dos 应用程序中工作的 FPC。不过,我不想完全消极,所以这就是为什么要写这篇文章。但是信息应该很清楚,如果您要进行以数据为中心的编码,请不要投资 TP。
  • 我同意 FPC 是更好的选择。
【解决方案2】:

我正在使用 Turbo Pascal 5.5 并创建一个动态数组,也许诀窍是声明一个零维数组,如下所示:

dArray = array [0..0] of integer;

然后声明一个指向该数组的指针:

pArray = ^dArray ;

最后,创建一个指针变量:

ArrayPtr : pArray;

您现在可以引用指针变量ArrayPtr,如下所示:

ArrayPtr^[i]; { The index 'i' is of type integer}

请参阅下面的完整示例:

{
  Title: dynarr.pas

  A simple Pascal program demonstrating dynamic array.

  Compiled and tested with Turbo Pascal 5.5.
}

program dynamic_array;


{Main Program starts here}
type
  dArray = array [0..0] of integer;
  pArray = ^dArray ;
var
  i : integer;
  ArrayPtr : pArray;
begin

  for i := 0 to 9 do { In this case, array index starts at 0 instead of 1. }
    ArrayPtr^[i] := i + 1;

  writeln('The Dynamic Array now contains the following:');
  writeln;

  for i := 0 to 9 do
    writeln(ArrayPtr^[i]);

end.

在本例中,我们将数组声明为:

array[0..0] of integer;

因此,索引从 0 开始,如果我们有 n 个元素,则最后一个元素位于索引 n-1,这类似于 C/C++ 中的数组索引。

常规 Pascal 数组从 1 开始,但在本例中,它从 0 开始。

【讨论】:

  • 我不得不尝试一下——拿出 TP7、DOSBox,输入代码,编译并运行。仅供参考,只要 start 和 end 相同,dArray 可以是任何范围,[1..1](帮助 Pascal 人保持它基于 1,当然更新你的 for 循环)。
【解决方案3】:
unit Vector;

interface

const MaxVector = 8000;
  // 64 k div SizeOf(float); number of float-values that fit in 64 K of stack
  VectorError: boolean = False;
// toggle if error occurs. Calling routine can handle or abort


type
  VectorStruc = record
    Length: word;
    Data: array [1..MaxVector] of float;
  end;
  VectorTyp = ^VectorStruc;

procedure CreateVector(var Vec: VectorTyp; Length: word; Value: float);
{ Generates a vector of length Length and sets all elements to Value }

procedure DestroyVector(var Vec: VectorTyp);
{ release memory occupied by vector }

procedure SetVectorElement(var Vec: VectorTyp; n: word; c: float);

function GetVectorElement(const Vec: VectorTyp; n: word): float;

implementation

var ch: char;

function WriteErrorMessage(Text: string): char;

begin
  Write(Text);
  Read(WriteErrorMessage);
  VectorError := True;         // toggle the error marker
end;

procedure CreateVector(var Vec: VectorTyp; Length: word; Value: float);

var
  i: word;

begin
  try
    GetMem(Vec, Length * SizeOf(float) + SizeOf(word) + 6);
  except
    ch := WriteErrorMessage(' Not enough memory to create vector');
    exit;
  end;
  Vec^.Length := Length;
  for i := 1 to Length do
    Vec^.Data[i] := Value;
end;

procedure DestroyVector(var Vec: VectorTyp);

var
  x: word;

begin
  x := Vec^.Length * SizeOf(float) + SizeOf(word) + 6;
  FreeMem(Vec, x);
end;

function VectorLength(const Vec: VectorTyp): word;

begin
  VectorLength := Vec^.Length;
end;

function GetVectorElement(const Vec: VectorTyp; n: word): float;

var
  s1, s2: string;

begin
  if (n <= VectorLength(Vec))  then
    GetVectorElement := Vec^.Data[n]
  else
  begin
    Str(n: 4, s1);
    Str(VectorLength(Vec): 4, s2);
    ch := WriteErrorMessage(' Attempt to read non-existent vector element No ' +
      s1 + ' of ' + s2);
  end;
end;


procedure SetVectorElement(var Vec: VectorTyp; n: word; C: float);

begin
  if (n <= VectorLength(Vec))  then
    Vec^.Data[n] := C
  else
    ch := WriteErrorMessage(' Attempt to write to non-existent vector element');
end;

end.  

只要您的数据适合堆栈,即小于 64 kB,任务就相对简单。我唯一不知道的是 6 位额外大小的去向,但是它们是必需的。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-03-29
    相关资源
    最近更新 更多