Re: is strncpy useful at all?
From: Anthony Borla (ajborla_at_bigpond.com)
Date: 12/16/04
- Next message: Alwyn: "Re: Polymorphism"
- Previous message: Anthony Borla: "Re: is strncpy useful at all?"
- In reply to: Arthur J. O'Dwyer: "Re: is strncpy useful at all?"
- Next in thread: Alwyn: "Re: is strncpy useful at all?"
- Reply: Alwyn: "Re: is strncpy useful at all?"
- Reply: Arthur J. O'Dwyer: "Re: is strncpy useful at all?"
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
Date: Wed, 15 Dec 2004 23:20:45 GMT
"Arthur J. O'Dwyer" <ajo@nospam.andrew.cmu.edu> wrote in message
news:Pine.LNX.4.60-041.0412151140020.3459@unix44.andrew.cmu.edu...
>
> On Wed, 15 Dec 2004, Anthony Borla wrote:
> > "zentara" <zentara@highstream.net> wrote...
> >> I was looking at an example of strncpy.
> >> It was explained that it is better than strcpy because
> >> it specifies the maximum number of chars to copy.
> >> But this example just overflows anyway.
> [...]
> > You already got the explanations, so how about an example of
> > how you might implement these [well, similar] functions ?
>
> "Well, similar" indeed! Why didn't you take the extra five
> seconds and write the /correct/ function definitions?
>
Whilst I admit the return values in both functions are incorrect, and a
prototype name was mispelled, I believe the rest of the code is correct
given that:
* I was writing C, not C++, so no 'const' usage present
* Functions were not intended to be Standard-conforming,
merely, as described, 'similar' to the library functions
> > Besides, it's an excuse to be
> > wicked and play with pointers and 'goto' ;) !
>
> Only if you're looking for an excuse. They're trivial to
> write without 'goto'.
>
Too true. Whilst the errors were not intended, the 'goto' usage *was*
deliberate:
'...an excuse to be wicked ...' ;) !
even though, as you point out, unnecessary.
> > /* ====================================== */
> >
> > #include <stddef.h>
> >
> > char* strncpy(char* dest, char* src);
>
> BZZT!
>
> > char* strncpy(char* dest, char* src, size_t maxlen);
> >
> > int main(void)
> > {
> > char src[] = "ABCD";
> > char dest[10] = {'\0'};
> >
> > /* Some tests you may want to try ... */
> > strncpy(dest, src, 0);
> > strncpy(dest, src, 1);
> > strncpy(dest, src, 3);
> > strncpy(dest, src, 4);
> > strncpy(dest, src, 5);
> > strncpy(dest, src, 12);
>
> The last "test" invokes undefined behavior.
>
> >
> > /* Of course, these will blow up ... */
> > strncpy(NULL, src, 4);
> > strncpy(dest, NULL, 12);
>
> Correct; both invoke UB.
>
> > /* And this will blow up if 'src' isn't NUL terminated ... */
> > strncpy(dest, src, -1);
>
> Even if it is null-terminated, this one invokes UB as well.
>
> > return 0;
> > }
> >
> > char* strcpy(char* dest, char* src)
> > {
> > while (*src != '\0')
> > *dest++ = *src++;
> >
> > *dest = '\0'; return dest;
> > }
>
> This is /almost/ correct. The return value ought to be the
> old value of 'dest' (i.e., the first parameter to the function).
> You return a pointer to the terminating null byte of 'dest'.
> A correct implementation would be [UNTESTED CODE]
>
> char *strcpy(char *dst, const char *src)
> {
> char *olddst = dst;
> while ((*d++ = *s++) != '\0')
> continue;
> return olddst;
> }
>
> By the way, didn't anyone ever tell you that one-space
> tabs are unreadable? Try four spaces, or at least some
> value between 3 and 8.
>
No, but they have now - thank you, Arthur :) ! Seriously, I actually do use
2 space indentation but it may 'get lost' in the copy'n'pasting from source
code [fixed-width fonts] to e-mail client [proportional fonts].
> > char* strncpy(char* dest, char* src, size_t maxlen)
> > {
> > size_t len = 0;
> >
> > while (*src != '\0')
> > {
> > if (++len > maxlen)
> > goto STRNCPY_EXIT;
> >
> > *dest++ = *src++;
> > }
> >
> > STRNCPY_EXIT:
> > *dest = '\0'; return dest;
> > }
>
> This one is just utterly wrong, and poorly implemented to
> boot. (Why are you using 'goto' when 'break' would suffice?)
> This function tries to append a null byte to 'dest' no matter what,
> and never tries to null-pad the destination string up to 'maxlen'.
> It bears no resemblance to the standard 'strncpy' function, a correct
> implementation of which might be [UNTESTED CODE]
>
> char *strncpy(char *dst, const char *src, size_t n)
> {
> char *olddst = dst;
> while (n > 0 && (*d++ = *s++) != '\0')
> continue;
> while (n > 0)
> *d++ = '\0';
> return olddst;
> }
>
Not sure about the use of 'd' and 's', and might not 'n' need decrementing ?
Glad I'm not the only one who makes mistakes ;) !
>
> As Mike pointed out, C++ programmers should
> generally not be using either of these functions for
> string handling.
>
Indeed, but I'm pretty sure I was writing C code ;) !
Cheers,
Anthony Borla
P.S.
A slightly refined, more complete version [note 'runTest' is deliberately
not self-checking]:
/* -------------------------------------------*/
#include <stddef.h>
#include <string.h>
#include <stdio.h>
typedef char* (*FP_STRNCPY)(char* dest, char* src, size_t maxlen);
char* tstrcpy(char* dest, char* src);
char* tstrncpy(char* dest, char* src, size_t maxlen);
void runTest(FP_STRNCPY fp, char* dest, char* src, size_t maxlen,
size_t destlen);
#define DEST_SIZE 10
int main(void)
{
char src[] = "ABCD"; char dest[DEST_SIZE + 1];
/* Some tests you may want to try ... */
runTest(tstrncpy, dest, src, 0, DEST_SIZE);
runTest(tstrncpy, dest, src, 1, DEST_SIZE);
runTest(tstrncpy, dest, src, sizeof src - 1, DEST_SIZE);
runTest(tstrncpy, dest, src, sizeof src, DEST_SIZE);
runTest(tstrncpy, dest, src, sizeof src + 1, DEST_SIZE);
runTest(tstrncpy, dest, src, DEST_SIZE, DEST_SIZE);
runTest(tstrncpy, dest, src, -1, DEST_SIZE);
// runTest(tstrncpy, NULL, src, 0, DEST_SIZE);
return 0;
}
char* tstrcpy(char* dest, char* src)
{
char* odest = dest;
while (*src != '\0')
*dest++ = *src++;
*dest = '\0'; return odest;
}
char* tstrncpy(char* dest, char* src, size_t maxlen)
{
size_t len = 0; char* odest = dest;
/* Don't alter destination if zero-valued 'maxlen' */
if (maxlen < 1)
return odest;
/* Guard against non NUL-terminated buffer */
while (*src != '\0' && len++ < maxlen)
*dest++ = *src++;
/* NUL-fill buffer remnants (added for Standards-conformance) */
if (len < maxlen)
while (len++ < maxlen)
*dest++ = '\0';
*dest = '\0'; return odest;
}
void runTest(FP_STRNCPY fp, char* dest, char* src, size_t maxlen,
size_t destlen)
{
char* rdest = NULL;
if (dest == NULL || src == NULL)
printf("Arguments NULL-valued - test may 'blow up'\n");
memset(dest, 'X', destlen);
printf("src: %4x:%s\n", src, src);
printf("dest: %4x:%s\n", dest, dest);
printf("maxlen: %u\n", maxlen);
printf("destlen: %u\n", destlen);
printf("rdest: %4x:%s\n", rdest,
rdest == NULL ? "NULL" :
*rdest == '\0' ? "EMPTY" : rdest);
rdest = fp(dest, src, maxlen);
printf("rdest: %4x:%s\n\n", rdest,
rdest == NULL ? "NULL" :
*rdest == '\0' ? "EMPTY" : rdest);
fflush(stdout);
return;
}
/* -------------------------------------------*/
- Next message: Alwyn: "Re: Polymorphism"
- Previous message: Anthony Borla: "Re: is strncpy useful at all?"
- In reply to: Arthur J. O'Dwyer: "Re: is strncpy useful at all?"
- Next in thread: Alwyn: "Re: is strncpy useful at all?"
- Reply: Alwyn: "Re: is strncpy useful at all?"
- Reply: Arthur J. O'Dwyer: "Re: is strncpy useful at all?"
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
Relevant Pages
|