为什么要用指针?(100)

大愚

Unregistered / Unconfirmed
GUEST, unregistred user!
用了delphi很长一段时间了,但是一直没怎么用过指针,我也知道指针的一些用法,但是觉得指针很麻烦,有些时候还不如直接用类型。比如一个记录类型:type TItem = Record id : Integer
title : String
end
PItem = ^TItem;varDItem:pitem;和DItem:Titem;一样的用,使用指针还需要手动分配内存和清除,有什么好处吗?
 
Z

znxia

Unregistered / Unconfirmed
GUEST, unregistred user!
var DItem:pitem;begin new(DItem)
DItem.ID:=3
dispose(DItem);end;----------------var DItem:Titem;begin DItem.ID:=3;end;---------------有些地方,例如TreeView的节点Node,有一个Data属性,该属性必须指向指针类型的变量。此外,通过别人传递给你的指针,你可以修改别人的数据。哎,说什么好呢,这2者,要看你在什么地方使用了,呵呵
 
Y

yuzhizhi

Unregistered / Unconfirmed
GUEST, unregistred user!
其实我的感觉数据结构中指针作用可以非常灵活.如一个二叉树算法时,你可以根据你的需要来随时添加你的二叉树.如果用你DItem:Titem;如果做成二叉树,只怕只能通过数组预先定义.
 
Z

zkktom

Unregistered / Unconfirmed
GUEST, unregistred user!
指针比较灵活!
 

白河愁

Unregistered / Unconfirmed
GUEST, unregistred user!
你用过只有2K内存的机器(其中256字节还用来做堆栈了)的机器,就知道为什么了.
 
G

guanyue7613

Unregistered / Unconfirmed
GUEST, unregistred user!
varDItem:pitem;DItem:Titem;表面是一样的用,实际上完全不一样。DItem:pitem;此时只会分配4个字节的pointer指针指向结构地址。[red]DItem:Titem;此时会在内部使用_InitializeRecord对它初始化,当然最后会使用_InitializeArray分配sizeof(Titem)个字节的内存地址。[/red]在频繁使用时,直接New和dispose比InitializeRecord的效率高很多。
 

白河愁

Unregistered / Unconfirmed
GUEST, unregistred user!
DItem:Titem;此时会在内部使用_InitializeRecord对它初始化所谓初始化,也不就是在堆中随便指定一段内存用而已,只是个指针赋值,应该比分配要快.
 
G

guanyue7613

Unregistered / Unconfirmed
GUEST, unregistred user!
白河愁,建议您多了解下这组函数的实现再发言:procedure _Initialize(p: Pointer
typeInfo: Pointer);procedure _InitializeArray(p: Pointer
typeInfo: Pointer
elemCount: Cardinal);procedure _InitializeRecord(p: Pointer
typeInfo: Pointer);procedure _Finalize(p: Pointer
typeInfo: Pointer);procedure _FinalizeArray(p: Pointer
typeInfo: Pointer
elemCount: Cardinal);procedure _FinalizeRecord(P: Pointer
typeInfo: Pointer);如果不愿查看Delphi源码,可以查看周爱民的《Delphi源代码分析》
 
F

FreeAndNil

Unregistered / Unconfirmed
GUEST, unregistred user!

白河愁

Unregistered / Unconfirmed
GUEST, unregistred user!
guanyue7613, 建议下多做实践,实践出真知type paa = ^aa
aa = record bb: dword
end;procedure TForm1.BTN_1Click(Sender: TObject);var aaa: aa
bbb: paa;begin aaa.bb:= 1
New(bbb)
bbb^.bb:= 1;end;asm //对于直接分配的变量就取堆的空间 ESP44fa70 51 push ecx44fa71 c7042401000000 mov [esp], $0000001//而要NEW的,就要调用 GETMEM44fa78 b804000000 mov eax, $0000000444fa7d e8e631fbff call @GetMem//eax 返回分配的空间44fa82 c70001000000 mov [eax], $00000001谁慢谁快一目了然.建议看书的时候要适当做实践,书上不是所有东西都对的.至于你说那个titem,只是很个别的特例,大部分指针都是如上操作的.
 

大愚

Unregistered / Unconfirmed
GUEST, unregistred user!
谢谢各位的精彩分析,大致了解了指针就是:1.快2.使用灵活,可以前后移动3.可交给其他程序或过程修改当前数值4.固定用法,ADD用得多5.省内存?(应该会浪费4个字节内存吧?指针也只有分配了内存才有意义吧?)6.每一个类型变量实例化也就是封装了指针的一系列动作?
 
W

wql

Unregistered / Unconfirmed
GUEST, unregistred user!
大批量数据或不知道具体有多少数据的时候,指针的优势就出来了,例如你一次分配2M的内存,但是用指针你可以在需要的时候在分配
 
G

guanyue7613

Unregistered / Unconfirmed
GUEST, unregistred user!
to白河愁,谁的是特例要说清楚,而且你根本没把汇编copy完全!!
代码:
type  PTestRecord = ^TTestRecord
 TTestRecord = record    AField : Integer
   BField : string
   CField : Variant
   case Integer of      1 : (DField : Int64)
     2 : (EField : WideChar)
 end;procedure Test();var  pR : PTestRecord
 tR : TTestRecord;begin  tR.AField := 1
 tR.BField := 'abc'
 New(PTestRecord)
 pR^.AField := 1
 pR^.BField := 'abc';end;
对应的汇编如下所示:
代码:
005F3251 8D4000           lea eax,[eax+$00]uMain.pas.235: begin005F3254 55               push ebp005F3255 8BEC             mov ebp,esp005F3257 83C4E0           add esp,-$20005F325A 53               push ebx005F325B 8D45E0           lea eax,[ebp-$20]005F325E 8B1528325F00     mov edx,[$005f3228]005F3264 E89F2DE1FF       call @InitializeRecord [red]开始初始化,分配内存,此处取决于结构的大小[/red]005F3269 33C0             xor eax,eax005F326B 55               push ebp005F326C 68CA325F00       push $005f32ca005F3271 64FF30           push dword ptr fs:[eax][red]用SEH结构,保证结构最终调用Finalize来回收内存[/red]005F3274 648920           mov fs:[eax],espuMain.pas.236: tR.AField := 1;005F3277 C745E001000000   mov [ebp-$20],$00000001uMain.pas.237: tR.BField := 'abc';005F327E 8D45E4           lea eax,[ebp-$1c]005F3281 BAE0325F00       mov edx,$005f32e0005F3286 E88920E1FF       call @LStrLAsguMain.pas.238: New(PTestRecord);005F328B 8B1528325F00     mov edx,[$005f3228]005F3291 B820000000       mov eax,$00000020005F3296 E8B132E1FF       call @NewuMain.pas.239: pR^.AField := 1;005F329B C70301000000     mov [ebx],$00000001uMain.pas.240: pR^.BField := 'abc';005F32A1 8D4304           lea eax,[ebx+$04]005F32A4 BAE0325F00       mov edx,$005f32e0005F32A9 E82220E1FF       call @LStrAsg005F32AE 33C0             xor eax,eax005F32B0 5A               pop edx005F32B1 59               pop ecx005F32B2 59               pop ecx005F32B3 648910           mov fs:[eax],edx[red]自动收尾回收[/red]005F32B6 68D1325F00       push $005f32d1
 

白河愁

Unregistered / Unconfirmed
GUEST, unregistred user!
to guanyue7613:有没有完全自己看截图http://www.ff18.com/tmp/prg.png
 
G

guanyue7613

Unregistered / Unconfirmed
GUEST, unregistred user!
to 白河愁:我说的正是你写的那个record只是个特例,不能说明record不调用InitializeRecord!何况一般record会只有一个Dword字段吗?往record多加几个字段试试?
 

白河愁

Unregistered / Unconfirmed
GUEST, unregistred user!
to guanyue7613:经过测试,加入数十个字段都没有问题.问题是出在 CField : Variant上,只要使用了就会有 init, 它是一个无类型,不属于传统的普通内存装载型变量它根本不是一个 record 应该装的东西,就好比 string, tobject如果你认为 是 record 就应该使用 Variant,那我无话可说.
 
G

guanyue7613

Unregistered / Unconfirmed
GUEST, unregistred user!
真的是只有Variant吗?你试试这个?PTestRecord = ^TTestRecord;TTestRecord = record AField : Integer
BField : string;end;
 
G

guanyue7613

Unregistered / Unconfirmed
GUEST, unregistred user!
[:D]我搞错了,经测试含有string, widestring等含有需要重新分配内存大小的字段,记录才需要InitializeRecord。。。。。。。
 

大愚

Unregistered / Unconfirmed
GUEST, unregistred user!
高手交战就是不一样,开眼了(其实看不懂。。。。)
 
顶部