Board index » Visual Studio » TCHAR, terminating '\0' and _tcscat

TCHAR, terminating '\0' and _tcscat

Visual Studio193
I want to insert a string into a LPCSTR (a filename) and wrote the following

code which wasnt working:



... in my method....

"...

TCHAR newstring[250];

char *pdot = _tcsrchr(lpFileName,'.'); // lpFileName is LPCSTR

_tcsncpy(newstring,lpFileName,pdot-lpFileName);

_tcscat(newstring,_T("_added"));

_tcscat(newstring,pdot);

..."



The string "_added" is appended at the end of newstring (index 249) and not

immediately after the first copy-operation.

After changing the code into this everything is fine.



... in my method....

"...

TCHAR newstring[250];

char *pdot = _tcsrchr(lpFileName,'.'); // lpFileName is LPCSTR

_tcsncpy(newstring,lpFileName,pdot-lpFileName);

newstring[pdot-lpFileName] = '\0'; // this isnt documented - why?

_tcscat(newstring,_T("_added"));

_tcscat(newstring,pdot);

..."

My question is,

isnt there a simpler way to achieve this, especially setting the

terminating '\0'?



MD


-
 

Re:TCHAR, terminating '\0' and _tcscat

I am curious as to why you are not using CString instead of dealing with all

this needless complexity. Its operator LPCTSTR will be sufficient to pass it

on to relevant methods.



--

Ajay Kalra [MVP - VC++]

ajaykalra@yahoo.com





"Mark Daring" <cap_nemesis@hotmail.com>wrote in message

Quote
I want to insert a string into a LPCSTR (a filename) and wrote the

following

code which wasnt working:



... in my method....

"...

TCHAR newstring[250];

char *pdot = _tcsrchr(lpFileName,'.'); // lpFileName is LPCSTR

_tcsncpy(newstring,lpFileName,pdot-lpFileName);

_tcscat(newstring,_T("_added"));

_tcscat(newstring,pdot);

..."



The string "_added" is appended at the end of newstring (index 249) and

not

immediately after the first copy-operation.

After changing the code into this everything is fine.



... in my method....

"...

TCHAR newstring[250];

char *pdot = _tcsrchr(lpFileName,'.'); // lpFileName is LPCSTR

_tcsncpy(newstring,lpFileName,pdot-lpFileName);

newstring[pdot-lpFileName] = '\0'; // this isnt documented - why?

_tcscat(newstring,_T("_added"));

_tcscat(newstring,pdot);

..."

My question is,

isnt there a simpler way to achieve this, especially setting the

terminating '\0'?



MD









-

Re:TCHAR, terminating '\0' and _tcscat

When you use strncpy (_tcsncpy), it doesn't always put a NULL terminator on.

That is why you have to be careful with this function call.



There are many different ways to insert text into a filename. You can use

class methods (like CString) or use API calls to get the path, filename, ext

in section and build your own filespec from it.



Relvinian



"Mark Daring" <cap_nemesis@hotmail.com>wrote in message

Quote
I want to insert a string into a LPCSTR (a filename) and wrote the

following

code which wasnt working:



... in my method....

"...

TCHAR newstring[250];

char *pdot = _tcsrchr(lpFileName,'.'); // lpFileName is LPCSTR

_tcsncpy(newstring,lpFileName,pdot-lpFileName);

_tcscat(newstring,_T("_added"));

_tcscat(newstring,pdot);

..."



The string "_added" is appended at the end of newstring (index 249) and

not

immediately after the first copy-operation.

After changing the code into this everything is fine.



... in my method....

"...

TCHAR newstring[250];

char *pdot = _tcsrchr(lpFileName,'.'); // lpFileName is LPCSTR

_tcsncpy(newstring,lpFileName,pdot-lpFileName);

newstring[pdot-lpFileName] = '\0'; // this isnt documented - why?

_tcscat(newstring,_T("_added"));

_tcscat(newstring,pdot);

..."

My question is,

isnt there a simpler way to achieve this, especially setting the

terminating '\0'?



MD









-

Re:TCHAR, terminating '\0' and _tcscat

I've done it using CString and now just wanted to see what the "without MFC"

way is.

IMHO it is not complexer than with CString, only different methods :-)



MD



"Ajay Kalra" <ajaykalra@yahoo.com>schrieb im Newsbeitrag

Quote
I am curious as to why you are not using CString instead of dealing with

all

this needless complexity. Its operator LPCTSTR will be sufficient to pass

it

on to relevant methods.



--

Ajay Kalra [MVP - VC++]

ajaykalra@yahoo.com





"Mark Daring" <cap_nemesis@hotmail.com>wrote in message

news:e#eavSbfEHA.236@tk2msftngp13.phx.gbl...

>I want to insert a string into a LPCSTR (a filename) and wrote the

following

>code which wasnt working:

>

>... in my method....

>"...

>TCHAR newstring[250];

>char *pdot = _tcsrchr(lpFileName,'.'); // lpFileName is LPCSTR

>_tcsncpy(newstring,lpFileName,pdot-lpFileName);

>_tcscat(newstring,_T("_added"));

>_tcscat(newstring,pdot);

>..."

>

>The string "_added" is appended at the end of newstring (index 249) and

not

>immediately after the first copy-operation.

>After changing the code into this everything is fine.

>

>... in my method....

>"...

>TCHAR newstring[250];

>char *pdot = _tcsrchr(lpFileName,'.'); // lpFileName is LPCSTR

>_tcsncpy(newstring,lpFileName,pdot-lpFileName);

>newstring[pdot-lpFileName] = '\0'; // this isnt documented - why?

>_tcscat(newstring,_T("_added"));

>_tcscat(newstring,pdot);

>..."

>My question is,

>isnt there a simpler way to achieve this, especially setting the

>terminating '\0'?

>

>MD

>

>









-

Re:TCHAR, terminating '\0' and _tcscat

This behaviour is bad if you only use msdn and havent even thought about

setting the terminator yourself.

With CString its almost the same (2 lines less) and i was just interested in

doing it without CString (no special reason) in case MFC isnt there.



MD



"Relvinian" <m@msn.com>schrieb im Newsbeitrag

Quote
When you use strncpy (_tcsncpy), it doesn't always put a NULL terminator

on.

That is why you have to be careful with this function call.



There are many different ways to insert text into a filename. You can use

class methods (like CString) or use API calls to get the path, filename,

ext

in section and build your own filespec from it.



Relvinian



"Mark Daring" <cap_nemesis@hotmail.com>wrote in message

news:e%23eavSbfEHA.236@tk2msftngp13.phx.gbl...

>I want to insert a string into a LPCSTR (a filename) and wrote the

following

>code which wasnt working:

>

>... in my method....

>"...

>TCHAR newstring[250];

>char *pdot = _tcsrchr(lpFileName,'.'); // lpFileName is LPCSTR

>_tcsncpy(newstring,lpFileName,pdot-lpFileName);

>_tcscat(newstring,_T("_added"));

>_tcscat(newstring,pdot);

>..."

>

>The string "_added" is appended at the end of newstring (index 249) and

not

>immediately after the first copy-operation.

>After changing the code into this everything is fine.

>

>... in my method....

>"...

>TCHAR newstring[250];

>char *pdot = _tcsrchr(lpFileName,'.'); // lpFileName is LPCSTR

>_tcsncpy(newstring,lpFileName,pdot-lpFileName);

>newstring[pdot-lpFileName] = '\0'; // this isnt documented - why?

>_tcscat(newstring,_T("_added"));

>_tcscat(newstring,pdot);

>..."

>My question is,

>isnt there a simpler way to achieve this, especially setting the

>terminating '\0'?

>

>MD

>

>









-

Re:TCHAR, terminating '\0' and _tcscat

You need to learn reliable programming.



Think about:

1. What happens if there is no '.' in the string? (answer: the code crashes)

2. What happens if '.' if not part of a filename, but part of directory

name? (answer: "_added" is put to the directory name, which is not what you

want).

3. What happens if the file name is larger than countof(newstring) -

coountof("_added") ? (answer: buffer overflow, with security holes, etc)



See SHLWAPI.DLL functions. They are very usable in your case.



And, BTW, instead of _tcscat(newstring,_T("_added")); you just need

_tcscpy(newstring +pdot-lpFileName,_T("_added"));



to get rid of zero-byte problem



"Mark Daring" <cap_nemesis@hotmail.com>wrote in message

Quote
I want to insert a string into a LPCSTR (a filename) and wrote the

following

code which wasnt working:



... in my method....

"...

TCHAR newstring[250];

char *pdot = _tcsrchr(lpFileName,'.'); // lpFileName is LPCSTR

_tcsncpy(newstring,lpFileName,pdot-lpFileName);

_tcscat(newstring,_T("_added"));

_tcscat(newstring,pdot);

..."



The string "_added" is appended at the end of newstring (index 249) and

not

immediately after the first copy-operation.

After changing the code into this everything is fine.



... in my method....

"...

TCHAR newstring[250];

char *pdot = _tcsrchr(lpFileName,'.'); // lpFileName is LPCSTR

_tcsncpy(newstring,lpFileName,pdot-lpFileName);

newstring[pdot-lpFileName] = '\0'; // this isnt documented - why?

_tcscat(newstring,_T("_added"));

_tcscat(newstring,pdot);

..."

My question is,

isnt there a simpler way to achieve this, especially setting the

terminating '\0'?



MD









-

Re:TCHAR, terminating '\0' and _tcscat

tcsncat won't always append null terminator.

When declaring char arrays, its always a good idea to initialize with zeros

so you know whatever happens it will always be null terminated:



TCHAR newstring[250] = {0};



And as other poster says, what if '.' isn't there? You should always check:

if (pdot)

_tcsncpy(newstring,lpFileName,pdot-lpFileName);



Personally I'd prefer to do it the other way around, and avoid the pointer

arithmetic:

_tcsncpy(newstring, lpFileName, 249);

TCHAR *pdot = _tcsrchr(netwstring,'.');

if (pdot)

*pdot = 0;



Anyway, this will not work on UNICODE builds if like you say "lpFileName is

LPCSTR". Is that true even on Unicode builds?

If so you will need something like:

#if (defined UNICODE)

mbstowcs(newstring, lpFileName, 249);

#else

_tcsncpy(newstring, lpFileName, 249);

#endif

TCHAR *pdot = _tcsrchr(netwstring,'.');

if (pdot)

*pdot = 0;





"Mark Daring" <cap_nemesis@hotmail.com>wrote in message

Quote
I want to insert a string into a LPCSTR (a filename) and wrote the

following

code which wasnt working:



... in my method....

"...

TCHAR newstring[250];

char *pdot = _tcsrchr(lpFileName,'.'); // lpFileName is LPCSTR

_tcsncpy(newstring,lpFileName,pdot-lpFileName);

_tcscat(newstring,_T("_added"));

_tcscat(newstring,pdot);

..."



The string "_added" is appended at the end of newstring (index 249) and

not

immediately after the first copy-operation.

After changing the code into this everything is fine.



... in my method....

"...

TCHAR newstring[250];

char *pdot = _tcsrchr(lpFileName,'.'); // lpFileName is LPCSTR

_tcsncpy(newstring,lpFileName,pdot-lpFileName);

newstring[pdot-lpFileName] = '\0'; // this isnt documented - why?

_tcscat(newstring,_T("_added"));

_tcscat(newstring,pdot);

..."

My question is,

isnt there a simpler way to achieve this, especially setting the

terminating '\0'?



MD









-

Re:TCHAR, terminating '\0' and _tcscat

GuitarBill wrote:



Quote
tcsncat won't always append null terminator.

When declaring char arrays, its always a good idea to initialize with zeros

so you know whatever happens it will always be null terminated:



TCHAR newstring[250] = {0};



That doesn't guarantee newstring "will always be nul-terminated".



Quote
And as other poster says, what if '.' isn't there? You should always check:

if (pdot)

_tcsncpy(newstring,lpFileName,pdot-lpFileName);



If pdot-lpFileName>= 250, newstring will not be nul-terminated. If it's>

250, you have a buffer overrun. In both these cases, your initialization of

newstring is pure inefficiency, as you would observe exactly the same

behavior were you to eliminate it. It makes no sense to do a strncpy which

doesn't use the length of the destination string; it kinda misses the point

altogether. This is not the proper function to use. Here's one way to fix

it:



int len = pdot-lpFileName;

// Avoid magic numbers, but since it was used above...

if (len < 250)

*std::copy(lpFileName, pdot, newstring) = 0;

else

handle error



This std::copy call will copy the sequence [lpFileName, pdot) to newstring

and nul-terminate newstring. Note also that I don't need to initialize

newstring with 250 useless zeroes for this to work.



The function strncpy rarely makes any sense at all. If the source string is

longer than its length argument, it leaves the destination array truncated

and without a nul-terminator, and if it copies fewer characters than the

maximum allowed, it fills the remainder of the destination with zeroes. It's

quite the bizarre function.



Quote
Personally I'd prefer to do it the other way around, and avoid the pointer

arithmetic:

_tcsncpy(newstring, lpFileName, 249);

TCHAR *pdot = _tcsrchr(netwstring,'.');

if (pdot)

*pdot = 0;



You should be concerned with long filenames and truncation. What if the path

was:



C:\dir.ext\filename_pad_out_to_249_chars.oops



Your code relies on the fact you initialized newstring as you did above.

Logically, does it makes sense to fill an array with 250 zeroes and then

pretend that its size is only 249 characters? Moreover, what if the path

was:



C:\x.pad_out_to_1000_chars



Logically, does it make sense to copy (in this case) 249 characters, and

then throw away all but the first 4, just to avoid simple pointer

arithmetic?



--

Doug Harrison

Microsoft MVP - Visual C++

-