Jump to content
Ugochukwu Mmaduekwe

Strange and Random Access Violations

Recommended Posts

Hi all,

I wrote a simple function to help me convert a string to an array of char but I keep getting random occurring access violations.

 

class function TUtilities.StringToCharArray(const S: String)
  : TCharArray;
begin
  if System.Length(S) > 0 then
  begin
    System.SetLength(Result, System.Length(S));
    StrPLCopy(PChar(Result), S, System.Length(Result));
  end;
end;

Anyone know the cause?

Thanks.

Share this post


Link to post

it's in the help

 

Note: Dest should point to a location with room for MaxLen + 1 characters, including the null terminator.
 
too bad that the compiler can't detect the out of range
Edited by Attila Kovacs
  • Like 1

Share this post


Link to post

You should try this

class function TUtilities.StringToCharArray(const S: String)
  : TCharArray;
begin
  System.SetLength(Result, System.Length(S));
  if System.Length(S) > 0 then
  begin
    StrPLCopy(PChar(Result), S, System.Length(Result));
  end;
end;

 

Share this post


Link to post
5 hours ago, Attila Kovacs said:

it's in the help

 

Note: Dest should point to a location with room for MaxLen + 1 characters, including the null terminator.
 
too bad that the compiler can't detect the out of range

Thanks a lot, this did solve the problem.

Share this post


Link to post
35 minutes ago, Schokohase said:

You should try this


class function TUtilities.StringToCharArray(const S: String)
  : TCharArray;
begin
  System.SetLength(Result, System.Length(S));
  if System.Length(S) > 0 then
  begin
    StrPLCopy(PChar(Result), S, System.Length(Result));
  end;
end;

 

unfortunately, this did not work, but thanks either way.

Share this post


Link to post
2 hours ago, Ugochukwu Mmaduekwe said:

System.SetLength(Result, System.Length(S));

This should be  SetLength(Result, Length(S) * SizeOf( AnsiChar ) );
 

program Project1;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  System.SysUtils;


function MyStringToMyCharArray( const S: String ): TCharArray;
begin
  SetLength(Result, Length(S) * SizeOf( AnsiChar ) );
  if Length( S ) > 0 then
  begin
    StrPLCopy( PChar( Result ), S, Length( Result ) );
  end;
end;


var
 S: String;
 C: TCharArray;
 I: Integer;
begin
  try
    { TODO -oUser -cConsole Main : Insert code here }
    S := 'My Test String';
    C := MyStringToMyCharArray( S );
    for i := 0 to Length( C ) -1 do
      write( c[ i ] );
    writeln;
    readln;
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
end.

 

Edited by KodeZwerg

Share this post


Link to post
function StringToCharArray(const S: string): TCharArray;
begin
  PChar(Result) := PChar(S);
end;

 

  • Like 1

Share this post


Link to post

Option 1

uses
  System.SysUtils;
  
class function TUtilities.StringToCharArray(const S: String)
  : TCharArray;
begin
  Result := S.ToCharArray();
end;

Option 2 (found at System.SysUtils.TStringHelper.ToCharArray from Delphi 10.2.3 Tokyo)

class function TUtilities.StringToCharArray(const S: String)
  : TCharArray;
begin
  SetLength(Result, Length(S));
  Move(PChar(PChar(S))^, Result[0], Length(S) * SizeOf(Char));
end;

 

Edited by Schokohase

Share this post


Link to post
43 minutes ago, KodeZwerg said:

This should be  SetLength(Result, Length(S) * SizeOf( AnsiChar ) );
 


program Project1;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  System.SysUtils;


function MyStringToMyCharArray( const S: String ): TCharArray;
begin
  SetLength(Result, Length(S) * SizeOf( AnsiChar ) );
  if Length( S ) > 0 then
  begin
    StrPLCopy( PChar( Result ), S, Length( Result ) );
  end;
end;


var
 S: String;
 C: TCharArray;
 I: Integer;
begin
  try
    { TODO -oUser -cConsole Main : Insert code here }
    S := 'My Test String';
    C := MyStringToMyCharArray( S );
    for i := 0 to Length( C ) -1 do
      write( c[ i ] );
    writeln;
    readln;
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
end.

 

This will give the same access violation as the previous one if you run it multiple times in a loop.

The +1 space for the null terminator still applies.

Share this post


Link to post
26 minutes ago, Kryvich said:

function StringToCharArray(const S: string): TCharArray;
begin
  PChar(Result) := PChar(S);
end;

 

Oddly enough, this seems to work.

Another function in my arsenal.

Thanks.

Share this post


Link to post
45 minutes ago, KodeZwerg said:

This should be  SetLength(Result, Length(S) * SizeOf( AnsiChar ) );

Can you tell us why you think these is right? There is no reason for this construct. 
Length(s) is enough .

  • Like 1

Share this post


Link to post
8 minutes ago, Schokohase said:

Option 1


uses
  System.SysUtils;
  
class function TUtilities.StringToCharArray(const S: String)
  : TCharArray;
begin
  Result := S.ToCharArray();
end;

Option 2 (found at System.SysUtils.TStringHelper.ToCharArray)


class function TUtilities.StringToCharArray(const S: String)
  : TCharArray;
begin
  SetLength(Result, Length(S));
  Move(PChar(PChar(S))^, Result[0], Length(S) * SizeOf(Char));
end;

 

Thanks but am trying to avoid the string helper functions, I also want to avoid using *move* on strings because I heard some time back that it breaks reference counting on strings.

Share this post


Link to post
1 hour ago, Ugochukwu Mmaduekwe said:

Thanks but am trying to avoid the string helper functions, I also want to avoid using *move* on strings because I heard some time back that it breaks reference counting on strings.

It can brake reference counting only if you move() to string.

When you only move() from string the string is not affected in any way. Move() doesn't change the source.

  • Like 2
  • Thanks 1

Share this post


Link to post
14 minutes ago, Cristian Peța said:

It can brake reference counting only if you move() to string.

When you only move() from string the string is not affected in any way. Move() doesn't change the source.

Thanks a lot for the explanation.

Edited by Ugochukwu Mmaduekwe

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×