奇怪的指针问题(260分)

  • 主题发起人 主题发起人 compux
  • 开始时间 开始时间
C

compux

Unregistered / Unconfirmed
GUEST, unregistred user!
下面的代码:
procedure TForm1.Button1Click(Sender: TObject);
type ip=^double;
type sp=^string;
var pt:^pointer;
begin
new(pt);
(ip(pt))^:= 12345;
showmessage(floattostr(ip(pt)^));

(sp(pt))^:= 'aa12345';
showmessage(sp(pt)^);
dispose(pt);
end;

可以执行通过,为什么?我在new了pt之后并没有分配空间的。为什么没有报access violation错
 
new就是新分配了一段內存空間給你﹐有起始位置。你用ip(pt)就是從起始位置取一段
double型的數據給你﹐你用sp(pt)就是取一段string的數據給你﹐就不會錯。要是你不
指定數據類型才會錯。
 
type ip=^double;
type sp=^string;
var pt:^pointer;
begin
new(pt);

(sp(pt))^:= 'aa12345';
showmessage(sp(pt)^);

(ip(pt))^:= 12345;
showmessage(floattostr(ip(pt)^));
dispose(pt);

出错了,但是我也不知道为什么? 还请高手解答!!!
 
我运行了你的程序没有问题
我用的是delphi 6 不知你用的是???
 
to dadabox
我知道new会分配内存,Delphi中帮助是这样说的:
The New procedure creates a new dynamic variable and sets a pointer variable to point to it. P is a variable of any pointer type. The size of the allocated memory block corresponds to the size of the type that P points to.
也就是说分配的内存空间是根据指针变量的类型分配的,如果上面的代码将
var pt:^pointer;
改为
var pt:pointer;
肯定出错。
 
to compux:

pt:^pointer;
PT是一个指向指针的指针.
这样new(pt)会返回PT为一个指针,指向一个已经分配的地址空间,这个空间的大小
为SIZEOF(POINTER);
也就是四个字节

如果你修改为PT:POINTER;
这样,NEW(PT)应该会出错,因为PT是一个无类型的指针,编译器无法知道为你分配多大的
空间,所以SIZEOF会是0,NEW完后PT仍然为NIL

sp(pt))^:= 'aa12345'
//让PT指向的4字节 强制为指向字符串的指针,并把指针设置为
指向'AA12345'.记住DELPHI中的长字符串其实就是指针.这样也暂时不会出错,
但是这种方法会有问题,如果你在一个非局部过程中使用,会产生严重问题,那就是因为
STRING会自动释放,就会出现访问地址出错了.最好的方法是用PCHAR,动态分配字符串

showmessage(sp(pt)^);

(ip(pt))^:= 12345
//让PT指向的4个字节(原来是认为是POINTER)强制为整数类型,并
设置为12345,当然不会有错.
showmessage(floattostr(ip(pt)^));

 
to wenyue
上面的代码如果将定义转移为全局就会出错。
但是
(ip(pt))^:= 12345.334;
showmessage(floattostr(ip(pt)^));

这时应该不会强制转换为整形了,但是还是不报错,我定义的是Double,是8字节的。
是否也强制转换为Single了吗?
 
SORRY,我以为IP是INTEGER POINTER,没想到是FLOATPOINTER

按照原理来说,(ip(pt))^:= 12345.334是会出错的,当然(ip(pt))^:= 12345也会出错,
FLOAT是8字节,并且也不会自动转换到SINGLE

不直接出错是有原因的,NEW是从局部堆里分配空间使用
你可以把局部堆当成是一个已经分配有地址空间的大数组,你本来是分配得到了
其中的第N项的指针,但是你却用赋值占用了第N和N+1项的地址,当然不会引发内存访问
冲突错误

你这样不管占用空间大小的使用,只是占用了另外一些未能标记为你使用的一部分内存
可能现在不出错,但是可能会影响其他的一些在堆中的其他变量

如果你一定要这样用,将来你自己的程序就可能会出现想不到的错误
例如你用了(ip(pt))^:= 12345.334,结果却发现本来一个一定等于1的整数变量的
值发生了莫名其妙的变化

打个比方
TYPE TREC=PACKED TRECORD
I:INTEGER;
J:INTEGER;
END;

VAR REC:TREC;
BEGIN
REC.I:=1;
REC.J:=2;

IP(@REC.I)^:=1234;
SHOWMESSAGE(INTTOSTR(REC.J))
END;
然后你再查看下,结果J的值也发生了变化,但是IP(@REC.I)^:=1234;却没引发错误.
 
我觉得wenyue都差不多说完了。
另外,Delphi已经为你定义了这些类型,所以不用再多此一举,可读性也好一些:
type ip=^double
<==> PDouble
type sp=^string
<==> PString
var pt:^pointer
<==> PPointer
 
明白了,谢谢,给分。
 
多人接受答案了。
 
后退
顶部