字符串与 Pascal 中的大量(数组)字符有何不同?
How strings differ from massive(array) of chars in Pascal?
我有问题。为什么我不能将字符串的值分配给字符串,但使用字符就可以了。为什么^^^^^^?字符串在哪里?为什么会有 a[i]?
是因为字符串和字符的内部表示吗?
program massive.pas;
type
chars = array [1..255] of char;
var
s,s1: string;
ch1,ch2: chars;
i: integer;
begin
s1 := '';
s := 'abrakadabra';
for i := 1 to 5 do
begin
s1[i] := s[i];
writeln(s1[i],#10,'^^^',s1,'^^^')
end;
ch2 := '';
ch1 := 'abrakadabra';
for i := 1 to 5 do
begin
ch2[i] := ch1[i]
writeln(ch2[i])
end;
writeln('%%%',ch2,'%%%');
for i := 1 to 5 do
writeln('&&&',s1[i],'&&&');
end.
*输出
a
^^^^^^
b
^^^^^^
r
^^^^^^
a
^^^^^^
k
^^^^^^
a
b
r
a
k
%%%abrak%%%
&&&a&&&
&&&b&&&
&&&r&&&
&&&a&&&
&&&k&&&
type chars = Array[1..255] of Char
和 String
的主要区别在于 chars
数组的长度是固定的,而字符串的长度是动态的。
你没有说你使用的是哪个编译器,但我确实认为 String
类型在某些 Pascal 版本中被称为 ShortString
,最大长度为 255 个字符。 255 个字符的 space 是预先分配的,结构包括一个长度字段,用于跟踪字符串的分配长度。
在您的示例中,您分配 s1 := '';
换句话说,长度设置为零。那么你在for loop
赋值s1[i] := s[i];
时出错,没有设置s1的长度.
s1
的后续读取总是 return 空字符串,因为长度字段为 0。
如果您将字符分配给字符串,例如如:
for i := 1 to 5 do
begin
SetLength(s1, Length(s1)+1);
s1[i] := s[i];
writeln(s1[i],#10,'^^^',s1,'^^^');
end;
那么结果就是你最初的预期。
最好将长度设置为 for loop
.
之前的最后 5 个
当然还有其他解决方案。一种是根本不设置长度,而是在循环中拼接字符串,让它自己处理长度字段:
for i := 1 to 5 do
begin
s1 := s1 + s[i];
writeln(s1[i],#10,'^^^',s1,'^^^');
end;
编辑 24.12.2021:
你在评论中说:但是我还是不明白,为什么我在for循环中写s1[1]的时候,都成功了?
...并且大概在 end.
:
之前参考这段代码
for i := 1 to 5 do
writeln('&&&',s1[i],'&&&');
我们要看一下内存布局就知道分配给s1
的内存的第一个字节就是字符串的长度。可以简称为s[0]
。后续字节包含组成存储字符串的字符,它们可以称为 s[1]..s[n].
你写的时候第一个字节设置为0(一开始):
s1 := '';
// memory content:
0
|_|_|_|_|_|_|_|_|_| ...
然后你在第一个for
循环中写入时通过直接操作内存将字符添加到s1
:
s1[i] := s[i];
// content after 5 characters
0 a b r a k
|_|_|_|_|_|_|_|_|_| ...
因为您没有使用连接(或在添加字符时调整了长度),所以长度仍然为 0。
然后在最后一个循环的最后,直接访问内存再次获取字符,得到的结果看似正确,但严重滥用了字符串结构。
我有问题。为什么我不能将字符串的值分配给字符串,但使用字符就可以了。为什么^^^^^^?字符串在哪里?为什么会有 a[i]? 是因为字符串和字符的内部表示吗?
program massive.pas;
type
chars = array [1..255] of char;
var
s,s1: string;
ch1,ch2: chars;
i: integer;
begin
s1 := '';
s := 'abrakadabra';
for i := 1 to 5 do
begin
s1[i] := s[i];
writeln(s1[i],#10,'^^^',s1,'^^^')
end;
ch2 := '';
ch1 := 'abrakadabra';
for i := 1 to 5 do
begin
ch2[i] := ch1[i]
writeln(ch2[i])
end;
writeln('%%%',ch2,'%%%');
for i := 1 to 5 do
writeln('&&&',s1[i],'&&&');
end.
*输出
a
^^^^^^
b
^^^^^^
r
^^^^^^
a
^^^^^^
k
^^^^^^
a
b
r
a
k
%%%abrak%%%
&&&a&&&
&&&b&&&
&&&r&&&
&&&a&&&
&&&k&&&
type chars = Array[1..255] of Char
和 String
的主要区别在于 chars
数组的长度是固定的,而字符串的长度是动态的。
你没有说你使用的是哪个编译器,但我确实认为 String
类型在某些 Pascal 版本中被称为 ShortString
,最大长度为 255 个字符。 255 个字符的 space 是预先分配的,结构包括一个长度字段,用于跟踪字符串的分配长度。
在您的示例中,您分配 s1 := '';
换句话说,长度设置为零。那么你在for loop
赋值s1[i] := s[i];
时出错,没有设置s1的长度.
s1
的后续读取总是 return 空字符串,因为长度字段为 0。
如果您将字符分配给字符串,例如如:
for i := 1 to 5 do
begin
SetLength(s1, Length(s1)+1);
s1[i] := s[i];
writeln(s1[i],#10,'^^^',s1,'^^^');
end;
那么结果就是你最初的预期。
最好将长度设置为 for loop
.
当然还有其他解决方案。一种是根本不设置长度,而是在循环中拼接字符串,让它自己处理长度字段:
for i := 1 to 5 do
begin
s1 := s1 + s[i];
writeln(s1[i],#10,'^^^',s1,'^^^');
end;
编辑 24.12.2021:
你在评论中说:但是我还是不明白,为什么我在for循环中写s1[1]的时候,都成功了?
...并且大概在 end.
:
for i := 1 to 5 do
writeln('&&&',s1[i],'&&&');
我们要看一下内存布局就知道分配给s1
的内存的第一个字节就是字符串的长度。可以简称为s[0]
。后续字节包含组成存储字符串的字符,它们可以称为 s[1]..s[n].
你写的时候第一个字节设置为0(一开始):
s1 := '';
// memory content:
0
|_|_|_|_|_|_|_|_|_| ...
然后你在第一个for
循环中写入时通过直接操作内存将字符添加到s1
:
s1[i] := s[i];
// content after 5 characters
0 a b r a k
|_|_|_|_|_|_|_|_|_| ...
因为您没有使用连接(或在添加字符时调整了长度),所以长度仍然为 0。
然后在最后一个循环的最后,直接访问内存再次获取字符,得到的结果看似正确,但严重滥用了字符串结构。