TfileStream中的read函数参数疑惑?
该read函数说明:read(Var BUF;Size:int64);
BUF代表缓冲区(始址??)SIZE为从某文件流中读取数据到缓冲区的字节数。
我有一STRING变量:S:setlength(s,20);
下为出错代码:
tfileStream.create(filename).read(s,10):编译能通过,但运行到该句后发生ACCESSViolation异常。
修改后:tfileStream.create(filename).read(pointer(s)^,10);运行正常??!!
请各位大侠不吝指教,谢谢了!!
问题点数:50、回复次数:18Top
1 楼zsjzwj(北极熊)回复于 2005-10-17 10:23:07 得分 0
function Read(var Buffer; Count: Longint): Longint; override;
property Buffer: PChar;
因为你的变量s是string类型,需要转换为CHAR类型才可以用Top
2 楼alexanda2000(书生活)回复于 2005-10-17 10:26:24 得分 0
tfileStream.create(filename).read(s[1],10);Top
3 楼ThinkInDelphi(wwwwww)回复于 2005-10-17 10:48:11 得分 0
谢谢zsjzwj的分析。他找到了问题所在,只是不详细:string默认是AnsiString,一个4字节的指针。PCHAR是一个NULL-TERMINATE类型(以#0结尾)的字符串。(应该和AnsiString一样是一个4字节的指针?)同样是指针,为何有区别?
感觉alexanda2000更进了一步,s[1]为字符串第一字符。但BUF一般是指针啊?我就是这个不理解?!Top
4 楼alexanda2000(书生活)回复于 2005-10-17 10:54:05 得分 0
string实际上就是指针,也是以#0结尾,只是它指向的不是第一个字符。S[1]才是它的字符开始的地方。Top
5 楼alexanda2000(书生活)回复于 2005-10-17 10:55:48 得分 0
tfileStream.create(filename).read(s,10)实际上将流的数据写入了字符串用来存储其它相关信息的地方,所以就会出错了。Top
6 楼ThinkInDelphi(wwwwww)回复于 2005-10-17 10:56:00 得分 0
另外我用“S^”来指定第一个字符,不用s[1],编译都有问题.为什么??(我以前的C语法在Delphi老是不管用!)类似C中:string S;
printf(%c,*S)与printf(%c,S[0])一样的吧?Top
7 楼ThinkInDelphi(wwwwww)回复于 2005-10-17 11:01:01 得分 0
看一下read定义:
function Read(var Buffer; Count: Longint): Longint; override
BUffer显然是一个指针啊!
S[1]是个字符。这能对吗??Top
8 楼lyre(大头鬼)回复于 2005-10-17 11:04:31 得分 0
S[1]可以用,但最好用PChar(s)来取得首地址,切记要先使用SetLength给字符串分配空间,否则还是有可能访问非法地址。另外,Delphi的语法与C不一样,C当中数组和指针是一回事,但在Delphi中不是,更何况String类型并非数组。Top
9 楼ThinkInDelphi(wwwwww)回复于 2005-10-17 11:04:56 得分 0
注意pointer(s)^应该也表示S中第一个字符?或是其他?
另外tfileStream.create(filename).read(s[1],10);是不是能运行正常,我还没试过呢,明天给答案:-)Top
10 楼lyre(大头鬼)回复于 2005-10-17 11:05:58 得分 0
对于你的要求,最好自定义一个字符数组作为Buf:
var
Buf: array[0..1023] of char;Top
11 楼ThinkInDelphi(wwwwww)回复于 2005-10-17 11:07:32 得分 0
s[1]是指针?????????!!!
头脑短路中........Top
12 楼ThinkInDelphi(wwwwww)回复于 2005-10-17 11:15:49 得分 0
S[1],s[1],s[1]...........
to lyre:你的方法是对的,数组名是指针。那字符串名到底是不是指针??
“C当中数组和指针是一回事,但在Delphi中不是”说得具体点~~
Top
13 楼lyre(大头鬼)回复于 2005-10-17 12:34:22 得分 0
Delphi是强类型的语言,不像C中指针和数组可以通用,虽然实际上数组名作为一个变量来说,确实有一个对应的内存地址,而且你把它强制转换为指针后,访问的内容也是正确的。
Delphi中的字符串实际上是以前Pascal短字符串与C的以0结尾的字符串的一种综合体,也就是说,最前面有几个字节保存的是字符串的长度,然后是实际内容,最后又有一个结尾的0。Top
14 楼ThinkInDelphi(wwwwww)回复于 2005-10-17 12:48:59 得分 0
lyre说得没错,对于第二段内容我也了解。(第一段精彩!)
回到问题:
那s[1]是不是指针?
BUF指得是一个指针变量?
如果BUF是指针,那Pointer(S)^代表的是一个字符还是指针?[参数类型匹配吗?]
S^与Pointer(S)^的区别?(STRING指针与无类型指针我知道(都4字节),但不能替换使用,否则上面程序异常。难道这就是所谓“强类型”?)
Top
15 楼lyre(大头鬼)回复于 2005-10-17 14:48:24 得分 25
S[1]不是指针,而是指字符串的第1个字符。你注意read的定义:
read(Var BUF;Size:int64);
其中的Buf是一个无类型参量,这种情况下调用时不限参数类型。另外Buf是作为var定义的,传递参数时是将参数的地址传进去的。(实际上无类型参数也只能用var来定义。)C语言这种情况下需要&符来取址,Delphi不需要。
read(s[1], ..); ==>传入S[1]的地址。因为String类型的第一个字符下标从1开始,所以S[1]的地址也正是字符串正文开始的地址;
S虽然实际上是个指针,但这是对Delphi而言的,在引用的时候Delphi会循着S指明的地址依次找到字符串长度、内容、结尾的0等;对用户而言它是一个语言内建的数据类型而不是指针,所以S^的写法是错误的。
如果你把S强行转化为指针,将Pointer(S)^作为参数传给Read的时候,它实际指向字符串开头的字符串长度所在位置,你往这里写东西,当然就破坏了字符串的结构了;Top
16 楼alexanda2000(书生活)回复于 2005-10-17 15:22:32 得分 25
lyre(大头鬼)已经解释得很清楚了,read(Var BUF;Size:int64);中的buf是变参,read方法接收到的已经是buf的地址了,因此buf不需要传入指针变量。如果你真的传入一个指针,这个方法接收到的就是指针自身地址了,反而会出错。因此用s[1]作为buf的话,这个方法接收到的是s[1]的地址。
在Delphi中,数组不是指针,声明一个arr:array[0..12] of char,你看一下SizeOf(arr)就知道了。
PS:我觉得将Pointer(S)^作为参数传给read是可以的,因为Pointer(S)^表示了“S正文的内容”,它的地址应该和s[1]是一样的。Top
17 楼ThinkInDelphi(wwwwww)回复于 2005-10-19 12:32:18 得分 0
问题已经解决了。谢谢各位兄弟!!
分数将对半分给 lyre和 alexanda2000
另外 alexanda2000最后的回复是正确的,我已验证。原因我琢磨应该如下:
S作为一个“指针”来说,是一个指向STRING第一字符的指针,而不是指向长度值。
S作为一个字符串来说,S^不能用,即Delphi限制用户只能从s+1开始。
Pointer(S)^==s[1]
Top
18 楼alexanda2000(书生活)回复于 2005-10-19 14:55:08 得分 0
>>>S作为一个“指针”来说,是一个指向STRING第一字符的指针,而不是指向长度值。
错了,如果它真的指向第一个字符,就不用s[1]这么麻烦了。
《Delphi5 开发人员指南》中对字符串结构有比较详细的介绍。Top




