delphi - 为什么这两个 Delphi 代码块的行为不同?
问题描述
第一个代码块中注释的两个部分看似相同,但产生不同的结果(由于其他地方的问题)。我不明白它们有何不同。我唯一改变的是注释掉第一部分(for循环)或第二部分(赋值行)并得到不同的结果。
var
Amount: Integer;
I: Integer;
begin
Amount := 3;
// This produces undesired results (**the for loop**)
for I := 0 to Amount-1 do
CharDataBool[I] := CharToArray(CharDataText[I]);
// This works as expected (**the assignment lines**)
CharDataBool[0] := CharToArray(CharDataText[0]);
CharDataBool[1] := CharToArray(CharDataText[1]);
CharDataBool[2] := CharToArray(CharDataText[2]);
下面的代码有问题的做法,在某种程度上是问题的根源,但我的问题是关于上面的代码。仅当 CharToArray 函数未分配 false 时才会出现上述问题,如下所示:
function CharToArray(Source: TCharDetails): TCharArray;
var
X, Y: Integer;
begin
SetLength(Result, Source.Width, 10);
for Y := 0 to 9 do
for X := 0 to Source.Width-1 do
if Source.S[Y*Source.Width+X] = 'x' then
Result[X,Y] := true
else Result[X,Y] := false; // Adding this solves the problem
end;
没有进入“留下未知的值真的很糟糕”,我只想了解为什么问题在第一部分代码中出现(for循环)而不是(赋值行)?三个赋值行与 for 循环有何不同?
下面可以复制到默认 VCL 项目中的 Unit1
unit Unit1;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;
type
TForm1 = class(TForm)
private
{ Private declarations }
public
{ Public declarations }
end;
type
TCharArray = array of array of boolean;
TCharDetails = record
S: String;
Width: Integer;
end;
var
CharDataText: array of TCharDetails;
CharDataBool: array of TCharArray;
var
Form1: TForm1;
procedure Init;
implementation
{$R *.dfm}
function CharToArray(Source: TCharDetails): TCharArray;
var
X, Y: Integer;
begin
SetLength(Result, Source.Width, 10);
for Y := 0 to 9 do
for X := 0 to Source.Width-1 do
if Source.S[Y*Source.Width+X] = 'x' then
Result[X,Y] := true;
end;
procedure Init;
var
Amount: Integer;
I: Integer;
X,Y: Integer;
S1, S2: String;
begin
Amount := 2;
SetLength(CharDataText, Amount);
SetLength(CharDataBool, Amount);
ChardataText[0].Width := 10;
ChardataText[0].S :=
// 1234567890
' ' + // 0
' x ' + // 1
' xx ' + // 2
' x ' + // 3
' x ' + // 4
' x ' + // 5
' x ' + // 6
' x ' + // 7
' x ' + // 8
' xxx ';
ChardataText[1].Width := 10;
ChardataText[1].S :=
// 1234567890
'x ' + // 0
' xxxx ' + // 1
' x x ' + // 2
' x ' + // 3
' x ' + // 4
' x ' + // 5
' x ' + // 6
' x ' + // 7
' x ' + // 8
' xxxxxx x';
for I := 0 to Amount-1 do
CharDataBool[I] := CharToArray(CharDataText[I]);
S1 := '';
for Y := 0 to 9 do
for X := 0 to 9 do
S1 := S1 + CharDataBool[1,X,Y].ToString;
CharDataBool[0] := CharToArray(CharDataText[0]);
CharDataBool[1] := CharToArray(CharDataText[1]);
S2 := '';
for Y := 0 to 9 do
for X := 0 to 9 do
S2 := S2 + CharDataBool[1,X,Y].ToString;
// S1 != S2 ??
ShowMessage(S1 + #13 + S2);
end;
initialization
Init;
end.
解决方案
函数返回值是托管类型。不保证在Result
进入函数时重新初始化。
在循环示例中,编译器优化了Result
迭代之间的隐式本地重新初始化。这意味着数组的先前内容仍然存在并且必须清除。
作为一般规则,总是在进入时初始化=清除托管函数结果。
在这种情况下,调用SetLength(Result,0,0);
函数中的第一件事。
请参阅是否需要在初始化时设置动态数组?例如。
推荐阅读
- python - 限制数据帧字符长度
- vba - 如何仅使用循环和 if 语句制作此消息框?
- arrays - 如何在 numpy 对象数组中找到最小/最大对象的索引?
- azure-sphere - Azure Sphere 和 IoT Edge
- c - 使用数组和指针偏移表示法之间的实际区别
- java - System.out.print("输入限速(>0,<=80):");
- git - GitLab:孤儿分支的 GUI 选项
- tomcat - 在 Tomcat 而不是 Jetty 中本地运行时,Vaadin 14.0.5 无法找到“npm”(Node.js)
- git - git commit --date 中的未来相对日期格式
- python - 如何在 pyplot 中使用 Line Collection