开发者

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'

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


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;


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.


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.


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.


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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜