A lot of string functions return a pointer but What are the Advantages of return a pointer to destination and return destination?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *sstrcpy ( char *destination, const char *source ){ //return a pointer to destination
while ((*destination++ = *source++));
*destination='\0';
return destination;
}
char sstrcpy2 ( char *destination, const char *source ){ //return destination
while ((*destination++ = *source++));
*destination='\0';
return *destination;
}
int main(void){
char source[] = "Well done is better than well said";
char destination[40];
sstrcpy ( destination, source );
printf ( "%s\n", destination);
return 0;
}
The idea is to give the possibility to chain the functions. I.e. to pass one function result as a parameter to another one.
sstrcpy ( destination2, sstrcpy ( destination1, source ));
As for the proposed sstrcpy2 - it will only return a single, the last character of the copied string, which is apparently \0 in your implementation, which is rather useless in most cases.
Update:
Note that the implementation sstrcpy is incorrect as is, it will return the value of destination, which was already moved to the end of the string, and not the pointer to the beginning of it. Alternatively I would suggest saving the original pointer and increment it's copy instead:
char *sstrcpy ( char *destination, const char *source ){ //return a pointer to destination
char *dst = destination;
while ((*dst++ = *source++));
*dst='\0';
return destination;
}
Bug 1: you return the end of the string, not the beginning.
Bug 2: you add 2 null terminators at the end, instead of 1.
The correct implementation should be something along the lines of:
char* sstrcpy (char*restrict dst, const char*restrict src)
{
char* original = dst;
for(*dst = *src; *src != '\0'; dst++, src++)
{
*dst = *src;
}
return original;
}
where restrict is a contract with the caller that dst and src don't overlap. Please note that this might still be naive implementation - it is fine for small microcontrollers, but when it comes to library implementations of strcpy for 32 bit systems, they will work with aligned chunks of data.
What are the Advantages of return a pointer to destination and return destination?
There are no advantages whatsoever; the standard library is filled with oddities. This allows two kinds of pointless obfuscation:
// Bad code, do not use!
/*1*/ str = strcpy(str, src); // pointless and potentially dangerous
/*2*/ strcpy(str2, strcpy(str1, src)); // pointless and potentially dangerous
This in turn allows side effects in parameter evaluation to cause bugs, so it is dangerous. Don't write crap like that. The correct versions are:
/*1*/ strcpy(str, src);
/*2*/ strcpy(str1, src);
strcpy(str2, str1);
The latter versions are safer and easier to read. The resulting machine code will be identical.
Related
I am trying to create my own string copy function in C.
Copying the text works, however extra characters are added to the destination string at the end and I don't know why.
I would be very happy to get an answer.
Here is my code:
#include <stdio.h>
#include <string.h>
void copy(char *dst, char *src) {
int src_len = strlen(src);
char *src_strtng = &src[0];
char *dst_strtng = &dst[0];
for (int i = 0; i < src_len; i++) {
*dst_strtng++ = *src_strtng++;
}
printf("%s\n", dst);
}
int main() {
char srcString[] = "We promptly judged antique ivory buckles for the next prize!";
char dstString[strlen(srcString)];
copy(dstString, srcString);
}
create my own str copy function in C.
Missing null character termination
This is OP's key issue, lack of appending a null character to dst.
Only need to traverse src once
Rather than strlen() in copy(), just look for '\0'. *1
Does not return a char *
Save the destination pointer.
Prints output, yet strcpy() does not print anything.
Missing const for data referenced by src
Pedantic concern: str should act as if char was unsigned char *2
char *copy(char* dst, const char* src) {
unsigned char *udst = (unsigned char *) dst;
const unsigned char *usrc = (const unsigned char *) src;
do {
*udst++ = *usrc;
} while (*usrc++);
return dst;
}
Allocate enough space for the length of a string and a null character
strlen() returns the length of a string. That does not include the final null character.
int main() {
char srcString[] = "We promptly judged ...";
char dstString[strlen(srcString) + 1]; // Add 1
copy(dstString,srcString);
puts(dstString); // Print here, not in copy().
}
*1 C's strcpy() is char *strcpy(char * restrict s1, const char * restrict s2);
Note the restrict. This implies access via the pointer is not affected by other code. E.g. source string and destination will not overlap.
// Better as
char *copy(char* restrict dst, const char* restrict src) {
OP's use of strlen() in copy() is a good first step to handle overlapping memory (see following), but strcpy() does not need to handle that - suggest copy() not deal with overlap.
char *copy_handle_overlap(char* dst, const char* src) {
return memmove(dst, src, strlen(src) + 1);
}
*2 C string functions have:
For all functions in this subclause, each character shall be interpreted as if it had the type unsigned char (and therefore every possible object representation is valid and has a different value).
This is important for the rare non-2's complement to distinguish +0 from -0.
Non-2's complement support expected to be dropped with C2X.
I have to create a copy of some elements of the standard library in C and I have to create a copy of strcat. So I have to create a function that concatenate two strings in C. I know arrays in C can't change the allocated size. The only fonction i'm allowed to use is copies i made of strlen, strstr, and write() ... My code looks like this :
char *my_strcat(char *dest, char *src)
{
int dest_size;
int src_size;
int current_pos;
int free_space;
int pos_in_src;
src_size = my_strlen(src);
dest_size = my_strlen(dest);
while (dest[current_pos] != '\0')
current_pos = current_pos + 1;
free_space = dest_size - current_pos;
if (free_space < src_size)
return (0);
while (src[pos_in_src] != '\0')
{
dest[current_pos] = src[pos_in_src];
pos_in_src = pos_in_src + 1;
current_pos = current_pos + 1;
}
return (dest);
}
But I don't know how to declare my dest and src in the main.
I don't know how to create an array with a big size, declare it as a string like dest = "Hello\0" but this array has to still contains more than 6 characters.
Can you help me please ?
char dest[19] = "epite";
char *src = "chor42spotted";
my_strcat(dest, src);
Also, read the man for strcat(3)
the dest string must have enough space for the result.
https://linux.die.net/man/3/strcat
So your function is behaving incorrectly, you do not need to check that you have enough free space in dest
You want a function mystrcat which behaves exactly like stdlib strcat.
So the prototype is
/*
concatenate src to dest
dest [in / out] - the string to add to (buffer must be large enough)
src [in] - the string to concatenate.
Returns: dest (useless little detail for historical reasons).
*/
char *mystrcat(char *dest, const char *src);
Now we call it like this
int main(void)
{
char buff[1024]; // nice big buffer */
strcpy(buff, "Hello ");
mystrcat(buff, "world");
/* print the output to test it */
printf("%s\n", buff);
return 0;
}
But I'm not going to write mystrcat for you. That would make your homework exercise pointless.
The 1st parameter of the array simply has to be large enough to contain both strings + one null terminator. So if you for example have "hello" and "world", you need 5 + 5 +1 = 11 characters. Example:
#define LARGE_ENOUGH 11
int main (void)
{
char str[LARGE_ENOUGH] = "hello";
my_strcat(str, "world");
puts(str); // gives "helloworld"
}
In real world applications, you would typically allocate space for the array to either be same large number (couple of hundred bytes) or with a length based on strlen calls.
As for the implementation itself, your solution is needlessly complicated. Please note that the real strcat leaves all error checking to the caller. It is most likely implemented like this:
char* strcat (char* restrict s1, const char* restrict s2)
{
return strcpy(&s1[strlen(s1)], s2);
}
The most important part here is to note the const-correctness of the s2 parameter.
The restrict keywords are just micro-optimizations from the C standard, that tells the compiler that it can assume that the pointers point at different memory areas.
If you wish to roll out your own version with no library function calls just for fun, it is still rather easy, you just need two loops. Something like this perhaps:
char* lolcat (char* restrict s1, const char* restrict s2)
{
char* s1_end = s1;
while(*s1_end != '\0') // find the end of s1
{
s1_end++;
}
do // overwrite the end of s1 including null terminator
{
*s1_end = *s2;
s1_end++;
s2++;
} while(*s1_end != '\0'); // loop until the null term from s2 is copied
return s1;
}
I know that this strcpy function below is incorrect, but I cannot seem to figure out the one or two things I need to change to fix it. Any help would be greatly appreciated as I am completely stuck on this:
void strcpy(char *destString, char *sourceString)
{
char *marker, *t;
for(marker = sourceString, t = destString; *marker; marker++, t++)
*t = *marker;
}
Well it depends on your environment..
For example I see a few things I don't like:
You do not check for input parameters to be != NULL. This will cause a *0 access
I see you are not terminating your string with the '\0' character (or 0).. So, after the loop (please intent.) add *t = 0;
strcpy() is a predefined function and you are trying to create your own strcpy function. so, when you compile your program, you are getting conflicting types error. So, first rename your function name.
If you want to implement your own strcpy(), then i would suggest to implement strncpy(). It will copy at-most n-1 bytes from source null-terminated character array to destination character array and also add null character at the end of the destination character array.
void strcpy(char *dest, const char *src, size_t n)
{
if ((dest == NULL) || (src == NULL))
return;
int i;
for(i=0; i<(n-1) && src[i]; i++)
dest[i] = src[i];
dest[i]='\0';
}
It wouldn't let buffer overflow.
Note - My implementation is different from standard library strncpy() implementation. The standard library function strncpy() copies at most n bytes of src. If there is no null byte among the first n bytes of src, the string placed in dest will not be null-terminated.
I know that this strcpy function below is incorrect, but I cannot seem to figure out the one or two things I need to change to fix it.
You only need to add null character at the end of destination array.
void strcpy(char *destString, char *sourceString)
{
char *marker, *t;
for(marker = sourceString, t = destString; *marker; marker++, t++)
*t = *marker;
*t='\0';
}
This is a very simple aproach:
void copy(char * src, char * dst){
while(*src != '\0'){
*dst = *src;
src++;
dst++;
}
*dst = '\0';
}
int main(int argc, char** argv){
char src [] = "hello";
char dst [] = "----";
copy(src, dst);
printf("src: %s\n", src);
printf("dst: %s\n", dst );
}
It's more or less like wildplasser comment. First you iterate over the src pointer. In c, if you have '\0' (in a well formed string) then you can exit because it is the final character. Ok, you iterate over the src pointer and assign the value of src (*src) to the value of dst (*dst) and then you only have to increase both pointers...
It's all
A very easy strcpy function would be:
int strcpy(char *dest,char *source)
{
if (source==NULL)
{
printf("The source pointer is NULL");
return 0;
}
if (dest==NULL)
{
dest=(char*)malloc((strlen(source)+1)*sizeof(char));
}
int i;
for (i=0;source[i]!='\0';i++)
{
dest[i]=source[i];
}
dest[i]='\0';
return 1;
}
You should have no problem copying strings this way. Always use indexes instead of pointer operations, it's easier imo.
If you use an IDE, you should learn to use the debug function to discover the errors and problems, usually when you deal with strings one of the most common RUNTIME problems is the lack of a '\0', which automatically make your string functions go to memory zones where they shouldn`t be.
I'm getting a core dump that I have no clue how to solve. I have searched other questions and googled my problem but I just can't figure out how to solve this...
Here is the code:
const char checkExtension(const char *filename)
{
const char *point = filename;
const char *newName = malloc(sizeof(filename-5));
if((point = strrchr(filename,'.palz')) != NULL )
{
if(strstr(point,".palz") == 0)
{
strncpy(newName, filename, strlen(filename)-5);
printf("%s\n",newName ); // the name shows correctly
return newName; // Segmentation fault (core dumped)
}
}
return point;
}
The function was called char checkExtensions(const char *filename). I added the const due the solutions that I have found online but so far I haven't been able to make it work...
Thank you in advance for the help!
You have many problems with your code. Here are some of them:
Your function returns char which is a single character. You need to return a pointer to an array of characters, a C string.
You don't allocate the right amount of memory. You use sizeof() on a pointer which yields the size of a pointer.
You make it impossible for the caller to know whether or not to deallocate memory. Sometimes you heap allocate, sometimes not. Your approach will leak.
You pass '.palz', which is a character literal, to strrchr which expects a single char. What you mean to pass is '.'.
A better approach is to let the caller allocate the memory. Here is a complete program that shows how:
#include <string.h>
#include <stdio.h>
void GetNewFileName(const char *fileName, char *newFileName)
{
const char *dot = strrchr(fileName, '.');
if (dot)
{
if (strcmp(dot, ".palz") == 0)
{
size_t len = dot - fileName;
memcpy(newFileName, fileName, len);
newFileName[len] = 0;
return;
}
}
size_t len = strlen(fileName);
memcpy(newFileName, fileName, len);
newFileName[len] = 0;
return;
}
int main(void)
{
char fileName[256];
char newFileName[256];
strcpy(fileName, "foo.bar");
GetNewFileName(fileName, newFileName);
printf("%s %s\n", fileName, newFileName);
strcpy(fileName, "foo.bar.palz");
GetNewFileName(fileName, newFileName);
printf("%s %s\n", fileName, newFileName);
strcpy(fileName, "foo.bar.palz.txt");
GetNewFileName(fileName, newFileName);
printf("%s %s\n", fileName, newFileName);
return 0;
}
Output
foo.bar foo.bar
foo.bar.palz foo.bar
foo.bar.palz.txt foo.bar.palz.txt
Note that strcmp compares sensitive to letter case. On Windows file names are insensitive to case. I will leave that issue for you to deal with.
By letting the caller allocate memory you allow them to chose where the memory is allocated. They can use a local stack allocated buffer if they like. And it's easy for the caller to allocate the memory because the new file name is never longer than the original file name.
This is most probably your problem:
const char *newName = malloc(sizeof(filename-5));
First, filename is of type const char *, which means that (filename - 5) is also of this type. Thus, sizeof(filename - 5) will always return the size of the pointer datatype of your architecture (4 for x32, 8 for x64).
So, depending on your architecture, you are calling either malloc(4) or malloc(8).
The rest of the code doesn't even compile and it has serious string manipulation issues, so it's hard to tell what you were aiming at. I suppose the strncpy() was copying too much data into newName buffer, which caused buffer overflow.
If your goal was to extract the filename from a path, then you should probably just use char *basename(char *path) for that.
Several pretty major problems with your code. Making it up as I type, so it may not fix everything first time right away. Bear with me.
You need to return a char *, not a char.
const char checkExtension(const char *filename)
{
const char *point = filename;
You malloc memory but the instruction flow does not guarantee it will be freed or returned.
sizeof(filename) should be strlen(filename), minus 5 (sans extension) but +1 (with terminating 0).
const char *newName = malloc(sizeof(filename-5));
strrchr searches for a single character. Some compilers allow "multibyte character constants", but they expect something like 2 -- not five. Since you know the length and start of the string, use strcmp. (First ensure there are at least 5 characters. If not, no use in testing anyway.)
if((point = strrchr(filename,'.palz')) != NULL ) {
Uh, strstr searches for a string inside a string and returns 0 if not found (actually NULL). This contradicts your earlier test. Remove it.
if(strstr(point,".palz") == 0)
{
strncpy copies n characters, but famously (and documented) does not add the terminating 0 if it did not get copied. You will have to this yourself.
.. This is actually where the malloc line should appear, right before using and returning it.
strncpy(newName, filename, strlen(filename)-5);
printf("%s\n",newName ); // the name shows correctly
return newName; // Segmentation fault (core dumped)
}
}
You return the original string here. How do you know you need to free it, then? If you overwrote a previous char * its memory will be lost. Better to return a duplicate of the original string (so it can always be freed), or, as I'd prefer, return NULL to indicate "no further action needed" to the calling routine.
return point;
}
Hope I did not forget anything.
There are several problems with your code:
Wrong return type:
const char checkExtension(const char *filename){
You need to return a pointer (const char *), not a single character.
Not enough memory:
const char checkExtension(const char *filename){
const char *newName = malloc(sizeof(filename-5));
You are allocating the size of a pointer (char *), which is typically 4 or 8. You need to call strlen() to find out the size of the string:
Multibyte character:
if((point = strrchr(filename,'.palz')) != NULL ) {
'.palz' is a multibyte character literal. While this is allowed in C, its value is implementation-defined and might not do what you expect. String literals use double quotes (".palz").
No terminating zero:
strncpy(newName, filename, strlen(filename)-5);
Note that strncpy() doesn't necessarily null-terminate the target string. It write at most strlen(filename)-5 characters. If the source string contains more characters (as in your case), it will not write a terminating zero.
I'm not sure what exactly you're trying to do. Perhaps something like this:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
const char *checkExtension(const char *filename)
{
int len = strlen (filename)-5;
char *newName = NULL; /* return NULL on allocation failure. */
if (len > 0 && !strcmp (filename+len, ".palz")) {
newName = malloc (len+1);
if (newName) {
memcpy (newName, filename, len);
newName[len] = 0;
}
}
return newName;
}
int main (int ac, char **av)
{
if (ac > 1) {
const char *p = checkExtension (av[1]);
puts (p ? p : "NULL");
} else {
puts ("?");
}
return 0;
}
Multiple errors here. You have not said what you are trying to achieve, that has to be implied from the code. You have declared point and newName as const, yet reassigned with a value. You have tested strstr() == 0 when it should be strstr() == NULL. You have called strrchr(filename,'.palz') but sent a string instead of a char. Then you have returned the local variable point which goes out of scope before you get a chance to use it, because it was not declared as static. So it's irrelevant whether you returned a char or a char pointer.
char *checkExtension(const char *filename) {
// if filename has extension .palz return a pointer to
// the filename stripped of extension or return NULL
char *point;
static char newName[512];
strncpy(newName, filename, 512);
if ((point = strstr(newName, ".palz")) != NULL ) {
if (strlen (point) == 5) {
*point = 0; // string terminator
// printf("%s\n",newName ); // use only for debugging
return newName;
}
}
return NULL;
}
Alternatively provide a string the function can modify -
char *checkExtension(const char *filename, char *newName) { ... }
Alternatively provide a filename the function can modify -
char *checkExtension(char *filename) {
char *point;
if ((point = strstr(filename, ".palz")) != NULL ) {
if (strlen (point) == 5) {
*point = 0; // string terminator
return filename;
}
}
return NULL;
}
Recently I attended an interview where they asked me to write a C program to concatenate two strings without using strcat(), strlen() and strcmp() and that function should not exceed two (2) lines.
I know how to concatenate two strings without using strcat(). But my method has nearly 15 lines. I dont know how to write it in two lines.
I expect they wanted something like this:
void mystrcat(char * dest, const char * src)
{
//advance dest until we find the terminating null
while (*dest) ++dest;
//copy src to dest including terminating null, until we hit the end of src
//Edit: originally this:
//for (; *dest = *src, *src; ++dest, ++src);
//...which is the same as this
for (; *dest = *src; ++dest, ++src);
}
It doesn't return the end of the concatenated string like the real strcat, but that doesn't seem to be required.
I don't necessarily know if this sort of thing is a good interview question - it shows that you can code tersely, and that you know what strcat does, but that's about it.
Edit: as aib writes, the statement
while (*dest++ = *src++);
...is perhaps a more conventional way of writing the second loop (instead of using for).
Given that the task was to concatenate two strings, not to create a duplicate of strcat, I'd go with the simple option of creating a completely new string that is a combination of the two.
char buffer[REASONABLE_MAX] = {0};
snprintf(buffer, REASONABLE_MAX - 1, "%s%s", string1, string2);
The proper answer to that question is that the question would demonstrate a skill that it is bad to have. They are wanting you to demonstrate the ability to write hacker code. They are wanting you to invent your own implementation of things provided already by every C compiler, which is waste of time. They are wanting you to write streamlined code which, by definition, is not readable. The 15 line implementation is probably better if it is more readable. Most projects do not fail because the developers wasted 150 clock cycles. Some do fail because someone wrote unmaintainable code. If you did have to write that, it would need a 15 line comment. So my answer to that would be, show me the performance metrics that defend needing to not use the standard libraries and requiring the most optimal solution. Time is much better spent on design and gathering those performance metrics.
Never forget - you are also interviewing them.
//assuming szA contains "first string" and szB contains "second string"
//and both are null terminated
// iterate over A until you get to null, then iterate over B and add to the end of A
// and then add null termination to A
// WARNING: memory corruption likely if either string is not NULL terminated
// WARNING: memory corruption likely if the storage buffer for A was not allocated large
// enough for A to store all of B's data
// Justification: Performance metric XXX has shown this optimization is needed
for(int i=0; szA[i]!='\0'; i++);
for(int j=0; (j==0)||(szB[j-1]!='\0'); j++) szA[i+j] = szB[j];
*edit, 9/27/2010
After reading some other solutions to this, I think the following is probably the best code answer:
//Posted by Doug in answer below this one
void my_strcat(char * dest, const char * src)
{
while (*dest) ++dest;
while (*dest++ = *src++);
}
But I would follow that up with a safe version of that:
void my_safe_strcat(char * dest, const unsigned int max_size, const char * src)
{
int characters_used=0;
while (*dest) { ++dest; characters_used++; }
while ( (characters_used < (max_size-1) ) && (*dest++ = *src++) ) characters_used++;
*dest = 0; //ensure we end with a null
}
And follow that up with (full answer, which compiler will optimize to be the same as above, along with application which was the real question):
void my_readable_safe_strcat(char * dest, const unsigned int max_size, const char * src)
{
unsigned int characters_used = 0;
while (*dest != '\0')
{
++dest;
characters_used++;
}
while ( (characters_used < (max_size-1) ) && (*dest = *src) )
{
dest++;
src++;
characters_used++;
}
*dest = 0; //ensure we end with a null
}
int _tmain(int argc, _TCHAR* argv[])
{
char szTooShort[15] = "First String";
char szLongEnough[50] = "First String";
char szClean[] = "Second String";
char szDirty[5] = {'f','g','h','i','j'};
my_readable_safe_strcat(szTooShort,15,szClean);
printf("This string should be cut off:\n%s\n\n",szTooShort);
my_readable_safe_strcat(szLongEnough,50,szClean);
printf("This string should be complete:\n%s\n\n",szLongEnough);
my_readable_safe_strcat(szLongEnough,50,szDirty);
printf("This string probably has junk data in it, but shouldn't crash the app:\n%s\n\n",szLongEnough);
}
Two lines? Bwah...
void another_strcat(char* str1, const char* str2)
{
strcpy(strchr(str1, '\0'), str2);
}
EDIT: I'm very upset that people are so against strcpy and strchr. Waah! So, I thought I'd play by the spirit of the rules:
char thing(char* p, const char* s)
{
return *p ? thing(&p[1], s) : *s ? (*p++ = *s++, thing(p, s)) : *p = '\0';
}
I still can't understand how anyone would take 2 whole lines ;-P.
I tested this bit in VS2008, and it worked fine.
void NewStrCat(char* dest, const char* src)
{
while (*dest) ++dest;
while (*dest++ = *src++);
}
Any function can be made to fit in a single line by simply removing all the \n.
However, I think you're looking for this answer:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int main(void)
{
char string1[32] = "Hello";
char string2[] = ", World!";
char *dst = string1 + strlen(string1);
char *src = string2;
while (*dst++ = *src++); //single statement
printf("\"%s\"\n", string1);
return EXIT_SUCCESS;
}
The explanation is rather simple:
src++ returns a pointer to the current character being copied before incrementing to point to the next one. * dereferences this pointer, and a similar expression on the LHS copies it to dst. Result of the whole = expression is the character that was copied, hence a simple while loops it until a \0 is encountered and copied.
However:
strcat() is easier to read and possibly much faster. Any other solution is feasible only when strcat() is not available. (Or when you're in an interview, apparently.)
And replace strcat() above with strncat() unless you're really really sure the destination string is big enough.
Edit: I missed the part about strlen() being disallowed. Here's the two-statement function:
void my_strcat(char * restrict dst, const char * restrict src)
{
while (*dst) ++dst; //move dst to the end of the string
while (*dst++ = *src++); //copy src to dst
}
Note that the standard strcat() function returns the original value of dst.
One line:
sprintf(string1, "%s%s", string1, string2);
(Note that this might possibly invoke undefined behavior.)
Addendum
The ISO C99 standard states that:
If copying takes place between objects that overlap, the behavior is undefined.
That being said, the code above will still probably work correctly. It works with MS VC 2010.
I have a feeling such questions are meant to be elimination questions rather than selection. It is easier to eliminate candidates for them based on such convoluted questions rather than select candidates by asking them more real world questions.
Just a rant from me, since I am also looking for a job and facing such questions and answered quite a few of them thanks to SO!
void StringCatenation(char *str1,char *str2)
{
int len1,i=0;
for(len1=0;*(str1+len1);len1++);
do{
str1[len1+i]=str2[i];
i++;
}
while(*(str2+i);
}
void my_strcat(char* dest, const char* src)
{
while (*dest) ++dest;
while (*dest++ = *src++);
*dest = '\0';
}
Destination string must end with NULL terminated.