Re: TCHAR, terminating '\0' and _tcscat

Tech-Archive recommends: Repair Windows Errors & Optimize Windows Performance

From: Doug Harrison [MVP] (dsh_at_mvps.org)
Date: 08/10/04


Date: Mon, 09 Aug 2004 23:15:10 -0500

GuitarBill wrote:

>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".

>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.

>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++


Relevant Pages

  • Re: Array reinitialize
    ... |> | by a character string literal, ... |> | initialize the elements of the array." ... | is really 21 characters long. ... an array via an aggregate initialiser, ...
    (alt.comp.lang.learn.c-cpp)
  • Re: sending echo to all clients
    ... I did initialize it up properly, ... There is only one array and that is an array of pollfd structures named ... as an array of characters only but then I can't because sendsends bytes ... you receive C-style strings, so there's really no point to doing it. ...
    (comp.unix.programmer)
  • Re: sending echo to all clients
    ... I did initialize it up properly, ... There is only one array and that is an array of pollfd structures named ... as an array of characters only but then I can't because sendsends bytes ... So you are sending the clients the wrong number of bytes. ...
    (comp.unix.programmer)
  • Re: Character array initialization
    ... I expect your compilers will generate a diagnostic. ... characters with 6 non-null characters. ... sense to initialize an array of 5 characters with 6 characters. ...
    (comp.lang.c)
  • Re: compiler bugs
    ... In a language like C, the behavior of programs that reference ... Not if the unoptimizing compiler initializes all variables to some ... portion of the array in your algorithhm. ... that one actually does not need to initialize all variables (unlike ...
    (comp.compilers)