Why strncpy(s, t, n) doesn't put '\0' at the end?

Discussion in 'C Programming' started by ­m½Z, Jan 14, 2004.

  1. ­m½Z

    ­m½Z Guest

    I am a C programming beginner...
    I wonder, why strncpy(s, t, n) does not put '\0' at the end of the string.
    Because when I output the copied string, it output more than what I want,
    until I put '\0' at the end by myself.

    But, sometime I don't need put '\0' and it work well??
    Like
    strncpy(s, t, n);
    strcat(s, t1);
    .....
    work just what I want.
     
    ­m½Z, Jan 14, 2004
    #1
    1. Advertising

  2. "­m½Z" <> wrote in message
    news:bu2ups$5ns$...
    > I am a C programming beginner...
    > I wonder, why strncpy(s, t, n) does not put '\0' at the end of the string.
    > Because when I output the copied string, it output more than what I want,
    > until I put '\0' at the end by myself.
    >
    > But, sometime I don't need put '\0' and it work well??
    > Like
    > strncpy(s, t, n);
    > strcat(s, t1);
    > ....
    > work just what I want.


    It depends on how long the source string is. strncpy() copies up to n
    characters from t into s. If t is shorter than n characters, remaining
    characters in s are filled with zeros. If t is n characters long or longer,
    the first n characters are copied and that's it. All of this is explained in
    our manual. Have you read it first?

    Peter
     
    Peter Pichler, Jan 14, 2004
    #2
    1. Advertising

  3. "­m½Z" <> wrote in message
    news:bu2ups$5ns$...
    > I am a C programming beginner...
    > I wonder, why strncpy(s, t, n) does not put '\0' at the end of the string.
    > Because when I output the copied string, it output more than what I want,
    > until I put '\0' at the end by myself.
    >
    > But, sometime I don't need put '\0' and it work well??
    > Like
    > strncpy(s, t, n);
    > strcat(s, t1);
    > ....
    > work just what I want.
    >


    Thats just the way it works. If count is less than the length of the
    source string then you must null terminate yourself with:

    dest_str[count]='\0';

    If count is greater than the length of the source string then the
    destination string will be padded with 0s up to count. But you can still
    do the dest_str[count]='\0' (it is just redundant in this case).

    strncpy() is useful for ensuring that you never exceed the length of a
    string (causing a crash), and you should always use it if the source string
    could be longer than the destination string (or if you are not sure). If
    the source string was longer then the destination string will not be
    automatically null terminated so you should put a '\0' at the end yourself
    as follows:

    strncpy(dest_str,source_str,MAX_LEN_OF_DEST_STR);
    dest_str[MAX_LEN_OF_DEST_STR]='\0';

    If the source string was shorter that the destination string, the dest str
    will already be NULL terminated and the second line will be redudant (but so
    what!).

    NOTE that _memccpy(dest,source,0,count) is equivalent to
    strncpy(dest,source,count) but is generally much faster (at least on a
    Windows platform compiling with Borland or Microsoft compilers).

    Hope this helps...

    Sean
     
    Sean Kenwrick, Jan 14, 2004
    #3
  4. ­m½Z

    Richard Bos Guest

    "­m½Z" <> wrote:

    > I am a C programming beginner...
    > I wonder, why strncpy(s, t, n) does not put '\0' at the end of the string.


    Historical reasons. Originally, strncpy() was intended to work with a
    particular kind of fixed length, null-padded, not necessarily null-
    terminated char array, not with ordinary C strings at all.

    > Because when I output the copied string, it output more than what I want,
    > until I put '\0' at the end by myself.
    >
    > But, sometime I don't need put '\0' and it work well??


    What strncpy() does is copy as much of the source into the destination
    as required, but if the source is smaller than the limit, pad the rest
    with null characters. That means, of course, that the result will happen
    to be null-terminated as well; but it's also quite likely that it will
    have written more nulls than necessary.

    It's often better to use strncat() instead of strncpy(), if only for
    efficiency; instead of

    strncpy(dest, src, n);
    dest[n]='\0';

    you can use

    *dest='\0';
    strncat(dest, src, n);

    which will _also_ result in at most n characters, null-terminated, being
    written to dest, but will not have written all those extra null
    characters if src is short.

    Richard
     
    Richard Bos, Jan 14, 2004
    #4
  5. ­m½Z

    CBFalconer Guest

    Richard Bos wrote:
    > "­m½Z" <> wrote:
    >
    > > I am a C programming beginner...
    > > I wonder, why strncpy(s, t, n) does not put '\0' at the end of

    > the string.
    >
    > Historical reasons. Originally, strncpy() was intended to work with
    > a particular kind of fixed length, null-padded, not necessarily
    > null-terminated char array, not with ordinary C strings at all.
    >
    > > Because when I output the copied string, it output more than what
    > > I want, until I put '\0' at the end by myself.
    > >
    > > But, sometime I don't need put '\0' and it work well??

    >
    > What strncpy() does is copy as much of the source into the destination
    > as required, but if the source is smaller than the limit, pad the rest
    > with null characters. That means, of course, that the result will
    > happen to be null-terminated as well; but it's also quite likely that
    > it will have written more nulls than necessary.


    Why not simply write:

    strncpy(dst, src, n-1); dst[n] = '\0';

    You could encapsulate this in a macro. What it costs is the time
    spent to nul fill the destination on each call.

    #define STRNCPY(dst, src, n) \
    do {strncpy((dst), (src), (n)-1); dst[(n)] = '\0';} while (0)

    and dst and n expressions should not have side effects.

    A better solution IMO is to use strlcpy and strlcat, which are NOT
    standard. You can find an implementation on my pages, download
    section.

    --
    Chuck F () ()
    Available for consulting/temporary embedded and systems.
    <http://cbfalconer.home.att.net> USE worldnet address!
     
    CBFalconer, Jan 14, 2004
    #5
  6. "CBFalconer" <> wrote in message
    news:...
    > Why not simply write:
    >
    > strncpy(dst, src, n-1); dst[n] = '\0';


    ITYM
    strncpy(dst, src, n); dst[n-1] = '\0'; /* copies one char too many */
    or
    strncpy(dst, src, n); dst[n] = '\0'; /* or n-1, depending on n */

    IMO,
    strncpy(dst, src, n)[n] = '\0';
    is better. It's even syntactically safe.
     
    Peter Pichler, Jan 15, 2004
    #6
  7. ­m½Z

    Joe Wright Guest

    Peter Pichler wrote:
    >
    > "CBFalconer" <> wrote in message
    > news:...
    > > Why not simply write:
    > >
    > > strncpy(dst, src, n-1); dst[n] = '\0';

    >
    > ITYM
    > strncpy(dst, src, n); dst[n-1] = '\0'; /* copies one char too many */
    > or
    > strncpy(dst, src, n); dst[n] = '\0'; /* or n-1, depending on n */
    >
    > IMO,
    > strncpy(dst, src, n)[n] = '\0';
    > is better. It's even syntactically safe.


    Not so. Given the array dst[10] the element dst[10] does not exist.
    --
    Joe Wright http://www.jw-wright.com
    "Everything should be made as simple as possible, but not simpler."
    --- Albert Einstein ---
     
    Joe Wright, Jan 15, 2004
    #7
  8. ­m½Z

    CBFalconer Guest

    Peter Pichler wrote:
    > "CBFalconer" <> wrote in message
    >
    > > Why not simply write:
    > >
    > > strncpy(dst, src, n-1); dst[n] = '\0';

    >
    > ITYM
    > strncpy(dst, src, n); dst[n-1] = '\0'; /* copies one char too many */
    > or
    > strncpy(dst, src, n); dst[n] = '\0'; /* or n-1, depending on n */


    You have at least a point or two. Mea sloppy. Note to self:
    check boundary conditions.

    >
    > IMO,
    > strncpy(dst, src, n)[n] = '\0';
    > is better. It's even syntactically safe.


    Hey, that's sorta cute. Obfuscated, but cute. Maybe even:

    *(n + strncpy(dst, src, n)) = 0;
    or
    n[strncpy(dst, src, n)] = 0;
    or
    /* for dst of type array, not char * */
    /* This one may actually have some use !! */
    #define STRZCPY(dst, src) /
    (((sizeof dst)-1)[strncpy(dst, src, sizeof dst)] = 0);

    (WARN: newbies should not listen to this obscure maundering)

    --
    Chuck F () ()
    Available for consulting/temporary embedded and systems.
    <http://cbfalconer.home.att.net> USE worldnet address!
     
    CBFalconer, Jan 15, 2004
    #8
  9. ­m½Z

    Richard Bos Guest

    CBFalconer <> wrote:

    > Richard Bos wrote:
    > > "­m½Z" <> wrote:
    > >
    > > What strncpy() does is copy as much of the source into the destination
    > > as required, but if the source is smaller than the limit, pad the rest
    > > with null characters. That means, of course, that the result will
    > > happen to be null-terminated as well; but it's also quite likely that
    > > it will have written more nulls than necessary.

    >
    > Why not simply write:
    >
    > strncpy(dst, src, n-1); dst[n] = '\0';
    >
    > You could encapsulate this in a macro. What it costs is the time
    > spent to nul fill the destination on each call.


    Well, yes. That's why. On a single call that may seem trivial, but the
    total cost of a lot of strncpy() calls can be significant.

    > #define STRNCPY(dst, src, n) \
    > do {strncpy((dst), (src), (n)-1); dst[(n)] = '\0';} while (0)
    >
    > and dst and n expressions should not have side effects.
    >
    > A better solution IMO is to use strlcpy and strlcat, which are NOT
    > standard.


    Why use a non-Standard solution when

    dest[0]='\0'; strncat(dest, src, n);

    works just as well?

    Richard
     
    Richard Bos, Jan 15, 2004
    #9
  10. ­m½Z

    satyajit Guest

    CBFalconer <> wrote in message news:<>...
    > Peter Pichler wrote:
    > > "CBFalconer" <> wrote in message
    > >
    > > > Why not simply write:
    > > >
    > > > strncpy(dst, src, n-1); dst[n] = '\0';

    > >
    > > ITYM
    > > strncpy(dst, src, n); dst[n-1] = '\0'; /* copies one char too many */
    > > or
    > > strncpy(dst, src, n); dst[n] = '\0'; /* or n-1, depending on n */

    >
    > You have at least a point or two. Mea sloppy. Note to self:
    > check boundary conditions.
    >
    > >
    > > IMO,
    > > strncpy(dst, src, n)[n] = '\0';
    > > is better. It's even syntactically safe.


    Great!, How about

    #define STRNCPY(dst, src, n) (strncpy(dst, src, n)[n] = 0, dst)

    ?

    - Satyajit Rai
     
    satyajit, Jan 15, 2004
    #10
  11. ­m½Z

    CBFalconer Guest

    Richard Bos wrote:
    > CBFalconer <> wrote:
    >

    .... snip ...
    >
    > > #define STRNCPY(dst, src, n) \
    > > do {strncpy((dst), (src), (n)-1); dst[(n)] = '\0';} while (0)
    > >
    > > and dst and n expressions should not have side effects.
    > >
    > > A better solution IMO is to use strlcpy and strlcat, which are NOT
    > > standard.

    >
    > Why use a non-Standard solution when
    >
    > dest[0]='\0'; strncat(dest, src, n);
    >
    > works just as well?


    Because you have to pay peculiar attention to the value of n, and
    the result doesn't tell you when something has been truncated.

    --
    Chuck F () ()
    Available for consulting/temporary embedded and systems.
    <http://cbfalconer.home.att.net> USE worldnet address!
     
    CBFalconer, Jan 15, 2004
    #11
  12. ­m½Z

    Dan Pop Guest

    In <> CBFalconer <> writes:

    >Richard Bos wrote:
    >> "­m½Z" <> wrote:
    >>
    >> > I am a C programming beginner...
    >> > I wonder, why strncpy(s, t, n) does not put '\0' at the end of

    >> the string.
    >>
    >> Historical reasons. Originally, strncpy() was intended to work with
    >> a particular kind of fixed length, null-padded, not necessarily
    >> null-terminated char array, not with ordinary C strings at all.
    >>
    >> > Because when I output the copied string, it output more than what
    >> > I want, until I put '\0' at the end by myself.
    >> >
    >> > But, sometime I don't need put '\0' and it work well??

    >>
    >> What strncpy() does is copy as much of the source into the destination
    >> as required, but if the source is smaller than the limit, pad the rest
    >> with null characters. That means, of course, that the result will
    >> happen to be null-terminated as well; but it's also quite likely that
    >> it will have written more nulls than necessary.

    >
    >Why not simply write:
    >
    > strncpy(dst, src, n-1); dst[n] = '\0';
    >
    >You could encapsulate this in a macro. What it costs is the time
    >spent to nul fill the destination on each call.


    Then, use strncat which doesn't share any of the problems of strncpy:

    *dst = 0; strncat(dst, src, n-1);

    and can be trivially wrapped in a macro:

    #define STRNCPY(dst, src, n) (*(dst) = 0, strncat(dst, src, n))

    Dan
    --
    Dan Pop
    DESY Zeuthen, RZ group
    Email:
     
    Dan Pop, Jan 15, 2004
    #12
  13. ­m½Z

    Dan Pop Guest

    In <> CBFalconer <> writes:

    >Richard Bos wrote:
    >> CBFalconer <> wrote:
    >>

    >... snip ...
    >>
    >> > #define STRNCPY(dst, src, n) \
    >> > do {strncpy((dst), (src), (n)-1); dst[(n)] = '\0';} while (0)
    >> >
    >> > and dst and n expressions should not have side effects.
    >> >
    >> > A better solution IMO is to use strlcpy and strlcat, which are NOT
    >> > standard.

    >>
    >> Why use a non-Standard solution when
    >>
    >> dest[0]='\0'; strncat(dest, src, n);
    >>
    >> works just as well?

    >
    >Because you have to pay peculiar attention to the value of n,


    ???

    >and the result doesn't tell you when something has been truncated.


    You typically use such functions when you don't care about truncation.
    When truncation is not an option, you simply use strcpy and check the
    size of the input string.

    Dan
    --
    Dan Pop
    DESY Zeuthen, RZ group
    Email:
     
    Dan Pop, Jan 15, 2004
    #13
  14. "Joe Wright" <> wrote in message
    news:...
    > Peter Pichler wrote:
    > > "CBFalconer" <> wrote in message
    > > news:...
    > > > Why not simply write:
    > > >
    > > > strncpy(dst, src, n-1); dst[n] = '\0';

    > >
    > > ITYM
    > > strncpy(dst, src, n); dst[n-1] = '\0'; /* copies one char too many

    */
    > > or
    > > strncpy(dst, src, n); dst[n] = '\0'; /* or n-1, depending on n

    */
    >
    > Not so. Given the array dst[10] the element dst[10] does not exist.


    In that case, n == 9. That's why I said, "depending on n".
     
    Peter Pichler, Jan 15, 2004
    #14
  15. ­m½Z

    Richard Bos Guest

    CBFalconer <> wrote:

    > Richard Bos wrote:
    > > Why use a non-Standard solution when
    > >
    > > dest[0]='\0'; strncat(dest, src, n);
    > >
    > > works just as well?

    >
    > Because you have to pay peculiar attention to the value of n,


    Peculiar? What's so unusual about having to know the length of the
    memory area you're copying into? You _have_ to pass this length, or else
    you're back with plain strcpy().

    > and the result doesn't tell you when something has been truncated.


    That isn't always something you care about; and in any case, the
    original strncpy() call doesn't give you that information, either.

    Richard
     
    Richard Bos, Jan 16, 2004
    #15
  16. ­m½Z

    CBFalconer Guest

    Richard Bos wrote:
    >
    > CBFalconer <> wrote:
    >
    > > Richard Bos wrote:
    > > > Why use a non-Standard solution when
    > > >
    > > > dest[0]='\0'; strncat(dest, src, n);
    > > >
    > > > works just as well?

    > >
    > > Because you have to pay peculiar attention to the value of n,

    >
    > Peculiar? What's so unusual about having to know the length of the
    > memory area you're copying into? You _have_ to pass this length, or else
    > you're back with plain strcpy().
    >
    > > and the result doesn't tell you when something has been truncated.

    >
    > That isn't always something you care about; and in any case, the
    > original strncpy() call doesn't give you that information, either.


    Then go right ahead and use it. I really don't mind. I don't
    want to have to think about things, so the more natural the
    parameters are the better. The more info I get back the better,
    as long as it isn't misleading info.

    --
    Chuck F () ()
    Available for consulting/temporary embedded and systems.
    <http://cbfalconer.home.att.net> USE worldnet address!
     
    CBFalconer, Jan 16, 2004
    #16
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Neo Geshel
    Replies:
    2
    Views:
    3,625
    Versteijn
    Aug 18, 2004
  2. Simon
    Replies:
    3
    Views:
    709
    Simon
    Sep 6, 2004
  3. Replies:
    4
    Views:
    1,130
    Dave Moore
    Feb 1, 2005
  4. Mr. SweatyFinger
    Replies:
    2
    Views:
    2,002
    Smokey Grindel
    Dec 2, 2006
  5. Gabriel Rossetti
    Replies:
    3
    Views:
    556
    Jerry Hill
    Apr 25, 2008
Loading...

Share This Page