Reputation: 386
I’ve read you cannot dynamically allocate an array in Pascal, but I’m also thinking of implementing a string struct.
In C, I would go about it by creating a struct
containing a pointer to an array of chars (containing the characters), a length integer, and a size one. I would then malloc
the char *
and realloc
it when it needs to be resized.
typedef struct {
size_t size;
size_t length;
char* contents;
} String;
Can this be done in (ISO) Pascal? I don’t want to use a built‐in Pascal dynamic array because it defeats the purpose of making my own string type.
From the comments, it seems like ISO Pascal (both Standard and Extended) doesn’t support such things. Is it possible in Free Pascal?
Upvotes: 1
Views: 409
Reputation: 1556
Can I define my own string type in Pascal?
You need to observe following characteristics of a string data type: In Pascal as defined by the ISO standard 7185 and 10206† a string data type is a
packed
array of
char
integer
index of 1
, andinteger
index of greater than 1
.For example packed array[1..2] of char
is a string data type.
You can pass such string variables to the built‑in procedures write
and writeLn
if the destination is a text
file, and in Extended Pascal also read
and readLn
if the source is a text
file.
I’ve read I can’t really dynamically allocate an array in Pascal […]
Yes/no:
For Standard Pascal as defined by ISO standard 7185, this claim is in practice true, in theory (usually) false. Depending on the implementation, you can dynamically allocate varying amounts of memory, but the overhead is prohibitively impracticable:
program variableLengthStringDemo(output);
const
stringMaximumLength = 4;
type
integerNonNegative = 1..maxInt;
stringLength = 0..stringMaximumLength;
stringCapacity = 1..stringMaximumLength;
string = record
length: stringLength;
case capacity: stringCapacity of
1: (character: packed array[1..1] of char);
2: (characterPair: packed array[1..2] of char);
3: (characterTriplet: packed array[1..3] of char);
4: (characterQuadruplet: packed array[1..4] of char);
end;
var
word: ^string;
begin
new(word, 3);
word^.characterTriplet := 'ABC';
word^.length := 3;
writeLn(word^.characterTriplet)
end.
For identified record
variables (identified means in ISO terminolgy essentially pointers) the built‑in procedures new
and dispose
accept further arguments to select a particular variant.
This allows implementors of a processor to allocate only as much memory as necessary, yet doing so is not mandated by the standards.
What is mandated, though, is that such a variable cannot change the variant anymore.
In the above code word^.capacity
is locked to 3
.
Moreover, since identifiers in all record
variants must be unique, you have to handle multiple identifiers in your code too.
This makes using this approach for character strings for productive purposes pretty useless.
You cannot branch every time in your code just to select the correct identifier for the currently active variant.
This would be insane.
For Extended Pascal as defined by ISO standard 10206, this claim is completely false.
EP defines the notion of schema data types.
Schema data types denote a set of data types.
You need to discriminate this set, “select” one the data types out of the bag, to use it.
The discriminants can be supplied to new
and dispose
, too.
program variableLengthArrayDemo(output);
type
characterSequence(capacity: integer)
= packed array[1..capacity] of char;
var
cheerfulMessage: ^characterSequence;
begin
new(cheerfulMessage, 12);
cheerfulMessage^ := 'Hello world!';
writeLn(cheerfulMessage^)
end.
There are other means to achieve variable‑length arrays in EP, this is just one.
NB:
In EP and SP, should you dispose
identified variables, dispose
needs exactly the same arguments as of the corresponding new
.
new(variable, 3)
→ dispose(variable, 3)
.
†:
Actually, there are fixed string type (presented here), variable string type (EP’s string
schema) and canonical string type (a meta data type purely for definitory purposes), all collectively known as string type.
[…] How do I do it in Free Pascal then?
Well …
In FreePascal
array of
char
or a derivative of char
as its base typeis a string. The FreePascal dialect permits you to typecast variables.
New
(and dispose
) accept further arguments only in {$mode ISO}
and {$mode extendedPascal}
.
As of 2024, the FreePascal Compiler (still) intends to support ISO 10206 but support for schema data types is still missing.
Upvotes: 1
Reputation: 1311
In Free Pascal it can be implemented similar to the mentioned C approach:
type
TMyString = record
size: SizeUInt;
length: SizeUInt;
contents: PAnsiChar;
end;
...
procedure AllocMyString(var S: TMyString; L: SizeUInt);
begin
S.size := 0;
S.length := L;
GetMem(Pointer(S.contents), L);
end;
procedure ReallocMyString(var S: TMyString; L: SizeUInt);
begin
S.size := 0;
S.length := L;
ReAllocMem(Pointer(S.contents), L);
end;
Upvotes: 3