你的第一段代码可以执行通过吗?代码在我的系统中运行不能通过的:
new(pt); sp(pt)^:='abc123';
showmessage(sp(pt)^); dispose(pt);上面的代码应该是不能运行通过的,因为只是new了一下,并没有分配空间。
将代码修改为:
new(sp(pt)); sp(pt)^:='abc123';
showmessage(sp(pt)^); dispose(pt);就可以了,这样编译系统就知道你要new一个^string类型的指针。
new(pt); sp(pt)^:='abc123';
showmessage(sp(pt)^); dispose(pt);上面的代码应该是不能运行通过的,因为只是new了一下,并没有分配空间。
将代码修改为:
new(sp(pt)); sp(pt)^:='abc123';
showmessage(sp(pt)^); dispose(pt);就可以了,这样编译系统就知道你要new一个^string类型的指针。
string本身就是指针类型。
Pointer是无类型指针,无类型指针,没有类型,new自然不可能知道该给其分配多大的内存空间。
此外,上面的赋值语句指针一律都没有分配内存,就直接使用,这是大忌。(我唯一不能确定的是string,Delphi确实可以为string自动分配内存,但是用^string,我就不清楚了,而且这样,纯粹是画蛇添足)
不过,我是这样地感到奇怪的?我以上的两种情况为什么结果不一样?为什么一种可以得到正确的结果,而另一种则会在执行过程中出错的。是与string本身是一个指针类型有关吗?string类型的变量本身是一个指针,当然要用上四字节来表示内存地址的。那所谓字符串的引用计数放在哪里?(真正的菜鸟问题!)
对于你的:“Pointer是无类型指针,无类型指针,没有类型,new自然不可能知道该给其分配多大的内存空间。”
给程序加上这样的一句: showmessage(inttostr(sizeof(pt^)));
可以发现,原来pointer类型的变量己经分配了4字节的内存!对于你的:“此外,上面的赋值语句指针一律都没有分配内存,就直接使用,这是大忌。”
这个,以上过程不是没有分配内存的,只不过,进行了指针的转化而己。
而且,如果把我以上的两个过程的一个,分开两个来执行,如下所示,则并不会出错的。
再加上我的注释,看看是不是有问题的!
type sp=^string;
var pt:^pointer;
begin
new(pt);//pt是一个指向pointer的指针!建立一个pointer的变量并把地址给pt!
sp(pt)^:='abc123';//sp(pt)的作用是把pt转化成指向字符串的指针!
//这样,sp(pt)^就变成了一个字符串变量,可以赋值给它!
showmessage(sp(pt)^);//显示出来!
dispose(pt);
end;
另一个:
type ip=^integer;
var pt:^pointer;
begin
new(pt);//pt是一个指向pointer类型的指针
ip(pt)^:=1234;//把pt转化成ip类型的数据,即整数类型的指针!
//这样,ip(pt)^就变成了一个整数变量,给它赋值1234.
showmessage(inttostr(ip(pt)^));//显示出来!
dispose(pt);
end;
1、先要说说我们现在地系统,我们的使用的都是32位Windows,所谓32位就是,地址的大小是32位,这就意味着,一个程序最大可以使用4G的内存。
2、在Windows系统中,int的大小恰好也是32位。
基于这么两点,我来说说你的运气为什么那么好!
首先,你New一个Pointer,那么就是开了4Byte的内存,然后你强制转换为PInt,进行Int的赋值,而Int恰巧是4Byte,所以上述语句不会产生错误。如果你换成Double,保证你错。
其次,你直接写'abc123',那么程序会在Heap中开一段内存,存放这个字符串。你的赋值,就是将这个字符串在堆中的起始地址付给那个Pointer。所以,此时并不会产生内存错误。但是,你原来New出来的地址就丢掉了,也就是所谓的Memory Leak。
好了,说了这两点。应该不难理解:
new(pt); ip(pt)^:=1234;
showmessage(inttostr(ip(pt)^)); sp(pt)^:='abc123';
showmessage(sp(pt)^); dispose(pt);
没有问题,实际上最后一句Dispose写与不写,都没有任何意义。
而前面掉个顺序为什么出错呢?
因为此时pt已经指向那堆中的字符串,这个时候,试图向指向这个字符串地址的内存(我也不知道这个地址在哪里)写数据,就很容易出AV错误。即使不出,那么该程序如果一大,就会出一个非常难以Debug的错误。你的运气太好了,不过你要写Pointer的程序,还得修炼两年。
var pt:^pointer;
begin
new(pt);//pt是一个指向pointer类型的指针
ip(pt)^:=1234;//把pt转化成ip类型的数据,即double类型的指针!//现在改了
//这样,ip(pt)^就变成了一个double变量,给它赋值1234.
showmessage(floattostr(ip(pt)^));//显示出来!//也改了
dispose(pt);
end;运行一下,出错了没有?可能我的电脑特别烂吧,傻电脑就是不按我们的意思出错!就算我把range checking选上,提醒它也没有用的。哦,还给它选上overflow checking也是照旧的。我的电脑是delphi4.0+win2000或winme的。没钱买delphi5.0! :(
会与delphi的版本有关的?你要用好指针吗?我看,你得再...再...想想.....想...想...上...两............
..........................................................................
..........................................................................
..........................................................................
.........................................................两...两...个小时!
var pt:pointer;
肯定出错,但是上面的代码没有出问题。难道Delphi有这种自动转换的功能?
type sp=^string;
var pt:^pointer;
begin
new(pt);//pt是一个指向pointer类型的指针
(ip(pt))^:= 12345;
showmessage(floattostr(ip(pt)^));//显示出来!//也改了 (sp(pt))^:= 'aa12345';
showmessage(sp(pt)^);
dispose(pt);
end;真的是类型智能转换的吗?那Delphi是如何分配存储空间的呢?
To dedema:你走你的阳关道,我走我的独木桥。我自信领悟了指针,至于Delphi有什么蹊跷,我不关心。我知道所有的编程语言在指针上至少要执行一个相同的规则。
什么“你走你的阳光道,我走我的独木桥”,岂不是说,我们今后各不相干吗?哎呀,不能这样说吧!我们在这里只不过是发表见解吧,我有某种理解,当然想弄清怎么回事的!你对指针有某种深刻的领悟,那就应该帮我们领悟一下呀!
对以上的一些代码,我再试一下,发现奇了!第一次编绎通过后,运行起来出错。第二次编绎起来运行后又没有错。真是奇怪,任何软件总有一些bug。就算不是bug,人的世俗脑袋面对密密麻麻的机器代码,也难免出错的。不然历史上就不至于有什么软件危机了。
对你上面的解释,凭我的智力还真的理解不了的!只好试一下执行结果后,挑你的语病来说了。希望你不要介意的!不过,我这样说好象白说,因为你本来就不会介意的!对吧!
难道你们都不知道吗
该打
如果你将
type ip=^double;//现在改了
type sp=^string;
var pt:^pointer;
定义为全局的就会出错,下面是在DelphiBBS上得到的回答:按照原理来说,(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;却没引发错误.不知chechy认为是否正确。
出在 sp(pt)^:='abc123';
showmessage(sp(pt)^);
你看看是不是呀,我还没有看完
你门讨论,我看看
type
ip = ^integer;
sp = ^string;
var
pt: pointer;
S: sp;
I: ip;
begin
new(S);
new(I);
S^ := 'abc123';
pt := S;
showmessage(sp(pt)^);
I^ := 1234;
pt := I;
showmessage(inttostr(ip(pt)^));
dispose(S);
dispose(I);
end;
type ip=^integer;
sp=^string;
var pt:^pointer;
begin
new(sp(pt)); //这里分配的空间不一定够 sp(pt)^:='abc123';
showmessage(sp(pt)^); ip(pt)^:=1234;
showmessage(inttostr(ip(pt)^)); dispose(pt);
end;
但是我想 事情可能是这样,
我的个人感觉,大家见笑。
PINTER是4BYTE和INTEGER一样,
所以,P1:^POINTER 声明的
P1 和 INTEGER的指针,是兼容的,
所以你可以用它指向,INTEGER变量。
但是
分配空间之后,在让他指向STRING的指针(姑且这么说)
他们是不兼容,偶认为
以上是我个人理解。
我不认为这里有指向指针的指针的说法。
为什么不 P1: POINTER
大事不好!
我按您的指示:
把如下这个局部过程的声明改到全局那儿!
type ip=^double;//现在改了
var pt:^pointer;
begin
new(pt);//pt是一个指向pointer类型的指针
ip(pt)^:=1234;//把pt转化成ip类型的数据,即double类型的指针!//现在改了
//这样,ip(pt)^就变成了一个double变量,给它赋值1234.
showmessage(floattostr(ip(pt)^));//显示出来!//也改了
dispose(pt);
end;
可是还是不出错的!包括编绎和执行!
把以上声明部分的pt:^pointer,改成pt:^byte,然后写成如下形式:
type ip=^double;//现在改了
var pt:^byte;
begin
new(pt);//pt是一个指向byte类型的指针
ip(pt)^:=122.322224;//把pt转化成ip类型的数据,即double类型的指针!并把数字改大,占用字节数更多的。
//这样,ip(pt)^就变成了一个double变量,给它赋值122.322224.
showmessage(floattostr(ip(pt)^));//显示出来!//也改了
dispose(pt);
end;
然后再把声明部分写到全局去,可是还是不出错的!
我傻眼了。
还有,局部堆的指针如以上般地转化,我写了如下的过程进行“体验”
type ip=^dword;
var pt:^byte;
r:record
x:byte;
y:byte;
z:byte;
xyz:byte;
end;
begin
// new(pt);//pt是一个指向byte类型的指针
r.x:=1;
r.y:=2;
r.z :=3;
r.xyz:=123;
pt:[email protected];
// showmessage(inttostr(integer(@r))+' '+inttostr(integer(@r.z)));//不一样的地址
//showmessage(inttostr(sizeof(r)));
ip(@r.x)^:=10*256*256*256+11*256*256+12*256+13;//把pt转化成ip类型的数据// showmessage(inttostr(ip(pt)^));//显示出来!
showmessage(inttostr(r.x)+' '+inttostr(r.y)+' '+inttostr(r.z)+' '+
inttostr(r.xyz));//显示结果为13 12 11 10,为期待的结果
//dispose(pt);
end;
可是把 ip(@r.x)^:=10*256*256*256+11*256*256+12*256+13;
改成为 ip(@r.y)^:=10*256*256*256+11*256*256+12*256+13;//把pt转化成ip类型的数据
后还是 出错了。按大富翁的回答不应出错的啊?谢谢你了。以后还要得到你的指点的。
上面的代码如果是^double不会出错,我估计是Delphi进行了某中转换。如果你定义了
^string,如下面: type ip=^double;
type sp=^string;var
pt:^pointer; //全局变量begin
new(pt);//pt是一个指向byte类型的指针
ip(pt)^:=122.322224;//把pt转化成ip类型的数据,即double类型的指针!并把数字改大,占用字节数更多的。
//这样,ip(pt)^就变成了一个double变量,给它赋值122.322224.
showmessage(floattostr(ip(pt)^));//显示出来!//也改了
sp(pt)^:='ddddd'; //错误
showmessage(sp(pt)^);
dispose(pt);end;上面的代码会导致指针错误,大富翁的回答我还觉得不是太明白,我到borland的新闻组
上面问一下。至于你最后的代码,还没来得及研究。
new(sp(pt));
new(sp(pt));
new(sp(pt));
new(sp(pt));
new(sp(pt));
干嘛把思路搅得这样乱呢?
编译通过执行不提示错误并不能证明什么的.
保护模式下内存地址的保护也是有限的.