Board index » delphi » converting PChar to String

converting PChar to String

Hi

I'm trying to write a program, where one of the functions should return
a string. However, I have to use the function FileSplit (from the WinDos
unit), and it returns PChar. when I try to assign str:=pchar^, the
string contains only the first character of the PChar. How do I go
conver a PChar to a String?

This is the function:

function Full2Name (str:string):string;
var
 dir, name, ext:pchar;

begin
 filesplit (@str, dir, name, ext);
 full2name:=name^;
end;

 

Re:converting PChar to String


On Sun, 15 Jun 1997 16:37:20 +0300, Alex Druinsky

Quote
<adr...@netvision.net.il> wrote:
>Hi

>I'm trying to write a program, where one of the functions should return
>a string. However, I have to use the function FileSplit (from the WinDos
>unit), and it returns PChar. when I try to assign str:=pchar^, the
>string contains only the first character of the PChar. How do I go
>conver a PChar to a String?

>This is the function:

>function Full2Name (str:string):string;
>var
> dir, name, ext:pchar;

>begin
> filesplit (@str, dir, name, ext);
> full2name:=name^;
>end;

Try:

  full2name := StrPas( name ) ;

Regards,

Stephen Posey
slpo...@concentric.net

Re:converting PChar to String


Quote
Alex Druinsky wrote:
> Hi

> I'm trying to write a program, where one of the functions should return
> a string. However, I have to use the function FileSplit (from the WinDos
> unit), and it returns PChar. when I try to assign str:=pchar^, the
> string contains only the first character of the PChar. How do I go
> conver a PChar to a String?

PChars and strings are stored differently.  A PChar is a series of
characters, terminated by an ASCII #0; a string is an array of
characters, where the 0 element's value reflects the length of the
string.  You can convert from PChar to string using the StrPas()
function in the Strings unit.

Quote
> This is the function:

> function Full2Name (str:string):string;
> var
>  dir, name, ext:pchar;

> begin
>  filesplit (@str, dir, name, ext);
>  full2name:=name^;
> end;

This won't work well, since a PChar is just a pointer type which is
given some special abilities by the compiler.  No space is allocated for
the strings.

Shouldn't the Dos unit also be available?  It has most of the same
functions and procedures, implemented with standard the string type.  If
not, I'd suggest reading up on PChars in the Language Guide.

--
Scott Earnest        | We now return you to our regularly |
set...@ix.netcom.com | scheduled chaos and mayhem. . . .  |

Re:converting PChar to String


Quote
Alex Druinsky (adr...@netvision.net.il) wrote:
> I'm trying to write a program, where one of the functions should return
> a string. However, I have to use the function FileSplit (from the WinDos
> unit), and it returns PChar. when I try to assign str:=pchar^, the
> string contains only the first character of the PChar. How do I go
> conver a PChar to a String?

Use StrPCopy and StrPas (in unit Strings) to convert, and (most importantly!)
allocate memory (e.g. with arrays of char) -- a PChar is only a pointer!
Like in the following procedure that I use for WinDos->Dos compatibility:

PROCEDURE FSplit(Path:PathStr;VAR Dir:DirStr;VAR Name:NameStr;VAR Ext:ExtStr);
VAR
  p:ARRAY[Byte] OF Char;
  d:ARRAY[0..fsDirectory] OF Char;
  n:ARRAY[0..fsFileName] OF Char;
  e:ARRAY[0..fsExtension] OF Char;
BEGIN
  FileSplit(StrPCopy(p,Path),d,n,e);
  Dir:=StrPas(d);
  Name:=StrPas(n);
  Ext:=StrPas(e)
END;

--
Frank Heckenbach, Erlangen, Germany
heck...@mi.uni-erlangen.de
Turbo Pascal:   http://www.mi.uni-erlangen.de/~heckenb/programs.htm
Internet links: http://www.mi.uni-erlangen.de/~heckenb/links.htm

Re:converting PChar to String


Alex Druinsky <adr...@netvision.net.il> scritto nell'articolo
<33A3F010.35853...@netvision.net.il>...

Quote
> Hi

> I'm trying to write a program, where one of the functions should return
> a string. However, I have to use the function FileSplit (from the WinDos
> unit), and it returns PChar. when I try to assign str:=pchar^, the
> string contains only the first character of the PChar. How do I go
> conver a PChar to a String?

> This is the function:

> function Full2Name (str:string):string;
> var
>  dir, name, ext:pchar;

> begin
>  filesplit (@str, dir, name, ext);
>  full2name:=name^;
> end;

Hi...
Try this:

full2name:=StrPas(name);

Ciao
Matteo
--
Please mail me at:
Matteo.Felici...@fe.nettuno.it
Ciao.

Re:converting PChar to String


Quote
Alex Druinsky <adr...@netvision.net.il> wrote:
>Hi

>I'm trying to write a program, where one of the functions should return
>a string. However, I have to use the function FileSplit (from the WinDos
>unit), and it returns PChar. when I try to assign str:=pchar^, the
>string contains only the first character of the PChar. How do I go
>conver a PChar to a String?

>This is the function:

>function Full2Name (str:string):string;
>var
> dir, name, ext:pchar;

>begin
> filesplit (@str, dir, name, ext);
> full2name:=name^;
>end;

Your problem is the result of a misunderstanding.  Don't feel bad,
Alex, seems quite a few people not really familiar with pointers,
and less familiar with "C" fall into the same pit.

Lets take a quick look at the online help:

 FileSplit (function)     (WinDos unit)
 _______________________________________
 Splits a file name into its three components.

  Declaration:
  function FileSplit(Path, Dir, Name, Ext: PChar): Word

Now, as you figured, FileSplit wants a pChar.  But, what you fail
to realize is that a pChar is nothing more than a pointer.  in
short, they are supposed to provide FileSplit with the memory
location that is to receive the various portions of the file spec.

Consider a little further into the inline help:
If a component string parameter is nil, the corresponding part of
the path is not stored. If the path does not contain a given
component, the returned component string is empty. The maximum
string lengths returned in Dir, Name, and Ext are defined by the
fsDirectory, fsFileName, and fsExtension constants.

So, if a pointer points to nothing, then FileSplit would skip that
portion.  However, in your case they contain garbage, which is
most likely not nil, so  FileSplit attempts to write to the memory
location they indicate. <crash>

When you start working with the WinDOS and STRINGS units you have
to put on your "C" thinking cap.  Another look in online help for
pChar, gives us:

PChar:
The predefined type PChar denotes a pointer to a null-terminated
string.

PChar is declared as:
   type PChar = ^Char;

Borland Pascal for Windows supports a set of extended syntax rules
(controlled by the $X compiler directive) to facilitate handling
of strings using the PChar type.

When you think on this, you eventually realize that the character
pointed to by the pChar to be passed to FileSplit must be expected
to point to a 0-Based array of size defined by the  fsDirectory,
fsFileName, and fsExtension constants.

Now, when you go back to the online code example under FileSplit,
you see the following, which agrees with this, but does't look
anything like what you wrote.

var
 Path: array[0..fsPathName] of Char;
 Dir: array[0..fsDirectory] of Char;
 Name: array[0..fsFileName] of Char;
 Ext: array[0..fsExtension] of Char;
begin
 Write('Filename (WORK.PAS): ');
 Readln(Path);
 FileSplit(Path, Dir, Name, Ext);

Note that by virtue of being 0-based arrays, Path, Dir, Name, and
Ext all qualify as and satisfy the requirement a pChar.  This is
the "C" leaking over from the WinDOS function.  "C" treats the
array of character and pChar as an address to a memory storage
location.  A routine that receives a pChar doesn't care if it was
the address of a 0-based array, or an actual pChar.  Both are
addresses that it can manipulate as it sees fit.

The owner of the 0-based array can use the array where ever a
pChar can be used, but _cannot_ change its value.  If p is a
pChar, then Inc(p) is valid, while Inc(Dir) is not.  p := Dir, is
also valid, but Dir = p is not.  Since dir is the array, you would
have to move the characters with something like, StrCpy(Dir, p);

Personally I wish the implementors had had a little less "C"
background, then they might have used a more Pascal approach to
the interface and use of null-terminated strings. I wouldn't find
it uncomfortable having to write @Dir to indicate "address of",
rather than have Dir automatically mean "address of".

I would even find p^[5] more comfortable in a Pascal program than
p[5].  When a Pascal programmer _knows_ p is a pointer, s/he would
expect to have to dereference it in order to access what it
"points to", and would expect to take the "address of" sometime
when assigning it a value.  But "C" prefers the automatic
conversion to be based on how you would most likely use it, rather
than be consistent with its actual type.

Hope I've helped.  I know I feel better.  Helps to swear and cuss
about the "C" being imposed on us once in awhile. ;-)

    ...red

Re:converting PChar to String


Quote
Alex Druinsky <adr...@netvision.net.il> wrote:
>Hi
>I'm trying to write a program, where one of the functions should return
>a string. However, I have to use the function FileSplit (from the WinDos
>unit), and it returns PChar. when I try to assign str:=pchar^, the
>string contains only the first character of the PChar. How do I go
>conver a PChar to a String?
>This is the function:
>function Full2Name (str:string):string;
>var
> dir, name, ext:pchar;
>begin
> filesplit (@str, dir, name, ext);
> full2name:=name^;
>end;

First, check if Extended Syntax ($X+) is enabled. Next, use str:=PChar
(PChar is *NOT* a pointer, it's different...). Mail me if it doesn't
work

Wottie
-------------------------------------------------------------
"World Wide Wottie"

'Gee, tose smilies look like aliens on my computer!'

Re:converting PChar to String


Quote
Wottie wrote:
> First, check if Extended Syntax ($X+) is enabled. Next, use str:=PChar
> (PChar is *NOT* a pointer, it's different...). Mail me if it doesn't
> work

Oh?  It's not a pointer?  From the online help:

  PChar:
 The predefined type PChar denotes a pointer to a null-terminated
string.

 PChar is declared as:
    type PChar = ^Char;

Certainly looks like a pointer to me.  ;-)

It's a pointer type which is given some special abilities by the
compiler, and an extra unit (Strings), is provided for complex
manipulations.

Quote
> Wottie
> -------------------------------------------------------------
> "World Wide Wottie"

--
Scott Earnest        | We now return you to our regularly |
set...@ix.netcom.com | scheduled chaos and mayhem. . . .  |

Re:converting PChar to String


In article <33a49201.16130...@news.concentric.net>,
   slpo...@concentric.net (Stephen Posey) wrote:

Quote
>On Sun, 15 Jun 1997 16:37:20 +0300, Alex Druinsky
><adr...@netvision.net.il> wrote:

>>Hi

>>I'm trying to write a program, where one of the functions should return
>>a string. However, I have to use the function FileSplit (from the WinDos
>>unit), and it returns PChar. when I try to assign str:=pchar^, the
>>string contains only the first character of the PChar. How do I go
>>conver a PChar to a String?

>>This is the function:

>>function Full2Name (str:string):string;
>>var
>> dir, name, ext:pchar;

>>begin
>> filesplit (@str, dir, name, ext);
>> full2name:=name^;
>>end;

>Try:

>  full2name := StrPas( name ) ;

But remember to double-check that the length of name is <=255. Otherwise
you might destroy something or get a GPF!

Just check the following program:

Program StrBad;
uses strings  {$IfDef Windows} ,WinCrt {$EndIf};
const n=50000;
var s:String;
    p:PChar;
begin
  GetMem(p,n+1);
  FillChar(p^,n,'!');
  Mem[Seg(p^):Ofs(p^)+n]:=0;
  s:=StrPas(p);
  StrDispose(p);
  WriteLn(s)
end.

For n<=255 everything is OK. For larger n the first problem is that the
length of the string (s[0]) is n mod 256. But the main problem is that
it overwrites memory following s, so you destroy something or get a GPF.

The error is in the strings unit and is not the only bug I have located
in there! Unfortunately I have not found any notice about the bugs in
the strings unit in the bugs lists that exist (BP7Bugs2 and TVBugs31).
If anyone knows of another source for bugs, please let me know.

Babis Athineos

--
E-mail: ba...@hol.gr
WWW : http://users.hol.gr/~babis
S-mail: Papadoniou 61, 11145 Athens, Greece

Re:converting PChar to String


In article <5obunb$7m8_...@ppp10.hol.gr> of Thu, 19 Jun 1997 18:44:59 in
comp.lang.pascal.borland, Babis Athineos <ba...@hol.gr> wrote:

Quote
>For n<=255 everything is OK. For larger n the first problem is that the
>length of the string (s[0]) is n mod 256. But the main problem is that
>it overwrites memory following s, so you destroy something or get a GPF.

>The error is in the strings unit and is not the only bug I have located
>in there! Unfortunately I have not found any notice about the bugs in
>the strings unit in the bugs lists that exist (BP7Bugs2 and TVBugs31).
>If anyone knows of another source for bugs, please let me know.

I suppose that the original bug-hunters have moved on to Delphi, leaving
their lists behind in various places.

Now that we have the Web, there is ample means for making details of
each bug available; the problem is largely one of indexing.

Hoe short an entry would suffice for each bug in a list?  Two lines?
Let's try yours :

S := StrPas(p) : if Length(p^)>255, S[0] wrong and S[256..] overwritten.
 http://babis.athineos.hol.gb/pascal/borland/bugs/strings/strpas#b27

Note - imaginary URL!   At that size, one could get hundreds of bugs in
an article the size of the average FAQ - I wonder if it would be worth
doing?  There would have to be a committment to maintaining it, and a
reliable system which could automatically post at the selected interval.

Or is there a better scheme?
--
John Stockton, Surrey, UK.    j...@merlyn.demon.co.uk    Turnpike v1.12    MIME.
  Web URL: http://www.merlyn.demon.co.uk/ -- includes FAQqish topics and links.
  Correct 4-line sig separator is as above, a line comprising "-- " (SoRFC1036)
  Before a reply, quote with ">" / "> ", known to good news readers (SoRFC1036)

Re:converting PChar to String


Quote
Babis Athineos (ba...@hol.gr) wrote:
> The error is in the strings unit and is not the only bug I have located
> in there!

How true! Missing checks for NIL pointers in many places and more! :-(
My own version of the strings unit is heavily patched! Unfortunately,
it still contains some of the original code, so I may not give away the
corrected version. Isn't proprietary software a wonderful thing,
especially when it's unsupported? :-(

Quote
> If anyone knows of another source for bugs, please let me know.

http://www.microsoft.com ;-)

--
Frank Heckenbach, Erlangen, Germany
heck...@mi.uni-erlangen.de
Turbo Pascal:   http://www.mi.uni-erlangen.de/~heckenb/programs.htm
Internet links: http://www.mi.uni-erlangen.de/~heckenb/links.htm

Re:converting PChar to String


Dr John Stockton <j...@merlyn.demon.co.uk> wrote:

Quote
>I suppose that the original bug-hunters have moved on to Delphi, leaving
>their lists behind in various places.

>Now that we have the Web, there is ample means for making details of
>each bug available; the problem is largely one of indexing.

>Hoe short an entry would suffice for each bug in a list?  Two lines?
>Let's try yours :

>S := StrPas(p) : if Length(p^)>255, S[0] wrong and S[256..] overwritten.
> http://babis.athineos.hol.gb/pascal/borland/bugs/strings/strpas#b27

I agree that
 S := StrPas(p) : if StrLen(p) > 255, length(s) is wrong.

But fail to find where any overwriting takes place.  50000 mod
255 is 80, and StrPas does return an 80 character string.
However, even is s is declared as string[20] nothing beyond s is
altered.

Quote
>Note - imaginary URL!   At that size, one could get hundreds of bugs in
>an article the size of the average FAQ - I wonder if it would be worth
>doing?  There would have to be a committment to maintaining it, and a
>reliable system which could automatically post at the selected interval.

>Or is there a better scheme?

I don't know if there is a better solution or not, but I think
it would be a worthwhile thing.  I'm afraid if bug reports were
not validated, the list might contain a number of erroneous,
incomplete, or exaggerated entries.  Such a list would still
serve to warn people of things to be concerned about.

    ...red

--
Support the anti-Spam amendment
  Join at http://www.cauce.org/

Re:converting PChar to String


In article <33c1d32c.208347...@news.southeast.net>,
   rdon...@southeast.net (R.E.Donais) wrote:

Quote
>Dr John Stockton <j...@merlyn.demon.co.uk> wrote:

>>I suppose that the original bug-hunters have moved on to Delphi,
leaving
>>their lists behind in various places.

>>Now that we have the Web, there is ample means for making details of
>>each bug available; the problem is largely one of indexing.

>>Hoe short an entry would suffice for each bug in a list?  Two lines?
>>Let's try yours :

>>S := StrPas(p) : if Length(p^)>255, S[0] wrong and S[256..]
overwritten.
>> http://babis.athineos.hol.gb/pascal/borland/bugs/strings/strpas#b27

I was thinking of something more organized... In BP7Bugs2 you can find
about 40 bugs in BP7. In TVBugs31 you can find about the same number
of bugs in TV2. I find very little purpose (if at all) in making a
note of one (1) bug in a web page; then you should visit 40 pages to
collect what you can easily find in one of the mentioned bug lists. So
I wonder if there is any interest to enrich the existing bug lists and
put them in certain web pages...

Quote
>I agree that
> S := StrPas(p) : if StrLen(p) > 255, length(s) is wrong.

>But fail to find where any overwriting takes place.  50000 mod
>255 is 80, and StrPas does return an 80 character string.
>However, even is s is declared as string[20] nothing beyond s is
>altered.

You can find the reason of overwriting or GPF by examining the RTL
source (file Strings.Pas). You will see that there is a MOVSB with
CX=StrLen(PCharString). So copying takes place even after the "end"
of the 255 characters. OTOH the string length is assigned by
MOV AL,CL and STOSB, so it is StrLen(PCharString) mod 256 (the high
byte in CH is lost).

Babis Athineos

--
E-mail: ba...@hol.gr
WWW : http://users.hol.gr/~babis
S-mail: Papadoniou 61, 11145 Athens, Greece

Re:converting PChar to String


In article <5ouk7a$7m8_...@ppp9.hol.gr> of Thu, 26 Jun 1997 20:42:18 in
comp.lang.pascal.borland, Babis Athineos <ba...@hol.gr> wrote:

Quote

>>Dr John Stockton <j...@merlyn.demon.co.uk> wrote:
>>>I suppose that the original bug-hunters have moved on to Delphi,
>>>leaving their lists behind in various places.
>>>Now that we have the Web, there is ample means for making details of
>>>each bug available; the problem is largely one of indexing.

>>>How short an entry would suffice for each bug in a list?  Two lines?
>>>Let's try yours :

>>>S := StrPas(p) : if Length(p^)>255, S[0] wrong and S[256..]
>>>overwritten.
>>> http://babis.athineos.hol.gb/pascal/borland/bugs/strings/strpas#b27

>I was thinking of something more organized... In BP7Bugs2 you can find
>about 40 bugs in BP7. In TVBugs31 you can find about the same number
>of bugs in TV2. I find very little purpose (if at all) in making a
>note of one (1) bug in a web page; then you should visit 40 pages to
>collect what you can easily find in one of the mentioned bug lists.

Certainly.  What I forgot to write was that the terse list would be
short enough to be posted to News as a Bug-Faq at fairly frequent
intervals.  It would just be an index, reminder, and warning.  The
entries would point either to existing URLs (for cases where the expert
on that bug wished to have immediate control of the text) or to a
collected list (or both).  The authors of the existing lists might wish
to keep them as they are, so there would then be another list for the
new ones.

H'mm.  I wonder if GNU Pascal has an option to include the "standard"
bugs <g>?

Quote
> So
>I wonder if there is any interest to enrich the existing bug lists and
>put them in certain web pages...

There should be.

--
John Stockton, Surrey, UK.    j...@merlyn.demon.co.uk    Turnpike v1.12    MIME.
  Web URL: http://www.merlyn.demon.co.uk/ -- includes FAQqish topics and links.
  Correct 4-line sig separator is as above, a line comprising "-- " (SoRFC1036)
  Before a reply, quote with ">" / "> ", known to good news readers (SoRFC1036)

Re:converting PChar to String


In article <5obunb$7m8_...@ppp10.hol.gr> of Thu, 19 Jun 1997 18:44:59 in
comp.lang.pascal.borland, Babis Athineos <ba...@hol.gr> wrote:

Quote
>But remember to double-check that the length of name is <=255. Otherwise
>you might destroy something or get a GPF!

>Just check the following program:

>Program StrBad;
>uses strings  {$IfDef Windows} ,WinCrt {$EndIf};
>const n=50000;
>var s:String;
>    p:PChar;
>begin
>  GetMem(p,n+1);
>  FillChar(p^,n,'!');
>  Mem[Seg(p^):Ofs(p^)+n]:=0;
>  s:=StrPas(p);
>  StrDispose(p);
>  WriteLn(s)
>end.

>For n<=255 everything is OK. For larger n the first problem is that the
>length of the string (s[0]) is n mod 256. But the main problem is that
>it overwrites memory following s, so you destroy something or get a GPF.

The error is in the strings unit ...

This is my modified prohram :

program StrBad ;
uses {$IfDef Windows} WinCrt, {$EndIf} Strings ;
const n = 50000 ; SL = 83 ;
var R : record S : string [SL] ; Guard : char end ;
p : PChar ;
begin
  GetMem(p, n+1) ;
  FillChar(p^, n, '!') ;
  Mem[Seg(p^):Ofs(p^)+n] := 0 ;
  R.Guard := #251 ;
  with R do begin Write(1) ;
    S:=StrPas(p) ; Write(2) ;
    StrDispose(p) ; Writeln(3) ;
    WriteLn('  R: S=[', Length(S), ']"', S, '"; Guard="', Guard, '"') ;
    end ;
  Readln ;
  end.

In Protected mode, it gives Error 216, GPF, between 1 & 2 (in StrPas, at
STOSB).  This seems O.K., StrPas is being asked to exceed the possible;
but I don't yet see the exact reason for the GPF.

In Real mode, the program runs, Guard is *NOT* affected; but the PChar
length seems to undergo "mod 256" within the function *before* the
assignment truncates it to fit S.  Thus, if SL>Lo(n), S is shorter than
it should be.  

I see StrCopy's on-line help admits to no length-checking.

General thought : how useful would it be to implement a "Reference"
version of units such as Strings, using pure Pascal (TP/BP, but as near
ISO as possible) instead of asm?  Good for testing and for porting to
GNU; IMHO greater size and reduced speed would often be acceptable.

--
John Stockton, Surrey, UK.    j...@merlyn.demon.co.uk    Turnpike v1.12    MIME.
  Web URL: http://www.merlyn.demon.co.uk/ -- includes FAQqish topics and links.
  Correct 4-line sig separator is as above, a line comprising "-- " (SoRFC1036)
  Before a reply, quote with ">" / "> ", known to good news readers (SoRFC1036)

Other Threads