小弟本意是想通过解析单元文件生成工程的引用结构图
在使用Move方法复制数据时经常出现不稳定的错误,时有时无!
Access violation at address 00402CEB in module 'Project1.exe'. Read of address 01830000
多运行几次测试代码就会报上述错。代码如下:
function TCodeFileModel.Append(AFileName: PChar): PCodeFile;
var
pItem: PCodeFile;
begin
New(pItem);
FillChar(pItem^, Sizeof(TCodeFile), #0);
// Move(AFileName^, pItem^, MaxFileLength);
Move(AFileName^, pItem.Name, MaxFileLength);
// .... 其他代码
end;
使用下面的TCodeFile 和 TCodeFileLink 记录生成单元引用关系
PCodeFileLink = ^TCodeFileLink;
PCodeFile = ^TCodeFile;
// 单元文件信息记录
TCodeFile = record
Name: array[0..MaxFileLength] of char; // 单元名称
Kind: TCodeFileKind; //类型
Contain: PCodeFileLink; //所引用到的单元链
Next: PCodeFile;
Prev: PCodeFile;
end; //单元链记录
TCodeFileLink = record
CodeFile: PCodeFile;
Next: PCodeFileLink;
end;下面是完整单元代码和测试代码
--------------------------------------------------------------------------------------// 测试代码
procedure TForm2.btn3Click(Sender: TObject);
var
i: Integer;
j: Integer;
pItem: PCodeFile;
begin
if FileMap <> nil then
FileMap.Free;
FileMap := TCodeFileModel.Create; // 多运行几次这里的测试代码就会出现错误
AddMsg('开始增加1000个');
btn3.Enabled := False;
try
for i := 1 to 1000 do
begin
try
pItem := FileMap.Append(Pchar('Test' + IntToStr(i)));
for j := 1 to 100 do
FileMap.AddLink(pItem, Pchar(IntToStr(i) + ' - Child - ' + IntToStr(j)));
except
on E: Exception do
AddMsg(e.Message);
end;
end;
finally
btn3.Enabled := True;
AddMsg('增加1000个结束');
end;
end;
procedure TForm2.AddMsg(const AValue: string);
begin
mmo1.Lines.Add(AValue);
end;unit uUnitMap;interfaceconst
MaxFileLength = 60;
type
// 搜索范围内, 搜索范围外, 工程
TCodeFileKind = (cfExternal, cfInternal, cfProject); PCodeFileLink = ^TCodeFileLink;
PCodeFile = ^TCodeFile; TCodeFile = record
Name: array[0..MaxFileLength] of char;
Kind: TCodeFileKind;
Contain: PCodeFileLink;
Next: PCodeFile;
Prev: PCodeFile;
end;
TCodeFileLink = record
CodeFile: PCodeFile;
Next: PCodeFileLink; // 使用单链就可以,
//Prev: PCodeFileLink;
end; TCodeFileModel = class
public
FirstItem: PCodeFile;
LastItem: PCodeFile;
CurrentItem: PCodeFile;
Count: integer; function Append(AFileName: PChar): PCodeFile;
function Find(AFileName: PChar): PCodeFile;
function Locate(AFileName: PChar): Boolean;
function FindLink(AParent, AChild: PCodeFile): Boolean;
procedure Link(AParent, AChild: PCodeFile);
procedure AddLink(AParent: PCodeFile; AFileName: PChar); public
constructor Create;
destructor Destroy; override;
procedure Clear;
end;
implementationuses SysUtils;constructor TCodeFileModel.Create;
begin
inherited;
clear;
end;destructor TCodeFileModel.Destroy;
begin
Clear;
inherited;
end;function TCodeFileModel.Locate(AFileName: PChar): Boolean;
var
pItem: PCodeFile;
begin
pItem := Find(AFileName);
Result := pItem <> nil;
if Result then
CurrentItem := pItem;
end;function TCodeFileModel.FindLink(AParent, AChild: PCodeFile): Boolean;
var
pIncItem: PCodeFileLink;
begin
Result := False;
pIncItem := AParent.Contain;
while pIncItem <> nil do
begin
Result := pIncItem.CodeFile = AChild;
if Result then
Break;
pIncItem := pIncItem.Next;
end;
end;function TCodeFileModel.Append(AFileName: PChar): PCodeFile;
var
pItem: PCodeFile;
begin
try
New(pItem);
FillChar(pItem^, Sizeof(TCodeFile), #0);
// 下面Move会出现错误,不稳定(错误时有时无)
// Move(AFileName^, pItem^, MaxFileLength);
Move(AFileName^, pItem.Name, MaxFileLength); pItem.Prev := LastItem;
if LastItem <> nil then
LastItem.Next := pItem
else
begin
FirstItem := pItem;
LastItem := pItem;
end;
LastItem := pItem; inc(Count);
Result := pItem;
except
// raise Exception.Create('Append(AFileName: PChar): PCodeFile');
on E: Exception do
raise Exception.Create('Err: Add ' + AFileName + ' Count:' + IntToStr(Count) +
#13#10'Error Code'#13#10 + E.Message + #13#10 +
'Address:' + IntToStr(integer(@pItem)));
end;end;procedure TCodeFileModel.Clear;
var
pLink: PCodeFileLink;
begin
while FirstItem <> nil do
begin
CurrentItem := FirstItem;
FirstItem := FirstItem.Next; while CurrentItem.Contain <> nil do
begin
pLink := CurrentItem.Contain;
CurrentItem.Contain := pLink.Next;
Dispose(pLink);
end;
Dispose(CurrentItem);
end; FirstItem := nil;
LastItem := nil;
CurrentItem := nil;
Count := 0;
end;procedure TCodeFileModel.Link(AParent, AChild: PCodeFile);
var
pLink: PCodeFileLink;
begin
try
New(pLink);
FillChar(pLink^, SizeOf(PCodeFileLink), #0);
pLink^.CodeFile := AChild; pLink.Next := AParent.Contain;
if AParent.Contain <> nil then
AParent.Contain := pLink;
except
raise Exception.Create('Link(AParent, AChild: PCodeFile);');
end;
end;procedure TCodeFileModel.AddLink(AParent: PCodeFile; AFileName: PChar);
var
pLinkItem: PCodeFile;
begin
// 此处应该考虑这个单元文件是否已经被关联过的检查
//
Assert(AParent <> nil);
pLinkItem := Append(AFileName);
Link(AParent, pLinkItem);
end;function TCodeFileModel.Find(AFileName: PChar): PCodeFile;
var
pItem: PCodeFile;
begin
Result := nil; pItem := FirstItem;
while pItem <> nil do
begin
if AnsiStrComp(AFileName, pItem.Name) = 0 then
begin
Result := pItem;
Break;
end;
pItem := pItem.Next;
end;
end;end.
在使用Move方法复制数据时经常出现不稳定的错误,时有时无!
Access violation at address 00402CEB in module 'Project1.exe'. Read of address 01830000
多运行几次测试代码就会报上述错。代码如下:
function TCodeFileModel.Append(AFileName: PChar): PCodeFile;
var
pItem: PCodeFile;
begin
New(pItem);
FillChar(pItem^, Sizeof(TCodeFile), #0);
// Move(AFileName^, pItem^, MaxFileLength);
Move(AFileName^, pItem.Name, MaxFileLength);
// .... 其他代码
end;
使用下面的TCodeFile 和 TCodeFileLink 记录生成单元引用关系
PCodeFileLink = ^TCodeFileLink;
PCodeFile = ^TCodeFile;
// 单元文件信息记录
TCodeFile = record
Name: array[0..MaxFileLength] of char; // 单元名称
Kind: TCodeFileKind; //类型
Contain: PCodeFileLink; //所引用到的单元链
Next: PCodeFile;
Prev: PCodeFile;
end; //单元链记录
TCodeFileLink = record
CodeFile: PCodeFile;
Next: PCodeFileLink;
end;下面是完整单元代码和测试代码
--------------------------------------------------------------------------------------// 测试代码
procedure TForm2.btn3Click(Sender: TObject);
var
i: Integer;
j: Integer;
pItem: PCodeFile;
begin
if FileMap <> nil then
FileMap.Free;
FileMap := TCodeFileModel.Create; // 多运行几次这里的测试代码就会出现错误
AddMsg('开始增加1000个');
btn3.Enabled := False;
try
for i := 1 to 1000 do
begin
try
pItem := FileMap.Append(Pchar('Test' + IntToStr(i)));
for j := 1 to 100 do
FileMap.AddLink(pItem, Pchar(IntToStr(i) + ' - Child - ' + IntToStr(j)));
except
on E: Exception do
AddMsg(e.Message);
end;
end;
finally
btn3.Enabled := True;
AddMsg('增加1000个结束');
end;
end;
procedure TForm2.AddMsg(const AValue: string);
begin
mmo1.Lines.Add(AValue);
end;unit uUnitMap;interfaceconst
MaxFileLength = 60;
type
// 搜索范围内, 搜索范围外, 工程
TCodeFileKind = (cfExternal, cfInternal, cfProject); PCodeFileLink = ^TCodeFileLink;
PCodeFile = ^TCodeFile; TCodeFile = record
Name: array[0..MaxFileLength] of char;
Kind: TCodeFileKind;
Contain: PCodeFileLink;
Next: PCodeFile;
Prev: PCodeFile;
end;
TCodeFileLink = record
CodeFile: PCodeFile;
Next: PCodeFileLink; // 使用单链就可以,
//Prev: PCodeFileLink;
end; TCodeFileModel = class
public
FirstItem: PCodeFile;
LastItem: PCodeFile;
CurrentItem: PCodeFile;
Count: integer; function Append(AFileName: PChar): PCodeFile;
function Find(AFileName: PChar): PCodeFile;
function Locate(AFileName: PChar): Boolean;
function FindLink(AParent, AChild: PCodeFile): Boolean;
procedure Link(AParent, AChild: PCodeFile);
procedure AddLink(AParent: PCodeFile; AFileName: PChar); public
constructor Create;
destructor Destroy; override;
procedure Clear;
end;
implementationuses SysUtils;constructor TCodeFileModel.Create;
begin
inherited;
clear;
end;destructor TCodeFileModel.Destroy;
begin
Clear;
inherited;
end;function TCodeFileModel.Locate(AFileName: PChar): Boolean;
var
pItem: PCodeFile;
begin
pItem := Find(AFileName);
Result := pItem <> nil;
if Result then
CurrentItem := pItem;
end;function TCodeFileModel.FindLink(AParent, AChild: PCodeFile): Boolean;
var
pIncItem: PCodeFileLink;
begin
Result := False;
pIncItem := AParent.Contain;
while pIncItem <> nil do
begin
Result := pIncItem.CodeFile = AChild;
if Result then
Break;
pIncItem := pIncItem.Next;
end;
end;function TCodeFileModel.Append(AFileName: PChar): PCodeFile;
var
pItem: PCodeFile;
begin
try
New(pItem);
FillChar(pItem^, Sizeof(TCodeFile), #0);
// 下面Move会出现错误,不稳定(错误时有时无)
// Move(AFileName^, pItem^, MaxFileLength);
Move(AFileName^, pItem.Name, MaxFileLength); pItem.Prev := LastItem;
if LastItem <> nil then
LastItem.Next := pItem
else
begin
FirstItem := pItem;
LastItem := pItem;
end;
LastItem := pItem; inc(Count);
Result := pItem;
except
// raise Exception.Create('Append(AFileName: PChar): PCodeFile');
on E: Exception do
raise Exception.Create('Err: Add ' + AFileName + ' Count:' + IntToStr(Count) +
#13#10'Error Code'#13#10 + E.Message + #13#10 +
'Address:' + IntToStr(integer(@pItem)));
end;end;procedure TCodeFileModel.Clear;
var
pLink: PCodeFileLink;
begin
while FirstItem <> nil do
begin
CurrentItem := FirstItem;
FirstItem := FirstItem.Next; while CurrentItem.Contain <> nil do
begin
pLink := CurrentItem.Contain;
CurrentItem.Contain := pLink.Next;
Dispose(pLink);
end;
Dispose(CurrentItem);
end; FirstItem := nil;
LastItem := nil;
CurrentItem := nil;
Count := 0;
end;procedure TCodeFileModel.Link(AParent, AChild: PCodeFile);
var
pLink: PCodeFileLink;
begin
try
New(pLink);
FillChar(pLink^, SizeOf(PCodeFileLink), #0);
pLink^.CodeFile := AChild; pLink.Next := AParent.Contain;
if AParent.Contain <> nil then
AParent.Contain := pLink;
except
raise Exception.Create('Link(AParent, AChild: PCodeFile);');
end;
end;procedure TCodeFileModel.AddLink(AParent: PCodeFile; AFileName: PChar);
var
pLinkItem: PCodeFile;
begin
// 此处应该考虑这个单元文件是否已经被关联过的检查
//
Assert(AParent <> nil);
pLinkItem := Append(AFileName);
Link(AParent, pLinkItem);
end;function TCodeFileModel.Find(AFileName: PChar): PCodeFile;
var
pItem: PCodeFile;
begin
Result := nil; pItem := FirstItem;
while pItem <> nil do
begin
if AnsiStrComp(AFileName, pItem.Name) = 0 then
begin
Result := pItem;
Break;
end;
pItem := pItem.Next;
end;
end;end.
解决方案 »
- 怎样通过快捷方式取得实际指向的路径?
- deipli spcomm不能接收循环发来的信息????
- 函数指针的使用问题
- 我的程序为什么启动后就不见了?
- ado连access2000,请问acess支持事务吗?
- Realplay控件问题
- 我是否该做这个软件,郁闷中,请大家给个意见
- 怎解DBGrid 中的日期字段用粘贴无效?
- 在Win2000 professional里,我的程序只要切换成中文输入(即按Ctrl+Space)时,我的程序就会死掉。计算机上其他程序都没这个问题?盼解答
- windowsmediaplayer 怎么截图?
- 多线程加载数据后数据部分丢失,求助。
- Pointer指针也能解除引用?
Move(AFileName^, pItem.Name, min(MaxFileLength,strlen(AFileName)));
试试。
另外根据调用者传给AFileName参数值的可能性,适当增加对空串的处理,即AFileName = nil时的处理。
原因就是那次 Move 的时候 AFileName+MaxFileLength 刚好越过它所在活动页面的边界,到了一个未被分配的页面,于是访问就出错了。运行多了才出错是因为,像不到64字节的小内存,并不是很容易处于页面边缘,并且差那么几个到几十个字节就越过页面了
同样感谢unsigned查到了一处不显眼的内存泄露^_^