关于Pointer的问题(100分)

  • 主题发起人 主题发起人 比尔
  • 开始时间 开始时间

比尔

Unregistered / Unconfirmed
GUEST, unregistred user!
我自己写的一个内存分配程序(包装了虚存分配函数)

procedure GetMemEx(var p : Pointer
nSize : Integer);
begin
VirtualAlloc(P, nSize,MEM_COMMIT, PAGE_READWRITE or PAGE_GUARD);
end;

在调用时如下写:

procedure Button1Click(Sender : TObject);
var
I : PInteger;
begin
GetMemEx(I, SizeOf(Integer))
---->编译出错: type of actual and formal var parameter must be identical
I^ := 123;
...
end;

难道PInteger不能作为var变量传进去?
 
PInteger是指针,操作的是这个指针指向的地址,不是变量,可以改变他的值
 
PInteger是有类型指针
可以转换一下
GetMemEx(Pointer(I), SizeOf(Integer));
 
var形式生命的参数类型约束很严格.
PInteger和Pointer在传地址时是不兼容的.
可按照yoking, 的去做.
也可也
procedure GetMemEx(p : Pointer
nSize : Integer);
begin
VirtualAlloc(P, nSize,MEM_COMMIT, PAGE_READWRITE or PAGE_GUARD);
end;
反正P是指针,传值传地址都一样.指向的地址都是一致的
 
yoking 的方法正确

wr960204 的方法不对,声明 P 为值传,无法返回新的地址。
在分配空间前,P 里面放的是一个随机数,而分配空间后
P 的值应该是新的空间的地址(几乎肯定和原来的随机数
不一样),如果不用变参,则新的地址无法传回来,所以
不能声明为值参。
 
beta,虽然传递的是指针的值。
但指针的值是指向的地址,所以我上面说的可以。
不信你试试再说好么?
 
我刚才试了一下,我对 VirtualAlloc 不熟悉,直接用 GetMem 代替,做了试验:

procedure GetMemEx(p: Pointer
nSize: Integer);
// 你可以看一下如果没有设置变参,值根本传不回去;如果用 var 则没有问题
// 不知道怎么地,我用 VirtualAlloc 无论是否用变参,都出错,不会用:(
begin
//VirtualAlloc(P, nSize,MEM_COMMIT, PAGE_READWRITE or PAGE_GUARD);
GetMem(p, nSize);
FillChar(p^, nSize, 0);
FillChar(p^, nSize - 1, Ord('A'));
end;

procedure TForm1.Button1Click(Sender: TObject);
var
pp: Pointer;
begin
GetMemEx(pp, 20);
ShowMessage(PChar(pp));
// FreeMem(pp, 20);
end;

 
beta,GetMem当然不行。
按传值方式Gemem要重新分配内存的。
我上面的回答是针对VirtualAlloc的。
这个函数并不重新分配内存,只是填充一篇内存,指针执行并不重新分配。
不信你试试这个

procedure GetMemEx(p: Pointer
nSize: Integer);
var
i:PInteger;
begin
VirtualAlloc(P, nSize, MEM_COMMIT, PAGE_READWRITE or PAGE_GUARD);
i:=p;
i^:=99;
inc(i);
i^:=98;
end;
var
p:PInteger;
pp:array[0..1] of Integer;
begin
pp[0]:=1;
pp[1]:=2;
p:=@pp[0];
showmessage(Inttostr(pp[0]));
GetMemEx(pointer(p),Length(pp));
showmessage(Inttostr(pp[0]));
end;
你看能不能传回来
 
beta,正像上面我说的。
你使用VirtualAlloc不成功在于这个函数并不分配内存
所以应该先初始化。
procedure TForm1.Button1Click(Sender: TObject);

procedure GetMemEx(p: Pointer
nSize: Integer);
begin
VirtualAlloc(P, nSize,MEM_COMMIT, PAGE_READWRITE or PAGE_GUARD);
end;
var
pp : Pointer;
k:array[0..19] of byte;
begin
pp:=@k[0];
GetMemEx(pp, 20);
ShowMessage(PChar(pp));
end;
 
希望能多多交流
 
// VirtualAlloc不成功在于这个函数并不分配内存
多谢 wr960204 指教:) 有机会多交流。

 
刚刚看了一下 VirtualAlloc 的帮助,算是明白点了,因为原来没有用过这个函数
所以直接看名字,想当然了:)
 
又看了一下帮助,发现不对,VirtualAlloc 的确是要分配内存的:
Memory allocated by this function is automatically initialized to zero

我用的时候之所以出错,是因为用法不对的缘故,第一个参数只是指明一个基地址
返回指针不是通过第一个参数返回的,是通过函数返回值返回的:
[in] Starting address of the region to allocate.
If the function succeeds, the return value is the base address of the allocated region of pages.

你的第一个例子之所以没有出错,因为你的确没有改变 P,它作为第一个参数传进去
仅仅是提供一个基地址而已,不会被改变的。真正的返回值是函数的返回值,而你却
将其忽略了。

正确的定义应该是这样:
procedure GetMemEx(var p : Pointer
nSize : Integer);
begin
p := VirtualAlloc(P, nSize,MEM_COMMIT, PAGE_READWRITE or PAGE_GUARD);
// ^^^^^ 这个返回值才是要用的
end;

试验:
procedure GetMemEx(var p : Pointer
nSize : Integer);
begin
p := VirtualAlloc(P, nSize,MEM_COMMIT, PAGE_READWRITE or PAGE_GUARD);
end;

procedure TForm1.Button1Click(Sender: TObject);
var
pp: Pointer;
i: Integer;
begin
i := 99;
pp := @i;
ShowMessage(IntToStr(Integer(pp^)))
// 99
GetMemEx(pp, 10);
ShowMessage(IntToStr(Integer(pp^)));
// 前面如果是变参,则显示 0,如果是值参则显示 99
// 因此印证了我的 变参 可以传回,值参 不能传回的说法。
// 当然也印证了帮助里面的分配后自动清零的说法。
// 因此一定要用变参
end;

还一个角度想,P 里面原来指向一个随即地址,也就可能是存有合法数据的地址
直接去填充那一片空间怎么行? :)

 
补充一下 Commit 的要分配内存,Reserved 的不要
不过他这里的要求是 Commit,因此要分配内存:)
 
明白了。多谢帮我弄清了一个误区
 
谢什么,这才是交流的目的嘛:)
要不是这样,我也不会去看,也就不会明白:)

 
beta的钻研精神值得学习,值得学习
 
这里气氛很好,Up
 
后退
顶部