将字符串分配给字符数组

发布于 2024-11-04 14:00:46 字数 984 浏览 0 评论 0原文

问题一

var example : array[0..15] of char;

想将输入中的值分配给该变量

example := inputbox('Enter Name', 'Name', '');

在高分单元中,我有记录和数组

type
points = record
var
  _MemoryName : array[0..15] of char;
  _MemoryScore : integer;
end;

var
rank : array[1..3] of points;

var s: string;
 a: packed array[0..15] of char;

highscoresdata.position[1]._MemoryName := StrPLCopy(a, s, Length(a)) ;

返回 -> (186): E2010 不兼容类型:'array[0..15] of Char' 和 'PWideChar'

var s: string;
 a: packed array[0..15] of char;

             s := InputBox('caption', 'Caption', 'Caption');
             FillChar(a[0], length(a) * sizeof(char), #0);
             Move(s[1], a[0], length(a) * sizeof(char));
      scores.rank[1]._MemoryName := <<tried both s and a>> ;

返回 (189): E2008 不兼容类型

Question One

I have

var example : array[0..15] of char;

I want to assign the value from an input to that variable

example := inputbox('Enter Name', 'Name', '');

In the highscores unit I have record and array

type
points = record
var
  _MemoryName : array[0..15] of char;
  _MemoryScore : integer;
end;

var
rank : array[1..3] of points;

var s: string;
 a: packed array[0..15] of char;

highscoresdata.position[1]._MemoryName := StrPLCopy(a, s, Length(a)) ;

returns -> (186): E2010 Incompatible types: 'array[0..15] of Char' and 'PWideChar'

var s: string;
 a: packed array[0..15] of char;

             s := InputBox('caption', 'Caption', 'Caption');
             FillChar(a[0], length(a) * sizeof(char), #0);
             Move(s[1], a[0], length(a) * sizeof(char));
      scores.rank[1]._MemoryName := <<tried both s and a>> ;

returns (189): E2008 Incompatible types

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

煮酒 2024-11-11 14:00:46

问题一

方法有很多。一是:

procedure TForm1.FormCreate(Sender: TObject);
var
  s: string;
  a: packed array[0..15] of char;
begin
  s := InputBox(Caption, Caption, Caption);
  assert(length(s) <= 16);
  FillChar(a[0], length(a) * sizeof(char), #0);
  Move(s[1], a[0], length(s) * sizeof(char));
end;

但我怀疑,对于你原来的问题可能有一个更优雅的解决方案。

问题二

每当您希望函数/过程没有特定参数时,您应该意识到项目的设计可能存在问题。然而,Sender 参数是多余的并不罕见,因为由于 VCL 的设计(特别是 TNotifyEvent),它们几乎无处不在。如果您知道接收过程不关心 Sender 参数,只需给它任何东西,例如 Selfnil

问题三

考虑这段代码:

procedure TForm4.FormCreate(Sender: TObject);
var
  a: packed array[0..15] of char;
  b: packed array[0..15] of char;
begin
  a := b;
end;

这不起作用。你不能像对待字符串一样对待数组;特别是,您不能像这样分配静态数组 (a := b)。

相反,您必须执行类似...

Move(b[0], a[0], length(a) * sizeof(char));

...或者只是循环并一次复制一个值。但是,如果您声明静态数组类型,则上述简单赋值 (a := b) 确实有效:

type
  TChrArr = packed array[0..15] of char;

procedure TForm4.FormCreate(Sender: TObject);
var
  a: TChrArr;
  b: TChrArr;
begin
  b := a;
end;

Question One

There are many ways. One is:

procedure TForm1.FormCreate(Sender: TObject);
var
  s: string;
  a: packed array[0..15] of char;
begin
  s := InputBox(Caption, Caption, Caption);
  assert(length(s) <= 16);
  FillChar(a[0], length(a) * sizeof(char), #0);
  Move(s[1], a[0], length(s) * sizeof(char));
end;

But there might be a more elegant solution to your original problem, I suspect.

Question Two

Every time you wish a function/procedure didn't have a particular argument, you should realize that there might be a problem with the design of the project. Nevertheless, it isn't uncommon that Sender parameters are superfluous, because they are almost omnipresent because of the design of the VCL (in particular, the TNotifyEvent). If you know that the receiving procedure doesn't care about the Sender parameter, simply give it anything, like Self or nil.

Question Three

Consider this code:

procedure TForm4.FormCreate(Sender: TObject);
var
  a: packed array[0..15] of char;
  b: packed array[0..15] of char;
begin
  a := b;
end;

This doesn't work. You cannot treat arrays like strings; in particular, you cannot assign static arrays like this (a := b).

Instead, you have to do something like...

Move(b[0], a[0], length(a) * sizeof(char));

...or simply loop and copy one value at a time. But the above simple assignment (a := b) does work if you declare a static array type:

type
  TChrArr = packed array[0..15] of char;

procedure TForm4.FormCreate(Sender: TObject);
var
  a: TChrArr;
  b: TChrArr;
begin
  b := a;
end;
顾忌 2024-11-11 14:00:46

Andreas 已为您解答了问题 1。

问题 2

我会安排您的事件处理程序调用另一个方法:

procedure TForm5.Edit1KeyPress(Sender: TObject; var Key: Char);
begin
  RespondToEditControlKeyPress;
end;

这样您就可以直接调用 RespondToEditControlKeyPress

我猜您想在不带参数的情况下调用它,因为您希望在修改编辑控件的文本时运行代码。您也许可以使用 OnChange 事件来代替。 OnChange 可能更合适,因为按键并不是将文本输入编辑控件的唯一方法。


顺便说一句,最好在 Stack Overflow 上一次问一个问题。

Andreas has you covered for question 1.

Question 2

I would arrange that your event handler called another method:

procedure TForm5.Edit1KeyPress(Sender: TObject; var Key: Char);
begin
  RespondToEditControlKeyPress;
end;

That way you can just call RespondToEditControlKeyPress directly.

I'd guess that you want to call it with no parameters because you want code to run when the edit control's text is modified. You could perhaps use the OnChange event instead. And it may be that OnChange is more appropriate because pressing a key is not the only way to get text into an edit control.


By the way, it's better to ask one question at a time here on Stack Overflow.

江湖正好 2024-11-11 14:00:46

用于将字符串类型值复制到字符数组类型值的快速方法。我建议使用这样的小辅助函数:

procedure StrToCharArray( inputStr:String; var output; maxlen:Integer);
type
    ArrayChar = Array[0..1] of Char;
begin
  StrLCopy( PChar(@ArrayChar(output)[0]),PChar(inputStr),maxlen);
end;

每次调用它时,传入要复制的最大长度。请记住,如果缓冲区长度为 15,则应传入 14 作为 maxlen,以便为终止 nul 字符留出空间(如果您打算始终终止字符串):

StrToCharArray( UserInputStr,  MyRecord.MyField,  14 );

此函数将确保复制到记录中的数据以空终止,假设这就是您想要的。请记住,在固定长度字符数组中,由您决定规则是什么。空终止?完全用空格或空字符填充......字符串和字符数组是如此不同,以至于存在多种可能的方式在两者之间进行转换。

如果您不打算用 nul 终止字符串,那么您应该使用其他人的答案中显示的 FillChar+Move 组合。

For a quick way to copy string-type values into array-of-character type values. I suggest a small helper function like this:

procedure StrToCharArray( inputStr:String; var output; maxlen:Integer);
type
    ArrayChar = Array[0..1] of Char;
begin
  StrLCopy( PChar(@ArrayChar(output)[0]),PChar(inputStr),maxlen);
end;

Each time you call it, pass in the maximum length to be copied. Remember that if the buffer length is 15, you should pass in 14 as the maxlen, so that you leave room for the terminating nul character, if you intend to always terminate your strings:

StrToCharArray( UserInputStr,  MyRecord.MyField,  14 );

This function will ensure that the data you copy into the record is null terminated, assuming that's what you wanted. Remember that in a fixed length character array it's up to you to decide what the rules are. Null terminated? Fully padded with spaces or null characters.... Strings and arrays-of-characters are so different, that there exist multiple possible ways of converting between the two.

If you don't intend to terminate your strings with nul, then you should use the FillChar+Move combination shown in someone else's answer.

你曾走过我的故事 2024-11-11 14:00:46

显而易见的答案是当然。
不要使用压缩的字符数组。

请改用字符串。
如果您使用 ansiststring,1 个字符将始终占用 1 个字节。
如果您使用 shortstring 同上。

Ansistring 与 Pchar 兼容,Pchar 是指向 char 压缩数组的指针。

所以你可以写

function inputbox(a,b,c: ansistring): pchar;
begin
  Result:= a+b+c;
end;

var s: ansistring;
begin
  s:= inputbox('a','b','c');
end;

一些建议
看起来您正在将代码从 c 转换为 Delphi。

char 压缩数组 与旧的 (1995) shortstring 完全相同,减去 shortstring 开头的长度字节。

我能想到使用压缩字符数组的唯一原因是当您从磁盘读取数据或从磁盘读取数据时,并且您有不想更改的遗留代码。

我将保留遗留代码以从磁盘读取和写入,然后将数据传输到 ansisstring 中,并且从那里仅使用 ansisstring。

这太简单了,Delphi 为您做一切。
而且... ansisstring 速度更快,自动创建和销毁,可以具有任意长度(最多 2GB),使用更少内存 - 因为仅存储相同的字符串一次(这意味着 stringa:= stringb ,其中字符串为 20 个字符,使用 ansistrings 比使用 char 数组至少快 5 倍)。
当然最重要的是,ansiststring 不可能出现缓冲区溢出错误。

unicodestring怎么样?
Unicodestring 很好用,但有时在 char 压缩数组 和 unicodestring 之间转换时会发生字符转换,因此我建议在这种情况下使用 ansistring

The obvious answer is of course.
Don't use a packed array of char.

Use a string instead.
If you use ansistring, 1 char will always take 1 byte.
If you use shortstring ditto.

Ansistring is compatible with Pchar which is a pointer to a packed array of char.

So you can write

function inputbox(a,b,c: ansistring): pchar;
begin
  Result:= a+b+c;
end;

var s: ansistring;
begin
  s:= inputbox('a','b','c');
end;

Some advice
It looks like your are translating code from c to Delphi.

a packed array of char is exactly the same as the old (1995) shortstring minus the length byte at the beginning of shortstring.

The only reason I can think of to use packed array of char is when you are reading data to and from disk, and you have legacy code that you don't want to change.

I would keep the legacy code to read and write from disk and then transfer the data into an ansistring and from there on only use ansistring.

It's soooooooo much easier, Delphi does everything for you.
And... ansistring is much faster, gets automatically created and destroyed, can have any length (up to 2GB), uses less memory --because identical strings only get stored once (which means stringa:= stringb where a string is 20 chars is at least 5x faster using ansistrings than array's of char).
And of course best of all, buffer overflow errors are impossible with ansistring.

What about unicodestring?
Unicodestring is fine to use, but sometimes translation of chars happens when converting between packed array of char and unicodestring, therefore I recommend using ansistring in this context.

山人契 2024-11-11 14:00:46

实际上,您尝试做的事情是不可能的:

  highscoresdata.position[1]._MemoryName := StrPLCopy(a, s, Length(a));

尝试将指针(StrPLCopy 的结果,Delphi 的最后几个版本中的 PWideChar)分配给数组,这确实是不可能的。你不能像这样复制一个数组。我会这样做:

  StrLCopy(highscoresdata.position[1]._MemoryName, PChar(s),
    Length(highscoresdata.position[1]._MemoryName));

这应该可行,并且在我看来,这是将字符串复制到字符数组的最简单的解决方案。没有必要使用 a 作为某种中间体,并且使用 Move 在我看来是相当低级的,因此有点棘手(很容易忘记乘以字符的大小,它是未经检查的,它不会添加 #0 等),尤其是当您不知道自己到底在做什么时。

该解决方案甚至适用于 Delphi 2009 之前的 Delphi 版本,因为它不依赖于字符的大小。

FWIW,我不会使用打包数组。 Packed 在当前的 Delphi 中没有意义,但可能会混淆编译器并使类型不兼容。

What you try to do is impossible, indeed:

  highscoresdata.position[1]._MemoryName := StrPLCopy(a, s, Length(a));

That tries to assign a pointer (the result of StrPLCopy, a PWideChar in the last few versions of Delphi) to an array, which is indeed impossible. You can't copy an array like that. I would do:

  StrLCopy(highscoresdata.position[1]._MemoryName, PChar(s),
    Length(highscoresdata.position[1]._MemoryName));

That should work, and is IMO the simplest solution to copy a string to an array of characters. There is no need to use a as some kind of intermediate, and using Move is, IMO, rather low level and therefore a little tricky (it is easy to forget to multiply by the size of a character, it is unchecked, it does not add a #0, etc.), especially if you don't know what exactly you are doing.

This solution should even work for versions of Delphi before Delphi 2009, as it does not rely on the size of the character.

FWIW, I would not use packed arrays. Packed doesn't have a meaning in current Delphi, but could confuse the compiler and make the types incompatible.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文