【问题标题】:Dynamic array, convert from C++ to Delphi动态数组,从 C++ 转换为 Delphi
【发布时间】:2014-04-22 19:35:12
【问题描述】:

我不明白为什么 Delphi 不像 C++ 那样工作

float *buffer;
buffer=new float[2];
buffer[0]=0.1;
buffer[1]=0.2;
buffer+=1;
//now buffer[0] has value of buffer[1] and buffer[1] has value 0

德尔福代码:

buffer: array of Single;
SetLength(buffer,2);
buffer[0]:=0.1;
buffer[1]:=0.2;
buffer:=buffer+1; //doesn't work

【问题讨论】:

  • @CaptainObvlious 如果您不想提供帮助,请不要发送垃圾邮件。
  • 请提问。还请展示您尝试过的内容,以便我们知道在哪里提出答案。请给出代码的上下文。从字面上翻译它很容易,但可能会产生误导和无益。
  • Stack Overflow 与大多数免费帮助网站一样,对如何提出问题以及提出哪些类型的问题都有规则和指南。请查看常见问题解答,以更好地了解人们为何不愿帮助您。长话短说,您应该付出努力,当您遇到困难时,请向我们提出具体问题。我们可以回答您的问题,但在不了解此代码实际用途的更多信息的情况下,我怀疑任何答案是否真的有用。此外,如果他们总是有其他人做他们的研究和工作,谁又能指望学习呢?
  • @user3560787 这是一个问答网站。不是 为我转换我的代码 网站。我也不相信你只有 10 岁,即使你表现得就像你一样。
  • 您的最新编辑使这个问题变得更好。 +1。你对 cme​​ts 感到不安,但那是因为最初的问题不够好。我建议您反思这种经历,以及与您之前已删除的问题类似的经历。以后在提问前多思考,多花点时间解释问题,你会得到更好的结果。最后一句忠告。永远不要说“不起作用”。始终解释您期望发生的事情以及实际发生的事情。

标签: c++ delphi


【解决方案1】:

您展示的 Delphi 代码与 C++ 代码正在执行的操作不同 - 使用指针算法。以下是更接近的翻译:

如果您使用的是 D2009+:

{$POINTERMATH ON}

var
  buffer: PSingle;

GetMem(buffer, SizeOf(Single) * 2);
buffer[0] := 0.1;
buffer[1] := 0.2;
buffer := buffer + 1;

如果您使用的是 D2007 或更早版本,请改用类似以下的内容:

type
  TSingleArray = packed array[0..(MaxInt div SizeOf(Single))-1] of Single;
  PSingleArray = ^TSingleArray;

var
  buffer: PSingle;

GetMem(buffer, SizeOf(Single) * 2);
PSingleArray(buffer)^[0] := 0.1;
PSingleArray(buffer)^[1] := 0.2;
Inc(buffer);

【讨论】:

  • 您的代码与 C++ 完全一样。为你+1。非常感谢您,先生! :)
  • 能否修改代码防止内存泄漏?我已经把FreeMem放到finally块了,但是好像有内存泄漏。
  • C++ 代码也泄露了。这段代码的上下文是什么。
  • @DavidHeffernan:不要改变人们答案的语义。我恢复了你的更改。当POINTERMATH 开启时,buffer + 1 工作,我希望我的答案显示出来。
  • @user3560787:如果您不想出现内存泄漏,请不要这样编码。如果更改它,您将丢失对原始指针的引用。如果您使用动态数组,编译器会为您清理它。有时,当另一种语言提供更好的便利时,准确的翻译并不是最好的。
【解决方案2】:

您遇到的很多问题都是因为您的 C++ 代码是荒谬的,人们不明白您为什么要这样做,在 C++ 或 Delphi 中。

一个指针指向一个内存地址,一般假定它包含一个变量。但是在 C(以及 C++ 和类似语言)中,指针也用作数组;而不是定义良好的“数组类型”,您只需有一个指向第一个元素的指针和适用于它的数组语法。您的buffer+=1 行基本上意味着“将指向变量元素的指针移到它当前所在的元素之后”。你声称now buffer[0] has value of buffer[1] and buffer[1] has value 0,但这并不是那么简单。旧的缓冲区 [0] 没有去任何地方;你只是移动了指针。

你来自:

  | 
  V
-----------------
| 0 | 1 | beyond|
-----------------
|0.1|0.2|???????|
-----------------

到:

      | 
      V
-----------------
| 0 | 1 | beyond|
-----------------
|0.1|0.2|???????|
-----------------

现在看起来 buffer[0] 已经改变了它的值,但值没有改变;你只是移动了指针。

出于某种原因,我在标记为 ?s 的数组末尾之后留下了值。那不是真正的0;那是未定义,它包含内存中这些字节发生的任何内容。它现在可能是0,但如果你再次运行它(或在不同的地方运行它电脑)你可以很容易地得到一些随机数。 “未定义的行为”是程序员所说的“事情以不可预测且难以追踪的方式出错”。这不是一件好事。 C充满了它;德尔福,更不用说。

您尝试做的事情在 Delphi 中不起作用的原因是 Delphi 具有与指针完全不同的定义良好的数组类型。动态数组可能看起来像“只是一个数组”,但它实际上是一个包含有关数组的元数据的数据结构,并在其末尾粘贴了一个数组。所以你不能移动指针;没有 C 代码那样的“元素指针”。

如果您真的想获得指向数组中某个元素的指针,可能是因为您一次扫描一个元素,您可以声明一个指针类型的变量(使用^ 运算符)并设置它与@ 运算符一起使用,如下所示:

var
buffer: array of Single;
ptr: ^single;
begin
   SetLength(buffer,2);
   buffer[0]:=0.1;
   buffer[1]:=0.2;
   ptr := @buffer[1];
end;

但同样,指针不是数组,数组也不是指针。所以你不能说ptr[0]。 (一些指针类型,例如PChar,出于实用性原因对这条规则做了一个例外,因为它们代表 C API 字符串,但作为一般规则,您不应将指针视为数组。)

如果你想做的是扫描一个数组,有一个更好的方法。因为数组类型定义明确,Delphi 知道它有多长,所以可以这样做:

for value in buffer do
   //do whatever

这称为枚举器,它充当一种特殊的for循环,循环遍历数组中的每个元素,并将其输入索引变量。

我希望这会有所帮助。如果没有,请说明您要使用此代码做什么,我会尝试更好地解释。 :)

【讨论】:

  • 是的,这就是我需要的。非常感谢!
  • @mason 哪些形式的 UB 存在于 C++ 中而 Delphi 中没有?
  • @David:很多东西。与此示例相关:超出数组范围的读/写。在 C++ 中,这会导致未定义的行为。在 Delphi 中,它引发了一个异常。
  • @JerryDodge:是的,但这就是重点。人非圣贤孰能。人们没有正确编码。即使是几乎所有事情都做对的非常优秀的开发人员,也只会几乎做对所有事情。所以问题是,当你犯错时会发生什么?这就是 C 惨遭失败的地方。
  • 确实,我在任何语言中看到的最大问题之一是未处理的异常强行结束进程——VCL 很好地防止了这种情况。
猜你喜欢
  • 1970-01-01
  • 2015-05-06
  • 2013-06-30
  • 1970-01-01
  • 2016-04-07
  • 2014-06-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多