我是Delphi语言的一个新手,最近在使用Pascal语言上遇到点困惑,请高人指教。
在代码中定义一个函数,返回局部String变量对应的字符串地址:
function RetChar: PChar;
var
str: String;
begin
str := 'Hello, world!';
result := PChar(str);
end;然后在Button的OnClick事件中调用:
procedure TForm1.Button13Click(Sender: TObject);
var
pStr:PChar;
tmp:String;
begin
pStr := RetChar;
tmp := pStr ;
ShowMessage(tmp);
end;
竟然运行正常,按理说返回局部String变量的字符串指针后,String变量的引用计数变为0,String变量内部字符串所占内存会被回收,为什么这样竟然能运行成功呢?
在代码中定义一个函数,返回局部String变量对应的字符串地址:
function RetChar: PChar;
var
str: String;
begin
str := 'Hello, world!';
result := PChar(str);
end;然后在Button的OnClick事件中调用:
procedure TForm1.Button13Click(Sender: TObject);
var
pStr:PChar;
tmp:String;
begin
pStr := RetChar;
tmp := pStr ;
ShowMessage(tmp);
end;
竟然运行正常,按理说返回局部String变量的字符串指针后,String变量的引用计数变为0,String变量内部字符串所占内存会被回收,为什么这样竟然能运行成功呢?
解决方案 »
- 请教关于DLL的两个问题:能否建立一个有Form的DLL,代码直接显示
- 我写了一个键盘记录,但是怎么控制键盘记录的开关?
- 报表导EXCEL中,的问题
- 数据库数据无法显示在窗口,在线等!
- delphi7一向好好的,今天告诉我不能用了,大家看看怎么解决这个问题呢?
- 如何实现聂象头获取视频图象到图片框?在线等不够可加分
- 请问怎样可以让 DBgrid 的其中一个 column 显示的是 Checkbox 控件?
- 很常见的查询功能如何实现?
- 李维《Delphi7高效率数据库程序设计》附书光盘中怎么找不到ChineseDemo.gdb数据库文件?
- 看看这样的东东有没有?
- 新手求教 delphi 中在一个窗体的特定区域嵌入另一个窗体
- 这个点餐界面用什么方式实现最优了?
我还做过这样的实验:
procedure TForm1.Button13Click(Sender: TObject);
var
pStr:PChar;
tmp:String;
arr:Array[0..100000] of TStringList;
begin
pStr := RetChar; for i:=0 to 99999 do
begin
arr[i] := TStringList.Create;
arr[i].Add('hello,world');
end; tmp := pStr ;
ShowMessage(tmp);
end;这次动态申请的内存应该够大了,程序依然能够运行成功。
function RetChar: PChar;
var
str: String;
begin
str := intostr(random(1000))+'Hello, world!';
result := PChar(str);
end;
输出前多执行一次这个函数,试一试
var
str: String;
begin
str := intostr(random(1000))+'Hello, world!';
result := PChar(str);
end;
这样输出很不安全
function RetChar: PChar;
var
str: String;
begin
//下面这行根本不是变量,引号中“写死的”是常量,亲
//'Hello, world!'不是动态产生的,而是在编译时就已经确定了
//下面只是把str指向了这个常量,亲
str := 'Hello, world!';
result := PChar(str);
end;你想要的代码在此:
function RetChar: PChar;
var
Str,S1,S2: String;
PI:PInteger;
begin
SetLength(Str,3);
Str[1]:='a';
Str[2]:='b';
Str[3]:='c';
S1:=Str;
S2:=Str;
Pointer(PI):=PChar(Str);
Dec(PI);
ShowMessage(Format('常量的长度为:%d',[PI^]));
Dec(PI);
ShowMessage(Format('常量的引用计数为:%d',[PI^]));
Result:=PChar(Str);
end;函数结束后,为了效率PChar(Str)这个地址只是被标记为可用;
类型于硬盘删除文件,只是标记此段空间可用,
而不会执行FillMemory();将此段内存清空,这会影响效率。
//上面应该改为:
ShowMessage(Format('长度为:%d',[PI^]));
Dec(PI);
ShowMessage(Format('引用计数为:%d',[PI^]));“类型于”打错,应该是“类似于”
var
Str,S1,S2: String;
PI:PInteger;
begin
str:='Hello, world!';
S1:=Str;
S2:=Str;
Pointer(PI):=PChar(Str);
Dec(PI);
ShowMessage(Format('常量的长度为:%d',[PI^]));
Dec(PI);
//注意:常量的引用计数为-1
ShowMessage(Format('常量的引用计数为:%d',[PI^]));
Result:=PChar(Str);
end;
正解,测试发现通过SetLeng(str,3),然后逐个字符赋值后,RetChar返回后,申请一大段内存,然后测试返回的字符串为空,应该是被FillMemory了,结贴...
//'Hello, world!'不是动态产生的,而是在编译时就已经确定了
常量在编译时就已经确定,而且生命期与进程相同,要在进程结束时才会被释放。