对Array Of PChar赋值的问题

rootwuyu 2011-06-29 05:45:42
环境:delphi2007+win7
代码:

Const
count: Integer = 10;
Var
i: Integer;
sArray: Array[0..10] Of PChar;
Begin
For i := 0 To count - 1 Do
sArray[i] := PChar('名称'+IntToStr(i));
For i := 0 To count - 1 Do
Memo1.Lines.Add(sArray[i]);
End;


这段代码,我预想得到的应该是
名称0
。。。
名称9

结果实际得到的

名称
名称9
名称
名称9
名称
名称9
名称
名称9
名称
名称9

把数据类型由array of pchar改成array of string就没事了

哪位兄弟百忙之中能帮忙一下?
...全文
169 11 打赏 收藏 转发到动态 举报
写回复
用AI写文章
11 条回复
切换为时间正序
请发表友善的回复…
发表回复
CaiBirdy 2011-07-01
  • 打赏
  • 举报
回复
windows有大量返回不确定长度的指针缓存函数,他们都是如此实现的
就是参数,不仅有指针,还有长度,如果传入的指针长度不够或者指针为空,
函数会返回实际需要的长度,并且错误结果返回长度不够错误。
Seamour 2011-06-30
  • 打赏
  • 举报
回复
由哪个模块写申请和释放的代码不重要,只要由同一个模块提供就可以。你的提供的接口可以要求使用者自己申请内存,什么时候释放就是使用者自己的事儿了;也可以在你写的模块里申请内存,然后再提供一个专门用于释放的函数。

delphi 的函数返回值类型不能是 array of T 的形式,但你要是这样写接口:

type Tfoo = array of T;
function bar: Tfoo; stdcall;


typedef T* Tfoo;
Tfoo __stdcall bar(void);

那你就等着挂吧,因为 bar 的声明实际上应该翻译成

void __stdcall bar(void*);


另外,你用 delphi 做测试反倒容易出问题,因为 delphi 的类型信息是完整的,翻译器会做许多没用的工作。实际上,参数中传 PAnsiChar 的地方直接传 AnsiString 完全没问题(返回值类型就完全不一样了)。TClassNumberArray 也同理,直接当 TClassNumber * 用没问题,但如果人家传进来一个没清0的 TRetFindAllByStation 就挂了。

如果你不了解 packed 的作用,那你就别乱加了。你这里写出来的声明加不加 packed 没影响;有些情况下你这边加了,c 那边还得 #pragma pack(1)。不知道谁教出来的,没事儿闲着一弄接口就瞎加 packed,这年头明明是加了麻烦更大。

顺便再说一下,前两天看到的一句话,说调试的难度要比写代码难一倍以上。所以如果写程序都费劲的话,那就没有足够的能力再去调试了。
写接口的时候,其实也完全可以用 delphi 自动管理生存期的类型,能少写不少代码。但如果不了解自己写的代码真正意味着什么的话,出错的概率也就更大了。从你问的问题来看,我建议你还是老老实实的用基本类型吧,string、array of T 什么的就不要用了。虽然写的时候很麻烦,也更容易出错,但至少这样的错误还是比较容易调试的。要不然出了问题你都找不出来是哪错了
ZyxIp 2011-06-30
  • 打赏
  • 举报
回复
function xx():Array of PChar;

function xx(res:Pointer;Len:Integer):Integer;
begin

end;

我觉得最好的原则是:如果谁调用,那就谁分配,最后由谁自己释放。
VC调用时,先分配一个够大的内存,然后将长度给用户,用户使用后将使用的长度给返回。




taste品味 2011-06-30
  • 打赏
  • 举报
回复
指针类型要申请内存空间
rootwuyu 2011-06-29
  • 打赏
  • 举报
回复
多谢楼上诸位的指点,的确是内存分配造成的问题!

借着这个贴再厚脸皮请大家再指点一下。

类似顶楼的问题,如果在一个dll中定义一个类似下面的函数

function xx():Array of PChar;

这个函数返回的数组维数是不确定的,通常会在函数内部,调用java实现的webservices后才能得到。

问:
1、对PChar的内存分配应该在dll内部,还是在外部的主程序里面?
2、与内存分配相对应的,释放应该在dll内部还是在外主部程序里面?


另:在2楼的我介绍了一下真实的需求情况,4楼的兄弟提到“你的结构里 TClassNumberArray 的性质和 string 是一样的,用 TClassNumberArray 不会出问题的话,用 string 也一样不会出问题”。

在这儿解释一下:目前做的还是只我们delphi与delphi dll调用的测试结果,还不知道最后交给对方用vc++调用的时候会不会成功。包括TClassNumberArray 的定义也不知道是不是可行的。甚至就是record是加packed还是不加也不确定。

哪位兄弟有类似的经验,帮忙指点一下?



ZyxIp 2011-06-29
  • 打赏
  • 举报
回复
sArray: Array[0..10] Of PChar;
数组长度为11,每一个的值为PChar ,只是一个指针,指针指向的都是无效的数据。

而你是想保存实际的数据,所以你要为每个指针分配内存

Const
count: Integer = 10;

Var
i: Integer;
sArray: Array[0..10] Of PChar;
Begin
For i := 0 To count Do //应该是10,你的数据长度为11
begin
sArray[i] :=GetMemory(5); //分配内存 '名称' 占4,数据占1
StrPCopy(sArray[i],('名称'+IntToStr(i))); //将值复制到分配的内存中。
end;
For i := 0 To count - 1 Do
mmo1.Lines.Add(sArray[i]);

For i := 0 To count Do //最后释放分配的内存。
FreeMemory(sArray[i])

End;
sun79915 2011-06-29
  • 打赏
  • 举报
回复
你这是因为字符串自动将内存回收了
也就是sArray[i] := PChar('名称'+IntToStr(i));这句以后,这个字符串分配的内存被DELPHI回收了,下一句又在这个内存上地址上做了新的分配,如果你不调inttostr的话,那所有的结果都应该是一样的,不一样是因为inttostr让内存产生了一个偏移,所以你的结果是循环出现的

解决办法也简单,给他们分配一下内存,加两个函数就可以了
sArray[i] := strnew(PChar('名称'+IntToStr(i)));

begin
Memo1.Lines.Add(sArray[i]);
StrDispose(sArray[i])
end;
Seamour 2011-06-29
  • 打赏
  • 举报
回复
你的结构里 TClassNumberArray 的性质和 string 是一样的,用 TClassNumberArray 不会出问题的话,用 string 也一样不会出问题
CaiBirdy 2011-06-29
  • 打赏
  • 举报
回复
没申请内存,

Const
count: Integer = 10;
Var
i: Integer;
sArray: Array[0..10] Of PChar;
Begin
For i := 0 To count - 1 Do
begin
sArray[i]:= allocMem(128);
Move(PChar('名称'+IntToStr(i))^, sArray[i]^, Length('名称'+IntToStr(i)));
end;
For i := 0 To count - 1 Do
begin
Memo1.Lines.Add(sArray[i]);
FreeMem(sArray[i]);
end;
End;

rootwuyu 2011-06-29
  • 打赏
  • 举报
回复
[Quote=引用 1 楼 seamour 的回复:]

你还是老老实实用 string 吧,PChar 又要分配空间又要释放,string 就什么都不用自己手动做
[/Quote]

起因是跟一家公司有个对接任务,我们有java上开发的webservices,不方便直接将ws提供给对方,需要用delphi封装成dll,供对方的vc程序调用。

我们在delphi中定义

TClassNumber = Packed Record
id: PChar;
name: PChar;
code: Pchar;
date: PChar;
time: PChar;
sites: Integer;
End;
TClassNumberArray = Array Of TClassNumber;

TReturn = Packed Record
RetNumber: Integer;
RetCode: PChar;
RetMessage: PChar;
End;


TRetFindAllByStation = Packed Record
Result: TReturn;
ClassNumberArray: TClassNumberArray;
End;

Procedure FindAllByStation(Const station, date, time: PChar; Var RetFindAllByStation: TRetFindAllByStation); export; stdcall;




在用delphi写程序测试dll的时候发现取出来的PChar内容乱得一蹋糊涂,才有了顶楼的测试代码。

问题肯定是由PChar使用不正确引起的。不过,由于我们本身善长的是java,delphi平时只是用来做一些小东西,没多大经验,不知道要怎么用才会避免这类问题。
Seamour 2011-06-29
  • 打赏
  • 举报
回复
你还是老老实实用 string 吧,PChar 又要分配空间又要释放,string 就什么都不用自己手动做

16,749

社区成员

发帖
与我相关
我的任务
社区描述
Delphi 语言基础/算法/系统设计
社区管理员
  • 语言基础/算法/系统设计社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧