关于动态记录数组指针的释放问题????[内有代码以供分析,谢谢] (100分)

  • 主题发起人 主题发起人 form2
  • 开始时间 开始时间
F

form2

Unregistered / Unconfirmed
GUEST, unregistred user!
首先我不想使用D4以上的动态数组功能
type
TByteArray=array [0..0] of Byte;//定义BYTE数组原型
PByteArray=^TByteArray;

TGS_info=Record
NeedType:byte;
TiaoJian:byte;
a1_5:array[1..5] of PByteArray;
He:PByteArray;
Ge:PByteArray;
end;
TTGS_info=array [0..0] of TGS_info;//定义TGS_info记录数组原型
PGS_infoArray=^TTGS_info;

implementation

procedure CreateByteArray(var a:PByteArray;b:longint);
begin
GetMem(a,b+1);
a[0]:=b;
end;

procedure FreeByteArray(var a:PByteArray);
begin
FreeMem(a,a[0]);
end;

procedure CreateGS_infoArray(var a:PGS_infoArray;b:longint);
begin
GetMem(a,SizeOf(a^)*b);
end;

procedure FreeGS_infoArray(var a:PGS_infoArray);
var
b:Longint;
begin
FreeMem(a,HIGH(a^));
//本来应该这样的:
// for b:=1 to HIGH(a^) do FreeMem(a);//可是会出错
//可能a1_5:array[1..5] of PByteArray;这5个没有释放,可是我不知道如何释放它们
//但是,如果前面改为
// TTGS_info=array [0..$FFFF] of TGS_info;//就不会出错!

end;

procedure TForm1.Button3Click(Sender: TObject);//测试
var
a:PGS_infoArray;
b,c,d,e:byte;
begin
CreateGS_infoArray(a,10);//创建10个TGS_info
for b:=1 to 10 do begin
a.NeedType:=3;
a.TiaoJian:=1;
for c:=1 to 5 do begin
CreateByteArray(a.a1_5[c],10);//动态创建10个TGS_info指针中的单独Byte数组
for e:=1 to 10 do a.a1_5[c][e]:=e;
end;
end;
c:=7;d:=4;
for b:=1 to d do begin
memo1.Lines.add(inttostr(a[c].a1_5[d]));//能显示1,2,3,4
end;
FreeGS_infoArray(a);//这里出错
end;

 
另外请问,如果getmem(p,256);
那么在以后,如何探测分配给 p 的大小256?
 
在我将所有的a[xx]替换成a^[xx]后程序运行通过(Delphi5)。

>>如何探测分配给 p 的大小
好像一般没有这个必要吧...如果确实需要,你可以用一个记录封装指针以及分配空间的大小。
 
看了你的回答,我怀疑我程序的其他地方导致了错误,所以重新创建了一个干净的项目
拷贝了上面的代码,将a[xx]替换成a^[xx]。同时,修改了一些代码
另外:我认为将a[xx]替换成a^[xx],好像没有太大关系!
procedure TForm1.Button1Click(Sender: TObject);//测试
var
a:PGS_infoArray;
b,c,d,e:integer;
n:integer;
begin
n:=100;//<---加了这句,我好测试>10的容量
CreateGS_infoArray(a,n);
for b:=1 to n do begin
a^.NeedType:=1;
a^.TiaoJian:=2;
for c:=1 to 5 do begin
CreateByteArray(a^.a1_5[c],10);
for e:=1 to 10 do a^.a1_5[c][e]:=e;
end;
end;
d:=4;
for b:=1 to 10 do begin
memo1.Lines.add(inttostr(a^[d].a1_5[d]));//等于显示:a[4].a1_5[4]的10个值
end;
FreeGS_infoArray(a);
end;

问题一:
当创建了新的项目,n=10的时候不会出现问题,可一旦n>=20那么就会导致freemem错误!
还有,我发现进行下面修改:
TTGS_info=array [0..1] of TGS_info;//定义TGS_info记录数组原型
^
我怎么玩都不会出现错误!晕倒

问题二:
如果将
.....
d:=4;
for b:=1 to 10 do begin
memo1.Lines.add(inttostr(a^[d].a1_5[d]));//等于显示:a[4].a1_5[4]的10个值
end;
FreeGS_infoArray(a);
==>修改为:
d:=4;
FreeGS_infoArray(a);
//或者直接freemem(a);
for b:=1 to 10 do begin
memo1.Lines.add(inttostr(a^[d].a1_5[d]));//等于显示:a[4].a1_5[4]的10个值
end;
竟然还能显示那1-10个数字,这说明 a 没有被释放!!!

最后,谢谢你在我另一贴所给例子的帮助
 
// 将所有的a[xx]替换成a^[xx]
没有用的,这是 Delphi 可以自动转换的 (即是说换了和没换等价:-p)

// for b:=1 to HIGH(a^) do FreeMem(a);//可是会出错
不用一个一个释放吧,你本来就是一起分配的,当然应该一起释放咯:
FreeMem(a, High(a) + 1);

// 竟然还能显示那1-100个数字,这说明 a 没有被释放!!!
不对,释放了只代表别人可以用这些空间了,在别人还没有修改他们之前,
他们当然是保持原样咯;
释放了并不代表清空了。

 
to beta:

FreeMem(a, High(a) + 1);编译不通过,必须FreeMem(a, High(a^) + 1);
按你这样改了,n还是不能>=20,一定出错
而在n<=10的时候,直接FreeMem(a);也没问题!

还有就是单步跟踪发现High(a^)=0
 
既然你不用array of 这种动态数组的定义方法。 那么你就不要用high这个函数来取数组大小。
high取的是array [n..m] of xxx中的m, 在你的定义中这个就是0。 所以high(a^)=0有什么可奇怪的。
 
老大,别忘了 CreateByteArray 中的“a[0]:=b;”。
这个程序的调试过程非常奇怪:我一开始将 a[ 换成 a^[ 还是出错(在a^.NeedType:=1;
处——Range Check Error!)。当我在 a^[0]:=b
之后加上 a^[2*b div b]:=b
之后,就
没有错误了,并且将后来加的这句删掉之后,程序也没有问题。
还有,我实在不明白 a^[0]:=b
一句有何作用?
 
1:CreateByteArray 中的“a[0]:=b;”我已经替换了,因为我用的是CTRL+R替换的
2:a^[0]:=b
因为我的Byte数组个数不会超过256,所以用a^[0]来储存数组大小
当然,b:Longint可能会导致溢出的,昨晚我改成:
procedure CreateByteArray(var a:PByteArray;b:byte);
begin
GetMem(a,b);
end;
procedure FreeByteArray(var a:PByteArray);
begin
FreeMem(a);
end;
3:a^[2*b div b]:=b
什么意思?只是欺骗编译器[]中不为立即数0吗?
a^[2*b div b]:=b;其实不就等于a^[2]:=b,和a^[1,,,,b]:=b;有什么区别吗?

这个程序是很奇怪,包括不能在CTRL+F7中看数组元素

 
>>TByteArray=array [0..0] of Byte;//定义BYTE数组原型
不知道这样的代码有何意义?人为的增加程序的复杂性而已。
 
在我使用{$R-}编译指示符之后,Range Check Error 错误不再出现。现在正在努力攻克
释放循环内分配的内存。

因为编译器认为 a^[2]:=b
中“常量表达式越界”,所以只好...
 
完全解决方案:

type
TByteArray=array [0..0] of Byte;//定义BYTE数组原型
PByteArray=^TByteArray;

TGS_info=Record
NeedType:byte;
TiaoJian:byte;
a1_5:array[1..5] of PByteArray;
He:PByteArray;
Ge:PByteArray;
end;
TTGS_info=array [0..MaxWord] of TGS_info;//定义TGS_info记录数组原型
//如果用 0..0,运行时会发生奇怪的问题: 写最后一个值时会改变最前一个!
PGS_infoArray=^TTGS_info;

procedure CreateGS_infoArray(var a:PGS_infoArray;b:Integer);
begin
GetMem(a,SizeOf(a^)*b);
end;

{$R-}
procedure TForm1.Button1Click(Sender: TObject);//测试
const
MySize=100;
var
a:PGS_infoArray;
b,c,d,e:byte;
begin
CreateGS_infoArray(a,MySize);
for b:=0 to MySize do
begin
a^.NeedType:=3;
a^.TiaoJian:=1;
for c:=1 to 5 do
begin
GetMem(a^.a1_5[c],MySize)
//Just GetMem
a^.a1_5[c]^[0]:=123;
for e:=0 to MySize-1 do // 0..MySize-1
a^.a1_5[c]^[e]:=e;
end;
end;
c:=0;
d:=4;
for b:=0 to d do //Check Head
memo1.Lines.add(inttostr(a^[c].a1_5[d]^));
c:=MySize;
for b:=0 to d do //Check Tail
memo1.Lines.add(inttostr(a^[c].a1_5[d]^));
for b:=0 to MySize do
for c:=1 to 5 do
FreeMem(a^.a1_5[c])
//Just use FreeMem(Pointer);
FreeMem(a)
//同上
end;

已消除所有 Memory Leak 以及访问错误(使用MemProof检查)。
 
我刚回来,运行正常!
看来我少了下面这些释放过程!
for b:=0 to MySize do
for c:=1 to 5 do
FreeMem(a^.a1_5[c])
//Just use FreeMem(Pointer);
FreeMem(a)
//同上

今晚我看看PGS_infoArray的ReSize
谢谢!我已经在修改我的主程序了
 
首先
TTGS_info = array [0..MaxWord] of TGS_info;
的确是标准用法,看 TStringList 的相应定义:
TStringItemList = array[0..MaxListSize] of TStringItem;

其次,我总算知道为什么不能用 High 了,因为它读取了你的 -4 偏移处的一个值,作为
数组的长度保存在那里的。想起 string 的 Length 了吗?呵呵,而你的这个东东没有加
那个东西,所以不行:)

 
多人接受答案了。
 

Similar threads

S
回复
0
查看
3K
SUNSTONE的Delphi笔记
S
S
回复
0
查看
2K
SUNSTONE的Delphi笔记
S
I
回复
0
查看
681
import
I
I
回复
0
查看
562
import
I
后退
顶部