关于字符串和动态数组的 Delphi 试题,目前贴出第一部分,答对者有分,全答对者100分!(300分)

  • 主题发起人 LiChaoHui
  • 开始时间
别人都回答过了,我就不献丑了,呵呵
 
题目不错!
 
1. abcde->mbcde
2. abcde->vbcde->mbcde
3. abcde->vbcde->mbcde(S2:=S1将S2的指针指向S1的数据空间相当于引用)
4. S1为AAA...(共20个)+#0+abcde长度共为26 S2的长度就是S1的长度
5. PChar型以#0结尾所以S2的长度是20
6. S1长度'hello world.'+3个空字符串=15
Dec(Byte(S1[0]), 3)去掉3个空字符串S1长度改为12
显示hello world.和Length('mello world.'+#0#0#0)=15
7. S的长度为15 Move(s, PChar(s2)^, Length(s)) 通过移动指针给S2赋值
S2[8]:=#0后 S2为abcdefg+#0+ijklmn
显示zbcdefghijklmn:714
8. S1为MMMMMMMMMM S2, S3与S1内容相同(S2赋值, S1引用)
显示BMMMMMMMMM

用时25分钟
 
记得以前的故事吗?
老师要求求出12:00以后下一次时针跟分针重合的时间
美国学生直接调手表
中国学生开始列公式

有必要研究这些问题吗?
 
没有手表的美国学生怎么办!?
有的问题还是弄清楚的好!--不知道原理做事情肯定很累!
-------------
以上问题我不会,听各位大侠解释!
 
对不起。^_^ 给个没面子的吧 : (
1。
是局部变量,不会初始化,将出现乱码abcdeXXXXXX
2。
还是乱码vbcdeXXXXXXX
3.
vbcde
4.
20
5.
20
6.
12
7.
有异常,不能显示结果

8。
乱码
BXXXXXX
 
1.猜想应该是'mbcde',但实际出错。再加一句SetLength(S,Length(S))则正常
结论:Delphi的写时复制原则作祟
2.-6没搞错
7.有点复杂
8.学习了,一想就明白了,就是PChar嘛!但乍一看搞成静态数组了

学习,静等下一批问题

大家不要被String[0]表示长度所迷惑,只有ShortString才对
而Delphi中默认全是长字符串,除非你自己制定,所以..

在长字符串前边也有长度,但不是在String[0],还在前面
 

谢谢大家的参与,
此题目的目的是为了大家更能清楚细致地了解Delphi中的
字符串和动态数组,以便在使用的时候更准确更熟练
有人说,了解这些东西需要知道Delphi的语言的底层工作机制
没有多大用处,
但是,我所列出的问题,都是日常编程中经常会遇到的问题
特别是经常操作字符串和使用动态数组的程序员

在我了解了Delphi中的长字符串之后,我的确很佩服delphi中的字符串处理机制
这种机制允许字符串中出现#0子节,而不会被截断,
使得用Delphi的字符串可以保存任何数据而不会有所损失,
同时,分配内存之后不必考虑释放内存的问题,而不会造成内存泄漏
字符串的运算速度也大大提高,因为不必扫描串来获取字符的长度
同时,仍然可以完美的兼容C中的#0结尾字符串,
既有自己的优点,也完全兼容C字符串,因为Delphi长字符串的末尾有一个#0字节
正是为了兼容C串而使用的,
但是Delphi的字符串因为使用了一种特殊的内存管理技术,
出现了这样一种机制,赋值时增加引用计数,
修改时分配内存,
所以使用字符串作为缓冲区或分配的空间时,最好使用SetLength分配内存

动态数组采用了和字符串类似的内存管理技术
但是,和字符串不同的是,动态数组之间的赋值
会使两个或多个变量同时引用同一数组,修改其中的一个,另一个也同时变化
这一点和字符串的处理是不同的

之所以提出这些问题,是为了当大家需要分配内存的时候
使用字符串和动态数组会是一种更值得推荐的方式
可以动态改变大小,不必释放,不必考虑内存泄漏问题
 
下面给出题目的参考答案

1.mbcde 或 内存访问冲突
这句代码PChar(s)[0] := 'm';可能会内存访问冲突,
结论: 作为分配内存使用时,不要用字符串常量来初始化字符串变量

2.mbcde
代码和1题差不多,但是一个赋值语句引起了字符串的修改时分配内存的机制
分配了新的空间,所以可以安全的运行

3.mbcde
由于字符串的修改时访问机制,字符串刚赋值后,实际上是指向同一块内存
只是增加了引用值,所以用这种方式修改字符串2,也就是修改了字符串1

4.26
相必大家都可以做对,我就不用解释了

5.20
注意,这种操作在编程中和4题的结果是不同的,注意两者的区别

6.hello world.15
注意,字符串赋值时复制的字符数只和字符串的长度有关,同时注意短字符串
和长字符串在0位置元素上的区别,短字符串的实际长度有0位置的字符决定

7.zabcdefghijklm:714
注意字符串在传递给无类型可变参数时的区别,
短字符串变量的地址实际表示0元素的地址,传递给无类型参数时
应写为S[1], 而长字符串是一个指针,
指向一个字符串变量的数据区,传递给无类型参数时,
应为PChar(s)^ 或者 s[1]

8.1个B和9个M,后面可能会有不可预料的内容出现
因为没有#0结尾,同时注意 Move(s1, s2[0], 10);
s1是短字符串,引用s1会发生内存溢出,
修改s3也相当于修改s2

上面是题目的参考答案,因为题目出的不好,所以答案也有点怪
如果不同一上面的答案,可以写出自己的答案,并说明原由

分数的发放为大队一道题10分,没有全对的
不过有人做的基本上都对了,自己看一下吧,过两天结帖

 
初步的分数分配:
firstrose,30
wr960204,30
lb_icesea79,50
秀,20
zjan521,20

上面的分数如果觉得不合理,可以提意见,可以再给
分数说明不了什么问题,我刚开始也就做对了3道题而已
关键是,大家能从这几道题目里面了解些东西
我讲得很不细致,看谁可以再补充一下

另外有一个问题: 使用Length获取短字符串的长度是否有潜在的问题?
讨论有分!
 
LiChaoHui,是这样的。

Pascal/Delphi中字符串(String)在内存里存储时,第一个字节为字符串的长度(编
程者不能直接看到),后面才是字符串的内容。这也是String最长为255个字符的原因
了。

不过因为没有运行,所以我只好按此理解猜,对不起你的30分了。
 
长字符串的定义:A_Long_Str: String;
短字符串的定义:A_Short_Str: String[200];
两者的存储结构完全不同,内存分配机制也不同
短字符串和C串并不兼容
 
A ShortString is 0 to 255 characters long.
While the length of a ShortString can change
dynamically, its memory is a statically
allocated 256 bytes
the first byte stores
the length of the string, and the remaining
255 bytes are available for characters.
If S is a ShortString variable, Ord(S[0]),
like Length(S), returns the length of S

assigning a value to S[0], like calling SetLength,
changes the length of S. ShortString uses 8-bit ANSI
characters and is maintained for backward compatibility only.
 
Length来取短字符串的长度当然没问题。
短字符串---------于老式Pascal保持兼容而保留的
type
ShorString=record
Length:Byte;//长度
data:array[1..Length] of char

end;
标准字符串---------最为先进的字符串,即兼容C又有很好的生存期管理
AnsiString=record
allocSiz:LongWord;//分配长度
useCount:LongWord;//引用次数
Length:LongWord;//实际长度
data:array[1..Length+1] of char;//因为后面还有一个#0

end;
宽字符串---------兼容宽字符集的字符串,但不能生存期管理
WideString=record
allocSiz: LongWord
//分配的大小
Length:LongWord
//字符串长度
Data:array[1..Length+1] of WideChar;//因为后面还有一个宽字符的#0
end

PChar类型就是字符型指针无甚好说---------字符指针和C的字符串保持兼容
PChar=^Char;
动态数组----------和标准字符串很相似
PDarray=Darray
DArray=record
useCount:LongWord;//引用次数
Length:LongWord;//实际长度
data:array[0..Length-1] of 数组元素数据类型

end

例如
var
q:array of integer;
p:pLongWord;
begin
Setlength(q,10);
P:=@q[0];
dec(p);
showmessage('动态数组长度'+inttostr(p^));
dec(p);
showmessage('动态数组引用次数'+inttostr(p^));
end
 
能解释第一题的原因吗?
 
第一题中的字符串赋值,将一个常量字符串赋值给一个字符串变量
但实际上,字符串变量并没有分配空间,仅仅是引用了常量字符串
所以此时用PChar(s)[0] 来访问字符串内容时,访问的是内存中常量字符串的位置
读取也许没有问题,但是可能这块内存不允许写,则会出现异常

此题的答案,应该是内存访问冲突(事实如此)
但是考虑到常量数据区不一定必须受到严格的写保护,
所以,也有可能修改成功,此时则会显示mbcde的结果

这正是第一题答案的由来
 
//使用Length获取短字符串的长度是否有潜在的问题?
我认为有,用户可能手动设置字符串中间的某字符为 #0 以截断字符串(的显示),
或者根本就直接改 S[0] 以修改长度标志。

不知道你所谓的潜在问题是不是担心的这个?
 
procedure TForm1.Button1Click(Sender: TObject);
var
aStr,bStr:ShortString;
begin
aStr:='abcdef';
bStr:='abcdef';
Setlength(aStr,3);
aStr[0]:=Chr(3);
Caption:=IntToStr(Length(aStr));
end;
对短字符串,只有第一字节表示了长度,所以上边显示为3
好像是个问题,可是长字符串也一样,如果你随意修改的话。只是好像不是那么容易
 

Similar threads

I
回复
0
查看
461
import
I
I
回复
0
查看
760
import
I
I
回复
0
查看
594
import
I
I
回复
0
查看
499
import
I
I
回复
0
查看
548
import
I
顶部