简体   繁体   English

将字符串分配给字符数组

[英]Assign String to Array of Characters

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'返回 -> (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返回(189): E2008 Incompatible types

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 ).尽管如此, Sender参数是多余的并不罕见,因为由于 VCL 的设计(特别是TNotifyEvent ),它们几乎无处不在。 If you know that the receiving procedure doesn't care about the Sender parameter, simply give it anything, like Self or nil .如果您知道接收过程不关心Sender参数,只需给它任何东西,例如Selfnil

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;您不能将 arrays 视为字符串; in particular, you cannot assign static arrays like this ( a:= b ).特别是,您不能像这样分配 static arrays ( 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:但是,如果您声明 static 数组类型,则上述简单赋值 ( a:= b ) 确实有效:

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

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

Andreas has you covered for question 1.安德烈亚斯为您解决了问题 1。

Question 2问题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.这样你就可以直接调用RespondToEditControlKeyPress

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.您也许可以改用OnChange事件。 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.并且可能OnChange更合适,因为按键并不是将文本放入编辑控件的唯一方法。


By the way, it's better to ask one question at a time here on Stack Overflow.顺便说一句,最好在 Stack Overflow 上一次问一个问题。

For a quick way to copy string-type values into array-of-character type values.用于将字符串类型值复制到字符数组类型值的快速方法。 I suggest a small helper function like this:我建议像这样的小帮手 function :

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:请记住,如果缓冲区长度为 15,则应将 14 作为 maxlen 传递,以便为终止nul字符留出空间,如果您打算始终终止字符串:

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.这个 function 将确保您复制到记录中的数据被 null 终止,假设这是您想要的。 Remember that in a fixed length character array it's up to you to decide what the rules are.请记住,在固定长度的字符数组中,由您决定规则是什么。 Null terminated? Null 终止? 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.完全用空格或 null 字符填充......字符串和字符数组是如此不同,以至于存在多种可能的在两者之间进行转换的方式。

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.如果您不打算用 nul 终止您的字符串,那么您应该使用其他人的答案中显示的 FillChar+Move 组合。

The obvious answer is of course.显而易见的答案当然是。
Don't use a packed array of char.不要使用打包的 char 数组。

Use a string instead.请改用字符串。
If you use ansistring , 1 char will always take 1 byte.如果您使用ansistring ,则 1 个字符将始终占用 1 个字节。 If you use shortstring ditto.如果您使用shortstring同上。

Ansistring is compatible with Pchar which is a pointer to a packed array of char . Ansistring 与Pchar兼容,后者是指向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.看起来您正在将代码从 c 转换为 Delphi。

a packed array of char is exactly the same as the old (1995) shortstring minus the length byte at the beginning of shortstring . packed array of char与旧的(1995 年)短字符串减去shortstring开头的长度字节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.我能想到使用packed array of char的唯一原因是当您从磁盘读取数据时,并且您有不想更改的遗留代码。

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 .我将保留遗留代码以从磁盘读取和写入,然后将数据传输到ansistring并从那里仅使用ansistring

It's soooooooo much easier, Delphi does everything for you.这太容易了,Delphi 为您做一切。
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).而且... ansistring更快,自动创建和销毁,可以有任何长度(最多 2GB),使用更少的memory --因为相同的字符串只存储一次(这意味着stringa:= stringb其中一个字符串是 20 个字符使用 ansistrings 比使用 char 数组快至少 5 倍)。
And of course best of all, buffer overflow errors are impossible with ansistring .当然,最重要的是,使用ansistring是不可能出现缓冲区溢出错误的。

What about unicodestring ? 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. Unicodestring 很好用,但有时在packed array of char和 unicodestring 之间转换时会发生字符转换,因此我建议在这种情况下使用ansistring

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.这试图将指针(StrPLCopy 的结果,Delphi 的最后几个版本中的 PWideChar)分配给数组,这确实是不可能的。 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.这应该可行,并且是 IMO 将字符串复制到字符数组的最简单解决方案。 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.不需要使用 a 作为某种中间值,并且使用 Move 是,IMO,相当低级,因此有点棘手(很容易忘记乘以字符的大小,它是未选中的,它没有添加 #0 等),尤其是在您不知道自己在做什么的情况下。

This solution should even work for versions of Delphi before Delphi 2009, as it does not rely on the size of the character.该解决方案甚至应该适用于 Delphi 2009 之前的 Delphi 版本,因为它不依赖于字符的大小。

FWIW, I would not use packed arrays. FWIW,我不会使用打包的 arrays。 Packed doesn't have a meaning in current Delphi, but could confuse the compiler and make the types incompatible. Packed 在当前的 Delphi 中没有意义,但可能会混淆编译器并使类型不兼容。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM