string to array in pascal - arrays

Hi I am passing string from command line line // - 2,3,4,5,6 and as a param in ip1.
when I run this code its give error "Error: Type identifier expected " and " Fatal: Syntax error, ";" expected but "ARRAY" found".
Please let me know what is the problem.....
program main;
uses SysUtils;
var
output : Array of integer;
var
ip1 : Array of integer;
function add(input1:Array of integer) : Array of integer;
begin
add := input1;
end;
type
TIntegerArray = Array of Integer;
function IntArray(var input:string) : TIntegerArray;
var
p: integer;
begin
p := Pos(',', input);
if p = 0 then
p := MaxInt - 1;
result[0] := Copy(input, 1, p - 1);
result[1] := Copy(input, p + 1);
end;
begin
ip1 := IntArray(ParamStr(1));
output := add(ip1);
write('output ',output,'time',0.0 );
end.

You have so many problems in the code you've posted, it's difficult to know where to start...
You need to move the type declaration for TIntegerArray up closer to the start of your program, so it can be used as the return type of both add and IntArray, as well as the argument to add. array of Integer and TIntegerArray are two different types in Pascal, and can't be interchanged.
You don't check to see if you received any parameters before blindly using them. If they don't exist, your code doesn't work at all. You need to check to make sure you've received the parameters, and produce a useful message with instructions if you don't find them.
You never allocate any space for the IntArray return value. You need to use SetLength to declare the proper number of elements in the array before you can assign anything to them when using dynamic arrays. (See #4 below.)
Your IntArray just presumes there are only two items in input, where your sample command line shows more. You need to use a loop. (
Your IntArray tries to use ParamStr(1) as a var parameter. ParamStr(1) is a constant, and can't be passed as a var anything.
You can't pass an array to write or writeln directly. You have to loop through the elements in the array and output each individually.
(Not really a problem, just info) add does nothing to "add" anything, so it is really poorly named. You should pick names that actually describe what it's doing so that your code is easier to read and understand. (I'm not sure what you intended to do with add, but what you have now does nothing useful.
(Another "not really a problem", but info.) You don't handle any exceptions in case the parameters are not able to be converted to integers. An invalid value provided to StrToInt will raise an exception. You should either use Val or StrToIntDef, or at the very least use a try..except block around the conversion to handle invalid parameters.
(Another "not really a problem".) You don't do anything to pause the program at the end so you can see the output of the write statement, which makes it very hard to test or debug your program from the IDE.
Here's a working (tested) version of your code.
program main;
uses
System.SysUtils;
type
TIntegerArray = Array of Integer;
var
ip1, output: TIntegerArray;
function add(input1: TIntegerArray) : TIntegerArray;
begin
Result := input1;
end;
function IntArray(input:string) : TIntegerArray;
var
p: Integer;
i: Integer; // Tracks current index into Result array
begin
i := 0;
p := Pos(',', input);
while P > 0 do
begin
Inc(i); // Increment index
SetLength(Result, i); // Allocate element in array
Result[i] := StrToInt(Copy(input, 1, P - 1)); // Assign value
System.Delete(input, 1, P); // Remove portion we just read
P := Pos(',', input); // See if there's another comma
end;
// Now get the part after last ',' and add to array also
i := Length(Result);
if (i > 0) and (input <> '') then
begin
SetLength(Result, i + 1);
Result[i + 1] := StrToInt(input);
Input := '';
end;
end;
var
Ctr: Integer;
begin
if ParamCount > 0 then
begin
ip1 := IntArray(ParamStr(1));
output := add(ip1);
Write('Output: ');
for Ctr := Low(output) to High(output) do
Write(output[Ctr], ' ');
// Don't know what this is supposed to do, but...
WriteLn('time', 0.0 );
end
else
begin
WriteLn('ParamCount: ', ParamCount);
WriteLn('Syntax: ', ExtractFileName(ParamStr(0)) + ' <arg,arg[,arg...]>');
end;
ReadLn;
end.

You need to use tintegerarray as return type for add() too, just like you already do for intarray.
After that you will find out that Pascal is strong typed, and doesn't allow assigning strings to parameters.
The ip1:=intarray(paramstr(1)); typecast looks extremely dodgy btw. Maybe lookup the help for paramstr and paramcount again.

Related

Read() not working for string type inputs in an array

I'm new to pascal and I have been working on a project recently. And here's a sample of it to where I got the problem. I'm trying to assign string type input values to string type array but it wont work. Basically, it wont allow me to enter data. It skips read(). Cannot enter data.But it works when I change the data type in both of them to Integer.
program temp;
var input_array : array[0..5] of string;
k : integer;
y : string;
begin
for k := 0 to 5 do
begin
writeln('Enter character : ');
read(y); // Not working
input_array[k] := y;
end;
for k := 0 to 5 do
writeln(input_array[k]);
end.
The FPC is not a fully ISO-compliant compiler, yet it’s worth taking a look at the standards anyway. In ISO 10206 “Extended Pascal” you will find the following note:
e) If v is a variable‑access possessing a fixed‑string‑type of capacity c, read(f, v) shall satisfy the following requirements. [… super technical mumbo jumbo …]
NOTE — 6 If eoln(f) is initially true, then no characters are read, and the value of each component of v is a space.
Bottom line, you can “fix” your program by inserting the following conditional readLn which will “consume” any “remnant” end‑of‑line character prior your actual read:
for k := low(input_array) to high(input_array) do
begin
write('Enter character: ');
if EOLn then
begin
readLn;
end;
read(input_array[k]);
end;

Inno Setup Acces violation increment array of strings

I hava an array of strings. I increment this array when it is necessary with the function:
function insertMessageAction(list: TMessagesActions; message: String): TMessagesActions;
var
lenght: integer;
begin
if message <> '' then begin
lenght := GetArrayLength(list);
SetArrayLength(list, lenght +1);
if GetArrayLength(list) > lenght then begin
list[lenght] := message
end;
end;
result := list;
end;
If de increment is of 0 to 2, no problems, by when I increment to 3 lenght, the array is corrupted and 'value' of list is: "Acces violation at address 00403498. Read of address 0000006A".
It is impossible to create more long arrays of 2 items (strings)? There is limit of characters?
Thanks.
First of all, do not use array for your task. Memory reallocation that happens when changing the size of your string array is an expensive operation. What's more, you were trying to return a copy of that input array (in a wrong way), which would be unecessarily inefficient too.
I strongly suggest you to use the TStringList which is intended to be used for a collection of strings. By using TStringList, the whole code from your question would become:
StringList.Add(Message);
But to your question. It is possible, but you need to comply with a few things; at least:
Do not attempt to return an input array passed by reference:
Result := list;
If you need to have an array as a return type for some reason, allocate the size of this output array and copy all the elements from the input array:
InputLen := GetArrayLength(List);
SetArrayLength(Result, InputLen + 1);
for I := 0 to InputLen - 1 do
Result[I] := List[I];
Result[InputLen] := Message;
If you'd still like to stay by array, better pass it by variable parameter:
[Code]
type
TMessagesActions = TArrayOfString;
procedure InsertMessageAction(var AList: TMessagesActions;
const AMessage: String);
var
ArrayLen: Integer;
begin
ArrayLen := GetArrayLength(AList);
SetArrayLength(AList, ArrayLen + 1);
AList[ArrayLen] := AMessage;
end;

How to make dynamic array constant?

There is any way of making x array constant after the data is read from user? There is any way of making variable not modifiable after it's value is read from user (eg. y)?
program hmm;
uses crt;
var
i, y: word;
x: array of word;
begin
readln(y);
y:=y-1;
SetLength(x,y);
for i := 0 to y do begin
read(x[i]);
end;
readkey;
end.
To make y constant I tried something like this, but it won't work - y will be set as 0.
program hmm;
uses crt;
var
i: word;
x: array of word;
const
{$J+}
y:word = 0;
{$J-}
begin
{$J+}
readln(y);
y:=y-1;
{$J-}
y:=0;
SetLength(x,y);
for i := 0 to y do begin
read(x[i]);
end;
readkey;
end.
Thanks for help.
Yes. Don't change either of them in your code after you set the initial value.
Other than that, there's no way. A dynamic array by definition is changeable, and so is a variable - that's why they have dynamic and variable as names.

Is there a clean way to declare a TBytes-compatible value at compile time?

If I wanted to declare a static compile-time array of Byte, I could do it like this:
var
bytes :array[0..24] of Byte = (1, 2, 3, .... );
However, the type of that is array[0..24] of byte, not System.TArray<System.Byte>, which is more commonly known as TBytes.
What I need is something that can be of type TBytes but I don't want to have to add an initialization section to hold these byte values in some painful way:
var
bytes2:TBytes;
initialization
SetLength(bytes2,24);
bytes2[0] := 1; bytes2[1] := 2; ....
Is there some way to do this instead:
var
bytes2:TBytes = (1,2,3, .... );
I tried also to find a way to convert quickly from TBytes (System.TArray<System.Byte>) and array[0..24] of Byte, like this:
bytes2 := byte;
Unfortunately, the closest I can get is this brute-force code:
SetLength(bytes2,Length(bytes));
for n := 0 to Length(bytes) do begin
bytes2[n] := bytes[n];
end;
It seems to me for two types so closely related, that the compiler could do a little better job of allowing me to coerce or copy, from the one type to the other. Anybody else feel that way about various types of "Array of X"? Know any cool ways around it? If the compiler did some magic, it might make the Move(...) function work for this case, but Move actually gives you an access violation, and can't be used with dynamic arrays or generic collections.
How about:
var
bytes: TBytes;
begin
bytes := TBytes.Create(1,2,3, .... );
end;
That said I always find it limiting that this syntax does not accept open arrays. So I have a bunch of functions that look like this:
function Bytes(const A: array of Byte): TBytes;
var
i: Integer;
begin
SetLength(Result, Length(A));
for i := low(Result) to high(Result) do
Result[i] := A[i];
end;
...
var
b1, b2: TBytes;
b3: array of Byte;
b4: array [0..42] of Byte;
...
b1 := Bytes(b2);
b1 := Bytes(b3);
b1 := Bytes(b4);
b1 := Bytes([1,2,3,4]);
I believe that the various generics enhancements in XE mean that this could be done with generics and without duplicating routines like Bytes for each different scalar.

Delphi TBytes - how to copy?

Point is opimization here.
Now:
type TSomeClass=class(TObject)
private
DataWrite: TBytes;
...
end;
Function TSomeClass.GetPacket: TBytes;
begin
SetLength(Result, Length(DataWrite));
Move(DataWrite[0],Result[0],Length(DataWrite));
end;
What I want to achieve:
Function TSomeClass.GetPacket: TBytes;
begin
Result := DataWrite;
end;
Because Arrays in Delphi are pointers to first element, the latter only and only writes 4 bytes so it is MUCH faster. Is this correct?
The one thing you need to be aware of is that different from strings, dynamic arrays are not "copy-on-write".
If you assign a string, or a dynamic array, only the pointer to the data on the heap is copied and the reference count is incremented.
But with a string, if you then write into a string (e.g. s[1] := 'a') which has a reference count > 1, the compiler will emit code which makes sure that the string is copied first. This is not the case with dynamic arrays:
var
s, t: string;
a, b: TBytes;
begin
s := 'abc';
t := s;
t[2] := 'X';
WriteLn(s); //still abc
a := TBytes.Create(1, 2, 3);
b := a;
b[1] := 0;
WriteLn(a[1]); // is now 0 not 2!
So in case of your code, if you change the contents of DataWrite after GetPacket was called, the change will be visible in the TBytes that GetPacket returned.
For the code where you actually make a copy of the array, instead of calling SetLength And Move, you can use:
function TSomeClass.GetPacket: TBytes;
begin
Result := Copy(DataWrite, 0, High(Integer));
end;
That will work but note that you are now working on the same byte array in client code that calls GetPacket. This might be a bad idea. Consider some network library that does some additional compression or encryption on the byte array. This creates a lot of possibilites to interact with your class without using the exposed interface - which is bad. Thus IMHO copying is the better option here.
BTW: How big are the arrays we are talking about here?

Resources