Computer Science Canada

C TYS

Author:  wtd [ Mon Dec 11, 2006 11:40 pm ]
Post subject:  C TYS

Consider:

code:
void strcpy(char *dest, char *src)
{
   while (*dest++ = *src++);
}


Implement the smallest change possible to this to get a function with the following signature.

code:
void strcat(char *dest, char *src);

Author:  wtd [ Mon Dec 11, 2006 11:45 pm ]
Post subject: 

Extra kudos to the programmer who can explain the performance issue with repeated uses of the resulting strcat function, and how it can be remedied.

Author:  ericfourfour [ Tue Dec 12, 2006 1:06 am ]
Post subject: 

For the extra kudos:
msdn2 wrote:
"Because strcat does not check for sufficient space in strDestination before appending strSource, it is a potential cause of buffer overruns."
(http://msdn2.microsoft.com/en-us/library/h1x0y282(VS.80).aspx)

If you want to avoid it, here is a useful guide. Here is one quote from that page that might answer the question though:
msdn2 wrote:
"Preventing buffer overruns is primarily about writing good code. Always validate all your inputs and fail gracefully when necessary."

I guess you should give the kudos to the person who understands what all of that means though. Very Happy

Author:  wtd [ Tue Dec 12, 2006 1:10 am ]
Post subject: 

Not bad, but the problem I asked about was performance related. Smile

Author:  md [ Tue Dec 12, 2006 2:12 am ]
Post subject: 

As there really isn't any ways of checking that the character array is big enough before adding to it without changing the function to accept maximum lengths... you really have to ignore buffer overruns.

Oh, I know the answer; and I almost figured it out entirely on my own before giving in ask asking for the wtd's version Razz

Author:  Monstrosity_ [ Tue Dec 12, 2006 12:03 pm ]
Post subject: 

wtd wrote:
Extra kudos to the programmer who can explain the performance issue with repeated uses of the resulting strcat function, and how it can be remedied.

If you mean calling the function with the same 'dest' repeatedly, then the performance issue would be the need to traverse the character array (which would get increasingly larger with each call) looking for the null character. A way to avoid this is returning something meaningful.

Author:  wtd [ Tue Dec 12, 2006 1:36 pm ]
Post subject: 

What would be "meaningful"? Smile

Author:  md [ Tue Dec 12, 2006 3:24 pm ]
Post subject: 

The end of the character string after concatenation Wink

Author:  Monstrosity_ [ Tue Dec 12, 2006 4:16 pm ]
Post subject: 

wtd wrote:
What would be "meaningful"? Smile

Yes, I left that part vague for the same reason I didn't do the actual TYS. Which besides laziness, was that I'll leave it for someone else who wishes to test thier skills ;p. Also, I'm sure when people actually do write the code, they will be able to come up with some more (perhaps less important) performance issues.

md gave a good meaningful return value, I can think of at least one more. Lets see what people can come up with...

Author:  [Gandalf] [ Tue Dec 12, 2006 9:08 pm ]
Post subject: 

My first, not so good, but working attempt:
c:
void strcat(char *dest, char *src)
{
   int len = 0;
   while (*(dest+len++) != '\0');
   while (*(dest+++sizeof(char)*len-1) = *src++);
}

Please excuse the lack of whitespace.

Author:  wtd [ Tue Dec 12, 2006 9:22 pm ]
Post subject: 

Much simpler than that, Gandalf. Smile

Do you understand how the strcpy function works?

Author:  Andy [ Tue Dec 12, 2006 9:28 pm ]
Post subject: 

tsk tsk gandalf...

c++:

void strcat(char *dest, char *src)
{
    while (*dest++ = (*dest)?*dest:*src++);
}



for strings that do not end with a substring of 0s

c++:

void strcat(char *dest, char *src)
{
    while (*dest++ = (*dest) ? *dest: *((src+=1 + (*(dest+1)=0)) -1));
}

Author:  wtd [ Tue Dec 12, 2006 10:16 pm ]
Post subject: 

Simpler than that. Razz

Author:  Monstrosity_ [ Tue Dec 12, 2006 10:35 pm ]
Post subject: 

Sorry guys, couldn't help myself Smile

[Gandalf] wrote:
My first, not so good, but working attempt:
c:
void strcat(char *dest, char *src)
{
   int len = 0;
   while (*(dest+len++) != '\0');
   while (*(dest+++sizeof(char)*len-1) = *src++);
}

Please excuse the lack of whitespace.


sizeof(char) == 1

Andy wrote:
tsk tsk gandalf...

c++:

void _strcat(char *dest, char *src)
{
    while (*dest++ = (*dest) ? *dest: *((src+=1 + (*(dest+1)=0)) -1));
}


I can't speak for C++, but in C we call this undefined behaviour. A variable can only be modified once in an expression.

Author:  Monstrosity_ [ Tue Dec 12, 2006 10:54 pm ]
Post subject: 

uhg, is there no edit button or am I blind?

Anyway, I reread what I wrote and it's not that your modifying a variable twice, it's that your both modifying and reading a variable in the same expression. Sorry about that.

Author:  [Gandalf] [ Tue Dec 12, 2006 11:02 pm ]
Post subject: 

Nope, no edit button in help forums because it was abused.
wtd wrote:
Much simpler than that, Gandalf. Smile

Do you understand how the strcpy function works?

Well, I assumed so. Razz Even simpler than Andy's too? Something with recursion maybe?

And yes, I'm quite confident in my understanding of your strcpy function.

Author:  md [ Wed Dec 13, 2006 12:51 am ]
Post subject: 

c++:

char *cat(char *dest, char *src)
{
    while( *dest ) dest++;
    while( *dest++ = *src++ ) ;
    return dest;
}


please excuse any typos... beer makes typing hard.

Author:  Andy [ Wed Dec 13, 2006 5:44 am ]
Post subject: 

ohh, multiple lines! lol.

md, you cant return a pointer when your functions shifts it. but i'm sure that was just the beer thinking =P

Author:  bugzpodder [ Wed Dec 13, 2006 9:29 am ]
Post subject: 

Andy wrote:
tsk tsk gandalf...

c++:

void strcat(char *dest, char *src)
{
    while (*dest++ = (*dest)?*dest:*src++);
}




tsk tsk Andy...

c++:

while ((*d++) || *d = *s++);

Author:  Monstrosity_ [ Wed Dec 13, 2006 11:43 am ]
Post subject: 

Andy wrote:
md, you cant return a pointer when your functions shifts it.

And why not?

Author:  md [ Wed Dec 13, 2006 11:43 am ]
Post subject: 

Andy wrote:
ohh, multiple lines! lol.

md, you cant return a pointer when your functions shifts it. but i'm sure that was just the beer thinking =P


Sure you can! though it should really be return dest--;

I think bugzpodder's code is the shorted however...

Author:  wtd [ Wed Dec 13, 2006 12:15 pm ]
Post subject: 

md wrote:
I think bugzpodder's code is the shorted however...


And yet represents more of a change than the code I demonstrated to you. Wink

Author:  bugzpodder [ Wed Dec 13, 2006 12:44 pm ]
Post subject: 

the correct code should actually be:
[syntax]
while(*++d||(*d=*s++));
[/code]

because of a subtlety *++d is evaluated from left to right, so d gets deferenced first then increased

Quote:
And yet represents more of a change than the code I demonstrated to you.
What do you mean?

Author:  Monstrosity_ [ Wed Dec 13, 2006 1:00 pm ]
Post subject: 

bugzpodder wrote:
the correct code should actually be:
[syntax]
while(*++d||(*d=*s++));
[/code]

because of a subtlety *++d is evaluated from left to right, so d gets deferenced first then increased

The grouping for those two is right to left, (*(++d)). If it were (++(*d)), where d gets dereferenced first then incremented, then your stuck in loop where the pointer never changes.

Also, your increments in both examples would skip assigning/checking to the first value in the array. Try with d as an empty string.

wtd wrote:
md wrote:
I think bugzpodder's code is the shorted however...

And yet represents more of a change than the code I demonstrated to you. Wink

Hmm, I'm interested in what yours could be now. I would have just added another line to the strcpy function.

Author:  bugzpodder [ Wed Dec 13, 2006 1:23 pm ]
Post subject: 

I was too greedy. Tried to put everything in the conditional statement.

code:

while(*d||(*d=*s++))d++;


Take that, punk! Razz

Author:  bugzpodder [ Wed Dec 13, 2006 1:28 pm ]
Post subject: 

and before anyone claims andy's code is shorter, both code sets has comparable character counts, and my code do |d| less assignments than andy's code

Author:  wtd [ Wed Dec 13, 2006 1:33 pm ]
Post subject: 

code:
void strcat(char *dest, char *src)
{
   while (*dest) dest++;
   while (*dest++ = *src++);
}


This represents a very minimal change to the strcpy function as provided.

Author:  Monstrosity_ [ Wed Dec 13, 2006 1:40 pm ]
Post subject: 

wtd wrote:
code:
void strcat(char *dest, char *src)
{
   while (*dest) dest++;
   while (*dest++ = *src++);
}


This represents a very minimal change to the strcpy function as provided.



I would have done
code:
void strcat(char *dest, char *src)
{
   dest += strlen(dest);
   while (*dest++ = *src++);
}

same deal, just function call over head ;p

Author:  bugzpodder [ Wed Dec 13, 2006 1:44 pm ]
Post subject: 

then you might as well use memcpy

Author:  wtd [ Wed Dec 13, 2006 2:00 pm ]
Post subject: 

Monstrosity_ wrote:
code:
void strcat(char *dest, char *src)
{
   dest += strlen(dest);
   while (*dest++ = *src++);
}


This actually won't work. Wink

Anyone care to guess why?

Author:  md [ Wed Dec 13, 2006 2:02 pm ]
Post subject: 

I may have an issue with your code bugz (haven't tested it yet...) What if d has non-zero characters after the first '\0'? seems like your code would consider that part of the string and not copy s over it as should happen.

/me also notes that the code he psoted was given by wtd... after much though and almost having the same thing by me

Author:  md [ Wed Dec 13, 2006 2:21 pm ]
Post subject: 

[edit type follow up] damned help forums...

code showing a case where your loop fails bugz:
c++:
#include <stdio.h>
#include <string.h>

void cat(char *d, char*s) {
while( *d || ( *d = *s++ ) )
        d++;
}
 

main()
{     
        char dest[40];
        char src[5];

        strcpy(dest, "start   invisible ");
        dest[6] = '\0';

        strcpy(src, "end");

        cat(dest, src);
        printf("%s", dest);
}

Author:  bugzpodder [ Wed Dec 13, 2006 3:40 pm ]
Post subject: 

my code is based on andy's and i believe he put a disclaimer up on this issue, which was known to me. Note the "tsk tsk Andy"

Author:  bugzpodder [ Wed Dec 13, 2006 4:14 pm ]
Post subject: 

and heres a patched version md

code:
while(*d||((*d=*s++) && !(*(d+1)=0)))d++;

Author:  Andy [ Wed Dec 13, 2006 4:46 pm ]
Post subject: 

md wrote:
Andy wrote:
ohh, multiple lines! lol.

md, you cant return a pointer when your functions shifts it. but i'm sure that was just the beer thinking =P


Sure you can! though it should really be return dest--;


err what? at the end of your function, dest is at the end of the string. without knowing how long the string is, you cant set it the pointer back to the beginning

Author:  Andy [ Wed Dec 13, 2006 4:49 pm ]
Post subject: 

wtd wrote:
Monstrosity_ wrote:
code:
void strcat(char *dest, char *src)
{
   dest += strlen(dest);
   while (*dest++ = *src++);
}


This actually won't work. Wink

Anyone care to guess why?


works for me...

Author:  Monstrosity_ [ Wed Dec 13, 2006 5:10 pm ]
Post subject: 

wtd wrote:
Monstrosity_ wrote:
code:
void strcat(char *dest, char *src)
{
   dest += strlen(dest);
   while (*dest++ = *src++);
}

This actually won't work. Wink

Anyone care to guess why?

strlen is not declared. I figured that would be a given, but in all fairness this could cause trouble if you leave it up to the implicit function declaration.

Author:  Andy [ Wed Dec 13, 2006 8:23 pm ]
Post subject: 

oh! because if you include string.h, the function strcat with the same parameters would have existed already.

Author:  wtd [ Wed Dec 13, 2006 8:25 pm ]
Post subject: 

If you include string.h to get the strlen function, then you'd have mismatched types for strcat, as that is also present in string.h, but is not declared to return "void". Smile

Author:  Monstrosity_ [ Thu Dec 14, 2006 1:15 pm ]
Post subject: 

wtd wrote:
If you include string.h to get the strlen function, then you'd have mismatched types for strcat, as that is also present in string.h, but is not declared to return "void". Smile

True, _IF_ you include string.h. The code I had pasted didn't, so all it's missing is a declaration for strlen. Which of course the easiest and most portable way is to include the header, but not the only way. Smile

Author:  Monstrosity_ [ Thu Dec 14, 2006 1:20 pm ]
Post subject: 

And if you want to be even more pedantic then you can say the code is undefined because it uses a reserved identifier, but then how fun would the problem be?


: