sizeof(str) or sizeof(str) - 1 ?

T

Trevor

If I have a string that should be NULL terminated, is it good practice to
use "sizeof(str)" or "sizeof(str) - 1" when using a function like strncpy?
If I have a 'string' that should NOT be NULL terminated, is it good practice
to use "sizeof(str) - 1" or "sizeof(str)" when using a function like
strncpy?

Is this function bug-free?

void setname(char *name)
{
char null_buf[256];
char buf[256];
strncpy(buf, name, sizeof(buf)); /* don't preserver NULL terminator */
strncpy(null_buf, name, sizeof(buf) - 1); /* preserve NULL terminator */
}
 
R

Régis Troadec

"Trevor" <[email protected]> a écrit dans le message de

Hi,
If I have a string that should be NULL terminated, is it good practice to
use "sizeof(str)" or "sizeof(str) - 1" when using a function like strncpy?
If I have a 'string' that should NOT be NULL terminated, is it good practice
to use "sizeof(str) - 1" or "sizeof(str)" when using a function like
strncpy?

When using strncpy, you deal with strings, perhaps much more accessed
through pointers than using arrays. In this case, sizeof isn't really
appropriate.
Why don't you use strlen instead of the sizeof operator ?
Is this function bug-free?

No, It probably crashes if name is null.
void setname(char *name)
{
char null_buf[256];
char buf[256];
strncpy(buf, name, sizeof(buf)); /* don't preserver NULL terminator */
strncpy(null_buf, name, sizeof(buf) - 1); /* preserve NULL terminator */

Both of these preserve the terminating null character if name is shorter
than 255 characters (including \0) and is zero-terminated.

If you don't wan't to keep the terminating null character, you'll do
someting like this :

void setname(const char * name)
{
char * buf;
/*...*/
if (name!= NULL)
{
buf = malloc(strlen(name));
strncpy(buf, name, strlen(name));
}
/*...*/
}

Regis
 
J

Joe Wright

Trevor said:
If I have a string that should be NULL terminated, is it good practice to
use "sizeof(str)" or "sizeof(str) - 1" when using a function like strncpy?
If I have a 'string' that should NOT be NULL terminated, is it good practice
to use "sizeof(str) - 1" or "sizeof(str)" when using a function like
strncpy?

Is this function bug-free?

void setname(char *name)
{
char null_buf[256];
char buf[256];
strncpy(buf, name, sizeof(buf)); /* don't preserver NULL terminator */
strncpy(null_buf, name, sizeof(buf) - 1); /* preserve NULL terminator */
}

A 'string' is NUL or '\0' terminated, by definition (not NULL). A
'string' is neither a variable nor a type. You can't apply sizeof to a
'string'. So let's start over with arrays of char.

char buf[256];

...is simply space, a place that can hold 256 variables of type char.

char *name = "Hello";

Now name points to a literal string of exactly six objects of type char.
The six are 'H', 'e', 'l', 'l', 'o', '\0'.

strncpy(buf, name, sizeof buf);

This will copy the six chars of name into buf and fill the remaining 250
chars of buf with '\0'.

strncpy(buf, name, sizeof buf - 1);

This will copy the six chars of name into buf and fill 249 of the
remaining 250 chars of buf with '\0'. Hmm? I'm not clear on your
'preserve the NUL terminator' question.
 
B

Barry Schwarz

If I have a string that should be NULL terminated, is it good practice to
use "sizeof(str)" or "sizeof(str) - 1" when using a function like strncpy?

sizeof is only useful if string is in an array whose definition is in
scope (not one passed in to a function). The answer to your question
is determined by whether or not you want to copy the terminal '\0'.
If I have a 'string' that should NOT be NULL terminated, is it good practice
to use "sizeof(str) - 1" or "sizeof(str)" when using a function like
strncpy?

If it is not '\0' terminated (not NULL which is something else), then
it is not a string by definition. The value that you use for strncpy
is based solely on the number of characters you want to copy.
Is this function bug-free?

void setname(char *name)
{
char null_buf[256];
char buf[256];
strncpy(buf, name, sizeof(buf)); /* don't preserver NULL terminator */
strncpy(null_buf, name, sizeof(buf) - 1); /* preserve NULL terminator */

Your comments are backwards. They are also misleading. If strncpy
detects a '\0', it will copy it in either case. Neither one will
overrun the destination array so they are bug free in that sense.


<<Remove the del for email>>
 
C

Christian Bau

"Trevor said:
If I have a string that should be NULL terminated, is it good practice to
use "sizeof(str)" or "sizeof(str) - 1" when using a function like strncpy?
If I have a 'string' that should NOT be NULL terminated, is it good practice
to use "sizeof(str) - 1" or "sizeof(str)" when using a function like
strncpy?

Just because strncpy is in the Standard C library doesn't mean you
should use it. Its definition makes it basically useless. First, lets
say you were generous and the size of str is 10000 bytes. Every call of
strncpy (str, "Hello", 10000) will copy five characters and then set
9995 bytes to zero. What's worse, you are not guaranteed to end up with
a legitimate string. I suggest writing your own function, like

void my_strncpy (char* dst, const char* src, size_t maxlen)
{
if (strlen (src) < maxlen) {
strcpy (dst, src);
} else if (maxlen > 0) {
memcpy (dst, src, maxlen - 1);
dst [maxlen - 1] = '\0';
}
}


Is this function bug-free?

void setname(char *name)
{
char null_buf[256];
char buf[256];
strncpy(buf, name, sizeof(buf)); /* don't preserver NULL terminator */
strncpy(null_buf, name, sizeof(buf) - 1); /* preserve NULL terminator */
}

If strlen (name) >= 255, then null_buf will contain the first 255
characters of name, followed by an indeterminate character, so it is
highly unlikely to be a legitimate C string.

What you can do:

strncpy (buf, name, sizeof (buf));
buf [sizeof (buf) - 1] = '\0';
or
strncpy (buf, name, sizeof (buf) - 1);
buf [sizeof (buf) - 1] = '\0';
 
C

Christian Bau

"Régis Troadec said:
"Trevor" <[email protected]> a écrit dans le message de

Hi,


When using strncpy, you deal with strings, perhaps much more accessed
through pointers than using arrays. In this case, sizeof isn't really
appropriate.
Why don't you use strlen instead of the sizeof operator ?

Because it is nonsense? To use strncpy, you must know how much space is
available to hold the result. If 1000 bytes of space are available, then
pass 1000 to strncpy. If I called strcpy (dst, "Hello") first, your idea
would mean that only the first five bytes of dst can be used. Worse yet,
it makes it impossible to copy a string to an uninitialised array.

Is this function bug-free?

No, It probably crashes if name is null.
void setname(char *name)
{
char null_buf[256];
char buf[256];
strncpy(buf, name, sizeof(buf)); /* don't preserver NULL terminator */
strncpy(null_buf, name, sizeof(buf) - 1); /* preserve NULL terminator */

Both of these preserve the terminating null character if name is shorter
than 255 characters (including \0) and is zero-terminated.

If you don't wan't to keep the terminating null character, you'll do
someting like this :

void setname(const char * name)
{
char * buf;
/*...*/
if (name!= NULL)
{
buf = malloc(strlen(name));
strncpy(buf, name, strlen(name));
}
/*...*/
}

Could you explain to us what that function would be good for? There is
no way for the caller to find out how many characters are stored in buf,
so that is useless. Oh, I noticed you forgot to return buf to the
caller... So you created a memory leak full of garbage data...
 
R

Régis Troadec

"Christian Bau" <[email protected]> a écrit dans le message
de
Hi,
>

Because it is nonsense? To use strncpy, you must know how much space is
available to hold the result. If 1000 bytes of space are available, then
pass 1000 to strncpy.

It's not a nonsense I think :
- How could you apply sizeof to a pointer ?
- Another common way to use strncpy() is to copy only the N first
characters of the source string in the destination string.

Sure, the main purpose of strncpy() is to provide a safer way to copy
strings than strcpy(), and I think that if you know the available space in
the destination buffer, you should directly pass it to strncpy(). In
strncpy, sizeof should be only applied to arrays whose size isn't known.
Could you explain to us what that function would be good for?

Answering to the OP question about obtaining a not null terminated *string*.
There is no way for the caller to find out how many characters are stored in buf,
so that is useless.

Sure he can: using strlen and adding another function argument.
Oh, I noticed you forgot to return buf to the
caller... So you created a memory leak full of garbage data...

But you did'nt notice my /*...*/ lines, which mean that you can have extra
code and other processings in the function, you could'nt guess. buf could
only be a local pointer to serve in many other processings in the function,
and would be of course freed as soon as it's useless.

Regis
 
E

Emmanuel Delahaye

I suggest writing your own function, like

void my_strncpy (char* dst, const char* src, size_t maxlen)
{
if (strlen (src) < maxlen) {
strcpy (dst, src);
} else if (maxlen > 0) {
memcpy (dst, src, maxlen - 1);
dst [maxlen - 1] = '\0';
}
}

I think that scanning the string twice (strlen(), strcpy()) is not a good
idea. Here is my STR_safecopy() (from my personal library at
http://mapage.noos.fr/emdel)

char *STR_safecopy (char *const des
,size_t const size
,char const *const src)
{
char *s_out = NULL;
if (des && size && src)
{
memcpy (des, src, size - 1);
des[size - 1] = 0;
s_out = des;
}

return s_out;
}
 
C

CBFalconer

Emmanuel said:
Christian Bau said:
I suggest writing your own function, like

void my_strncpy (char* dst, const char* src, size_t maxlen)
{
if (strlen (src) < maxlen) {
strcpy (dst, src);
} else if (maxlen > 0) {
memcpy (dst, src, maxlen - 1);
dst [maxlen - 1] = '\0';
}
}

I think that scanning the string twice (strlen(), strcpy()) is not
a good idea. Here is my STR_safecopy() (from my personal library at
http://mapage.noos.fr/emdel)

You can also use a prototype that has been well tested (see
references) and, in my implementation, does not use the standard
library at all. If the names strlcpy/strlcat create any problems
change them. BSD systems, will not, I believe, need any
implementation whatsoever. This code is deliberately minimized,
for performance reasons.

Please read the reference at:
<http://www.courtesan.com/todd/papers/strlcpy.html>

/* ------- file strlcpy.h ------- */
#ifndef strlcpy_h_
#define strlcpy_h_

#ifdef __cplusplus
extern "C" {
#endif

/* Implementation of strlcpy and strlcat
See http://www.courtesan.com/todd/papers/strlcpy.html

These routines are explicitly designed to move no
data and simply return the projected size of the
final strings when called with sz == 0.

In addition they treat src == NULL as an empty string

strlcat expects that the sz parameter is greater than
the size of the dst string. If not, the treatment is
exactly the same as if a sz value of 0 was used.

NOTE: these routines are deliberately designed to
not require any assistance from the standard
libraries. This makes them more useful in any
embedded systems that must minimize the load size.

Public domain, by C.B. Falconer
bug reports to mailto:[email protected]
*/

#include <stddef.h>

size_t strlcpy(char *dst, const char *src, size_t sz);
size_t strlcat(char *dst, const char *src, size_t sz);

#ifdef __cplusplus
}
#endif

#endif
/* ------- End file strlcpy.h ------- */

/* ------- file strlcpy.c ------- */
#include "strlcpy.h"

/* ---------------------- */

size_t strlcpy(char *dst, const char *src, size_t sz)
{
const char *start = src;

if (src && sz--) {
while ((*dst++ = *src))
if (sz--) src++;
else {
*(--dst) = '\0';
break;
}
}
if (src) {
while (*src++) continue;
return src - start - 1;
}
else if (sz) *dst = '\0';
return 0;
} /* strlcpy */

/* ---------------------- */

size_t strlcat(char *dst, const char *src, size_t sz)
{
char *start = dst;

while (*dst++) /* assumes sz >= strlen(dst) */
if (sz) sz--; /* i.e. well formed string */
dst--;
return dst - start + strlcpy(dst, src, sz);
} /* strlcat */

/* testing code snipped */
/* ------- End file strlcpy.c ------- */

Some comments and testing have been snipped. The unaltered files
are available at:

<http://cbfalconer.home.att.net/download/strlcpy.zip>
 

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

Forum statistics

Threads
473,731
Messages
2,569,432
Members
44,832
Latest member
GlennSmall

Latest Threads

Top