I do not understand why this code generates access violation.
var
S, Data: String;
begin
S := 'Test';
PChar(@S[1])^ := #80; //This raises access violation
S[1] := 'x'; //This woks as it should
SetLength(Data, 4);
PChar(@Data[1])^ := #80; //This do not raises access violation
end;
Why in case of S access violation is raised an in case of Data it is not raised?
Your confusion is quite understandable since, at first sight, that statement should work.
The reason it doesn't work is because of the way FPC allocates string constants when LONGSTRINGS is ON (which I believe is the default.)
When LONGSTRINGS is ON, the statement:
causes FPC to put the string in a _read only_ data section. When you try to write to it, you get an access violation.
if you turn LONGSTRINGS OFF, the statement will work because a shortstring is in memory and @s refers to a writeable memory location instead of a read-only section in the executable.
try this code:
{$MODE OBJFPC }
{$LONGSTRINGS OFF }
//{$LONGSTRINGS ON }
{$TYPEDADDRESS ON }
program PcharString;
var
s : string;
begin
s := 'test';
writeln(s);
writeln(pchar(@s[1])^);
pchar(@s[1])^ := 'b';
writeln(pchar(@s[1])^);
writeln(s);
writeln;
end.
If you compile and run the above with LONGSTRINGS OFF, it will work just fine. If you compile it with LONGSTRINGS ON, you'll get an access violation because the string "test" is in a read-only section of the PE file.
You can confirm this using any PE file dump utility. Look at the file in hex, search for test, note the file offset then search for that offset in the PE dump. You'll find it in a read only section which is the reason you get an access violation.
HTH.
ETA:
S points to read-only memory because 'Test' is constant?
I see you figured it out while I was typing my post. Good for you.