您好,Pchar() 函数怎么用?(50分)

  • 主题发起人 wjlsmail
  • 开始时间
wjlsmail:
要是你认清楚其实 string 也是指针,那么你就会把第一种情况归到第三种情况里面,
那么你对这个问题就认识清楚了:)

pipo:
我的理解是这样的:
存放一个字符串当然是需要空间的,比如你先给一个字符串赋初值为 'Hello World!',
此时他占用了 13 个字节(12 字节的内容,1 字节的结束符 #0,我们暂时不考虑前面)
而当你又对其进行操作的时候,比如改为 'Hello',现在它的 Length 变了,但是它的
分配长度会变吗?我不知道,不过我知道在某些情况下,不会。否则可能会反复地对其
占用的空间重新分配长度,这会降低效率,Delphi 不会这样干的。它应该只在必要的
时候才对其空间进行 ReAlloc,因此其“分配的大小”和“长度”没有直接的联系。于
是为了在释放的时候知道应该释放多少字节,就有了这个“分配大小”字段。
以上纯属推测,望之情富翁指正。

 
PChar 的确是个Pointer,但PChar有个约定:必须以NULL(即 #0)结束。
s:='1234';时,‘4’后面一个字节不一定就是 0
如果不显式地加上#0,将使程序不健壮。
 
类型转换不是函数。它只是将特定的内存空间映射(或复制)为另一种数据类型。
 
beta: 您好,谢谢您的回复。我初学,几乎完全空白:),望大家多指导?
如果String也是指针,那么 S2 := Pchar(s1) ;可以理解 ; 我想请教:

1. “String也是指针“ 仅是针对这种情况的一种理解呢还是原本就是这样?
2. 如果String 原本就是指针, 那么: S := '1234'的操作为何又是合理的? 因为如果
S 就是指针的,那么应该: S := @...;的,是不是String 有双重类型? 我觉得不可思议
如果具有双重类型,那么在内存中它又是怎样被存储的? 它的数据格式?
3 如果 String具有既是字符串又是指针, 那么Delphi中是如何存储、处理String类型的?
其他语言中对字符串业作这样的处理?
4 在Delphi中,还有哪些类型具有这样的特点,既是基本类型,又是指针 ?
 
当两个或更多的A n s i S t r i n g 类型共享一个指向相同物理地址的引用时,D e l p h i 内存管理使用了
copy - on - write 技术,一个字符串要等到修改结束,才释放一个引用并分配一个物理字符串。下面的例子显示了这些概念:
var
S1,S2 : string ;
begin
//给S1赋值,S1的引用计数为1
S1:='And now for something...';
S2:=S1; //现在S2 与S1 指向同一个字符串,S1 的引用计数为2
//S2 现在改变了,所以它被复制到自己的物理空间,并且S1 的引用计数减1
S2:=S2+'completely diff e r e n t 1 ' ;
end ;
 
vine : 您好,
1 . //S2 现在改变了,所以它被复制到自己的物理空间,并且S1 的引用计数减1
S2:=S2+'completely diff e r e n t 1 ' ;
为何S1的引用次数会减 1? 引用次数如何计算?
2 引用与指针相同吗? 书上说一个变量的别名就是它的引用 ,即意味着用不同的名字
访问同一个变量内容。(但有的书中又说引用就是指针,不同的语言也有不同的说法)

谢谢大哥,欢迎继续指导、讨论,谢谢
 
to wjlsmail:
1. “String也是指针“ 仅是针对这种情况的一种理解呢还是原本就是这样?
回复:string类型在指示器{H+}的时候为AnsiString,{H-}的时候为ShortString
AnsiString为生存期自管理类型,其结构为:|分配的大小|引用计数|长度|DDG|#0|
AnsiString类型变量实际是指向DDG字符串数据区的指针,可通过下标访问其字符元素,
但不能通过S[0]来访问其长度。
ShortString是为了保持和Delphi 1的兼容所保留的,其结构为:|长度|DDG|
可以通过S[0]来访问其字符串长度。shorstring与以null结尾的字符串不兼容。
可以看一看ShortStringAsPchar()函数定义
function ShortStringAsPChar(var S: ShortString): PChar;
{这函数能使一个字符串以null结尾,这样就能传递给需要PChar类型参数的Win32 API函数,如果字符串超过
254个字符,多出的部分将被截掉}
begin
if Length(S)=High(S) then Dec(S[0]); { 如果S太长,就截取一部分}
S[Ord(Length(S))+1]:=#0; { 把null加到字符串的最后}
Result:=@S[1]; { 返回PChar化的字符串}
end;
2. 如果String 原本就是指针, 那么: S := '1234'的操作为何又是合理的? 因为如果
S 就是指针的,那么应该: S := @...;的,是不是String 有双重类型? 我觉得不可思议
回复:这是由Delphi编译器进行处理的,你不必关心。就像对象实例也是指向堆中的一个指针
一样,但我们不必这样来访问:TForm^.caption:='Hello';
3/4回复:不可能出现你说的这种类型。
另外,PChar结构是|DDG|#0|供你参考
以上仅是个人观点,希望高人指正。

to beta:
你的推测看起来的确有道理,我觉得是不是在长度减小的时候不再重新分配内存,而在长度
增加的时候要新分配。是不是这样啊?
上面function ShortStringAsPChar(var S: ShortString): PChar;这个函数中
S[Ord(Length(S))+1]:=#0; { 把null加到字符串的最后}
这句里ord的函数的作用不甚理解,请执教

我有点儿代俎越疱了,替beta回答了问题,别见怪阿,呵呵
 
pipo: 谢谢您得回复,让我明白很多。其实我原来一直有种想法,也不知道对不对,
现在说出来,望大家,望各位前辈指正赐教。

我觉得,所有的变量(包括对象)都是这样被系统处理的: 如:
I : Integer; 我觉得系统是这样处理的:
首先给这个定义I一个标号,如 : 0012001 ,这个标号指向程序所用堆栈中的一个地址
然后再使用变量I .使用时,从 I---0012001----该地址
“首先给这个定义I一个标号“----这个标号由系统内部自动给出且唯一,它对应一个堆栈中的
单元 。 如第一个定义的变量可以为: 001,对应堆栈中专门用来存储变量的区域的第一个
单元 。
(对“指针“类型来说,该地址中存放的依然是一个地址值)
这样以来,这个标号就唯一的指向了一个单元。

这种想法对吗?可否给我讲一下系统如何处理变量?

还有, 1. Pipo :"对象实例也是指向堆中的一个指针一样"----能否详细解释讲一下,
谢谢您
2. 关于引用,见给Vine的回复 (上面第二条)

谢谢大家的指导,谢谢,欢迎继续
 
pchar 不是函数,是一个数据类型.
pchar(...)是对数据类型进行转换!
 
jsxjd; 谢谢,谢谢。这个现在我明白了:),不过也有的书上就写着: Pchar是字符串类型

ok,我继续听讲,欢迎大家继续指导、讨论,谢谢:)
 
还有,
Label2.Caption := Pchar(Pos('a','abc')); //编译无错,运行出错
Label2.Caption := Pchar(IntToStr(Pos('a','abc'))); //编译无错,运行无错

难道Pchar只能对 String作类型转化? (我更认同字符串为指针的说法,否则上面的例子
很难解释,还是象我的一个前辈说的: String与Pchar可以通用0)


 

Pchar(Pos('a','abc')); 并不指向真正的串,它的值是 1
这个地址是程序无法访问的。
 
欢迎继续,欢迎浏览
 
Pchar只是将来字符串变为指针
 
wjlsmail:
// 既是基本类型,又是指针 ?
不,string 并不是双重类型(既是基本类型,又是指针),它的实质是指针,但是编译器
想要让我们认为它不是:) 所以有些时候你会看见与 string 是指针的说法不相符的情况
比如
aPChar := aString; // 虽说都是指针,但是这样编译不通过
aPChar := PChar(aString); // 这样就可以,但这个转换仅仅是让编译器高兴而已:)

pipo:
// S[Ord(Length(S))+1]:=#0; { 把null加到字符串的最后}
// 这句里ord的函数的作用不甚理解
我认为这个 Ord 纯属多余,一下两种情况都是对的:
S[Length(S) + 1] := #0; // 直接通过函数取长度
S[Ord(S[0]) + 1] := #0; // S[0] 存放长度,Ord 将该长度字节从字符型转为整型
唯独你给出的这个显得多此一举。 个人看法而已:)

 

Label2.Caption := Pchar(Pos('a','abc')); //编译无错,运行出错

因为没有以 NULL 终结。

 
var
buff array[0..100] of char
string1:string;
copystr(buff,pchar('haha'+edit1.text); //使用方法

copystr(buff,pchar(string1); //
 
谢谢Beta精彩而生动的讲解,谢谢。不过,
能否将String的存储结构小结一下? 谢谢

整理一下:
**************************************************************************
一、
我觉得,所有的变量(包括对象)都是这样被系统处理的: 如:
I : Integer; 我觉得系统是这样处理的:
首先给这个定义I一个标号,如 : 0012001 ,这个标号指向程序所用堆栈中的一个地址
然后再使用变量I .使用时,从 I---0012001----该地址
“首先给这个定义I一个标号“----这个标号由系统内部自动给出且唯一,它对应一个堆栈中的
单元 。 如第一个定义的变量可以为: 001,对应堆栈中专门用来存储变量的区域的第一个
单元 。
(对“指针“类型来说,该地址中存放的依然是一个地址值)
这样以来,这个标号就唯一的指向了一个单元。
这种想法对吗?可否给我讲一下系统如何处理变量?

还有, 1. Pipo :"对象实例也是指向堆中的一个指针一样"----能否详细解释讲一下,
谢谢您
2. 关于引用,见给Vine的回复 (上面第二条)


**************************************************************************
二、
“ Label2.Caption := Pchar(Pos('a','abc')); //编译无错,运行出错
Label2.Caption := Pchar(IntToStr(Pos('a','abc'))); //编译无错,运行无错

难道Pchar只能对 String作类型转化?“
--------------------------------------------------------------------
jsxjd,:
Pchar(Pos('a','abc')); 并不指向真正的串,它的值是 1
这个地址是程序无法访问的。
------这个解释对这个例子是适用的,不过我想知道Pchar是否只能对 String作类型转化?
如果作为一种强制转换,Pchar应该可以对所有类型作用(我记得其他强制类型转换都可以
作用在各种类型上--------是不是这样的?)。
***************************************************************************
三、
vine : 您好,
1 . //S2 现在改变了,所以它被复制到自己的物理空间,并且S1 的引用计数减1
S2:=S2+'completely diff e r e n t 1 ' ;
为何S1的引用次数会减 1? 引用次数如何计算?
2 引用与指针相同吗? 书上说一个变量的别名就是它的引用 ,即意味着用不同的名字
访问同一个变量内容。(但有的书中又说引用就是指针,不同的语言也有不同的说法)
*****************************************************************************
四、
有的书上写着: Pchar是字符串类型
---------请问这样讲是不是合理? 我觉得大家都愿意将Pchar视为一个
强制指针转换,我更认同我的一个前辈说的: String与Pchar可以通用 ;


谢谢大家的指导,谢谢,欢迎继续,谢谢
 
但转换后要有意义,否则很可能形成一个不可访问的地址!
所有的整数不但可以转换成 pchar ,也可转换成其它的指针类型。
以下程序很可能运行时出错:

procedure TForm1.Button2Click(Sender: TObject);
var
p:pchar;
i:integer;
begin
i:=$100;
p:=pointer(i);
showmessage(p)
end;

 
大家累不累,string 就是字符串,只是赋值时不copy,而copy 它的指针,当改变时才copy
,这只是一种优化技术,s1:=s2,你就可以把它当作完全地copy .其实什么变量没有指针啊?
哪不过是编译器的事,我们就把它当作一个字符串变量就可以了。
 
顶部