设置数组(记录)长度时,Delphi堆栈溢出和访问冲突错误

时间:2011-03-24 01:57:00

标签: arrays delphi stack-overflow

我正在忙着构建一个应用程序,我正在从两个“记录”文件中读取数据。我有一个非常奇怪的错误,根据我打开文件的顺序弹出(参见下面的代码)。

如果我点击button1后跟按钮2,从而调用“天气数据记录”文件,后跟“参数记录”文件,一切都很好。如果我反过来这样做,我得到一个“堆栈溢出”,然后是“0x7c90e898的访问冲突:写入地址”错误。当我在Button1Click中为数组调用SetLength时会发生这种情况。

天气数据文件有大约550条记录,参数文件大约有45条记录。

任何人都可以看到我的代码有任何明显错误吗?如果有人想用它们进行测试,我不知道如何附加文件或使文件可用...

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, Buttons, ExtCtrls, Grids,FileCtrl,Contnrs;

type  
    TWeatherData = record  
    MyDate : TDate;  
    Rainfall : Double;  
    Temperature : Double;  

  end;

  TParameters = record
    Species : string[50];
    ParameterName: string[50];
    ParameterValue : double;
  end;

  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);

  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
Var
  WeatherDataFile : file of TWeatherData;
  j : integer;
  WeatherDataArray : array of TWeatherData;
  MyFileSize : Integer;

begin


  AssignFile(WeatherDataFile,'C:\Test5.cmbwthr') ;
  Reset(WeatherDataFile);
  MyFileSize := FileSize(WeatherDataFile);

  SetLength(WeatherDataArray,MyFileSize);

  j := 0;

  try
   while not Eof(WeatherDataFile) do begin
    j := j + 1;
    Read (WeatherDataFile, WeatherDataArray[j]) ;
   end;
  finally
   CloseFile(WeatherDataFile) ;
  end;
end;

procedure TForm1.Button2Click(Sender: TObject);
var
  ParametersFile : file of TParameters;
  j : integer;
  CurrentParameters : array of TParameters;
  MyFileSize : Integer;

begin
  AssignFile(ParametersFile,'C:\Test5.cmbpara') ;
  Reset(ParametersFile);

  Reset(ParametersFile);
  MyFileSize := FileSize(ParametersFile);

  SetLength(CurrentParameters,MyFileSize);

  j := 0;

  try
   while not Eof(ParametersFile) do begin
    j := j + 1;
    Read (ParametersFile, CurrentParameters[j]) ;
   end;
  finally
   CloseFile(ParametersFile) ;
  end;
end;

end. 

3 个答案:

答案 0 :(得分:8)

您通过在写入数组之前递增索引而不是之后写入数组的末尾。由于您正在写入不属于该阵列的内存,因此可能会出现任何问题。

AssignFile(ParametersFile, 'C:\Test5.cmbpara');
Reset(ParametersFile);
try // Enter "try" block as soon as the file is opened.
  MyFileSize := FileSize(ParametersFile);
  SetLength(CurrentParameters, MyFileSize);

  j := 0;
  while not Eof(ParametersFile) do begin
    Read(ParametersFile, CurrentParameters[j]);
    Inc(j);
  end;
finally
  CloseFile(ParametersFile);
end;

if j <> MyFileSize then
  raise Exception.CreateFmt('Parameter count mismatch: expected %d but got %d instead.',
    [MyFileSize, j]);

答案 1 :(得分:0)

您需要打包记录才能保存到文件中。

type  
  TWeatherData = packed record  
    MyDate : TDate;  
    Rainfall : Double;  
    Temperature : Double;  
  end;

  TParameters = packed record
    Species : string[50];
    ParameterName: string[50];
    ParameterValue : double;
  end;

答案 2 :(得分:0)

查看我们的SynCommons.pas单元中提供的TDynArray包装器。包含序列化功能。

你可以将常规字符串放在记录中,而不是shorttring:它将在磁盘上使用更少的空间,并且自Delphi 2009起将成为Unicode Ready。

type  
  TWeatherData = record  
    MyDate : TDate;  
    Rainfall : Double;  
    Temperature : Double;  
  end;
  TWeatherDatas = array of TWeatherData;

  TParameter = record
    Species : string;
    ParameterName: string;
    ParameterValue : double;
  end;
  TParameters = array of TParameter;

var
  Stream: TMemoryStream;
  Params: TParameters;
  Weather: TWeatherDatas;
begin
  Stream := TMemoryStream.Create;
  try
    Stream.LoadFromFile('C:\Test5.cmbpara');
    DynArray(TypeInfo(TParameters),Params).LoadFromStream(Stream));
    Stream.LoadFromFile('C:\Test5.cmbwthr');
    DynArray(TypeInfo(TWeatherDatas),Weather).LoadFromStream(Stream));
  finally
    Stream.Free;
  end;
end;

使用TDynArray,您可以使用TList访问任何动态数组 - 例如属性和方法,例如Count, Add, Insert, Delete, Clear, IndexOf, Find, Sort和一些新方法(如LoadFromStream, SaveToStream, LoadFromSaveTo允许快速二进制序列化任何动态数组,甚至包含字符串或记录 - CreateOrderedIndex方法也可用于创建个人索引根据动态数组内容。如果愿意,您还可以将数组内容序列化为JSON。

Delphi 6 up to XE