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

­

­m½Z

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

Peter Pichler

­m½Z said:
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
 
S

Sean Kenwrick

­m½Z said:
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
 
R

Richard Bos

­m½Z said:
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
 
C

CBFalconer

Richard said:
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.


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

Peter Pichler

CBFalconer said:
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.
 
J

Joe Wright

Peter said:
CBFalconer said:
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.
 
C

CBFalconer

Peter said:
CBFalconer said:
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)
 
R

Richard Bos

CBFalconer said:
Richard said:
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
 
S

satyajit

CBFalconer said:
Peter said:
CBFalconer said:
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
 
C

CBFalconer

Richard said:
.... 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.
 
D

Dan Pop

In said:
Richard said:
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.


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
 
D

Dan Pop

In said:
Richard said:
... 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
 
P

Peter Pichler

Joe Wright said:
Peter said:
CBFalconer said:
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".
 
R

Richard Bos

CBFalconer said:
Richard said:
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
 
C

CBFalconer

Richard said:
CBFalconer said:
Richard said:
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.
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,483
Members
44,901
Latest member
Noble71S45

Latest Threads

Top