nil 和 空字符串的疑问(100分)

  • 主题发起人 主题发起人 GoodYes
  • 开始时间 开始时间
G

GoodYes

Unregistered / Unconfirmed
GUEST, unregistred user!
var
S: String;
P: PChar;

begin

S := ''; // 或者不赋值
GetMem(P, Length(S) + 1);
StrPCopy(P, S);

end;

上面这段代码产生的变量 P 是不是等于 nil ?

调用 ShellExecute 函数直接传入 nil 和传入经过刚才处理的P变量的效果是不是一样?
 
上面这段代码产生的变量 P肯定不等于 nil,你为它分配了长度为1的空间
StrPCopy(P, S);这句相当于没执行,因为Length(S) = 0
 
谢谢 foxphone2003
那么传给ShellExecute 空字符串 '' 、 nil 和 经过上面处理的 P , 在 ShellExecute 看来有差别吗?
我想传给他经过上面代码处理的P,可是担心和nil的效果不同,错误的调用了ShellExecute
 
''是字符串常量,为空
nil是指针地址,只不过很特殊,为0

ShellExecute中的参数都是PAnisChar,都是指针,建议使用'',
那样可以显式的调用字符串指针。代码读取比较容易,效果其实是一样的。
 
谢谢楼上的指点
大家再指点一下下面的代码,比起直接用 PChar(字符串) 的方法代码多了很多,
此过程的目的想减少重复给PChar申请内存空间的代码,这样以后直接调用此过程就可以了
大家帮忙看看有什么不妥的地方。

procedure OpenFile(hWnd: HWND; AOperation, AFileName,
AParameters, ADirectory: String; ShowCmd: Integer);
var
Operation,
FileName,
Parameters,
Directory: PChar;
begin

GetMem(Operation, Length(AOperation) + 1);
try
StrPCopy(Operation, AOperation);
GetMem(FileName, Length(AFileName) + 1);
try
StrPCopy(FileName, AFileName);
GetMem(Parameters, Length(AParameters) + 1);
try
StrPCopy(Parameters, AParameters);
GetMem(Directory, Length(ADirectory) + 1);
try
StrPCopy(Directory, ADirectory);

ShellExecute(hWnd, Operation, FileName, Parameters, Directory, ShowCmd);
finally
FreeMem(Directory);
end;
finally
FreeMem(Parameters);
end;
finally
FreeMem(FileName);
end;
finally
FreeMem(Operation);
end;
end;
 
你代码写这么长,实在是汗,非常简单的代码,被你写复杂了
procedure OpenFile(hWnd: HWND; AOperation, AFileName,
AParameters, ADirectory: String; ShowCmd: Integer);

function TranslateStringToPChar(const S: string): PChar;
begin
if S <> '' then Result := PChar(S)
else Result := nil;
end;

begin
ShellExecute(hWnd, TranslateStringToPChar(AOperation),
TranslateStringToPChar(AFileName),
TranslateStringToPChar(AParameters),
TranslateStringToPChar(ADirectory), ShowCmd);
end;
 
回 zqw0117 朋友:
我之前也是用的 PChar('aaa') 这样的方式传递给ShellExecute,

可是我调用ShellExecute函数是在多线程的Execute 过程中。
通过多线程类的Create传入的PChar参数复制给类 私有PChar变量后就不正常了。
但是通过GetMem和后面的操作后就正常了。

而且我通过搜索大富翁以前的帖子,貌似建议用 GetMem 、 StrPCopy 、 FreeMem 操作
 
兄弟!!怎么说你好呢?实在是。。。不会变通。你在Create传入参数的时候,传string类型,在Execute里面执行ShellExecute的时候,再把保存从Create传入的参数的那个变量利用我写的TranslateStringToPChar来转换就可以了!
TMyThread = class (TThread)
private
Oper, Dir, App, Params: string;
protected
procedure Execute;
public
constructor Create(const AOper, ADir, AApp, AParams: string);
end;

constructor TMyThread.Create(const AOper, ADir, AApp, AParams: string);
begin
Oper := AOper;
Dir := ADir;
App := AApp;
Params := AParams;
inherited Create(False);
end;

procedure OpenFile(hWnd: HWND; AOperation, AFileName,
AParameters, ADirectory: String; ShowCmd: Integer);

function TranslateStringToPChar(const S: string): PChar;
begin
if S <> '' then Result := PChar(S)
else Result := nil;
end;

begin
ShellExecute(hWnd, TranslateStringToPChar(AOperation),
TranslateStringToPChar(AFileName),
TranslateStringToPChar(AParameters),
TranslateStringToPChar(ADirectory), ShowCmd);
end;

procedure TMyThread.Execute;
begin
OpenFile(0, Oper, App, Params, Dir, SW_SHOWNORMAL);
end;
 
谢谢 zqw0117
我现在想弄明白为什么PChar在线程类之内经过两次传递后会变得不正常,因为这个所以我怀疑PChar的正确性。所以最后用了GetMem的方法。

现在我想知道PChar到底被不被推荐。
 
PChar并不会因为线程里面两次传递而异常,关键的问题是string类的内存计数。string实际上就是一个PChar结构,只不过稍微复杂一点,前面有4个字节的长度,和4个字节的引用计数,当你执行
S1 := S2
这样的代码的时候,S1并不是S2的一份拷贝,而是指向S2,而S2的引用计数+1,这样,当S1的作用域失效后,S2的引用计数会-1,直到S2的引用计数是0的时候,S2被释放。

你在线程中出现的问题,实际上就是引用计数少计了,因为你启动线程的时候,传递PChar(S)过去,并不会让S的引用计数+1,而S出了你调用线程的那个方法后,S的引用就会-1,而这个时候,实际上你的线程还在指向S的地址做访问,而S可能已经释放了!就这么简单。

所以,给线程传string最保险,只有线程退出后,传进去的S的引用计数才会-1,保证在线程使用这个string的时候,string还存在于内存中!这样就ok了。
 
哦,有点明白,那么PChar(S)中的S如果是全局String变量,是不是就不会异常了?
 
一般的,nil为0,null为空,但是不同的编译器会有一个初始值!
 
谢谢各位,尤其非常感谢 zqw0117 !
 
多人接受答案了。
 

Similar threads

S
回复
0
查看
1K
SUNSTONE的Delphi笔记
S
S
回复
0
查看
916
SUNSTONE的Delphi笔记
S
S
回复
0
查看
850
SUNSTONE的Delphi笔记
S
后退
顶部