C strings need to be null terminated. Ie they need a '\0' character at the end, so common string expressions can tell where the string ends. String functions like strcpy and printf("%s... look for this null termination in their operation. When you do this:
for(i=0; s1[i] != '\0'; i++)
s2[i] = s1[i];
You fail to copy the null terminator. This means when you print the string, printf will go through the string until it finds the first '\0' character somewhere after the end of your string. This is why you see the extra characters, and in the case where the NULL is outside your strings allotted memory you will actually cause undefined behaviour by accessing unallocated space, which is very very bad.
You either need to null terminate your string by adding:
s2[i] = '\0'
After your for loop. Or even better, use a standard c function strcpy.
C strings need to be null terminated. Ie they need a '\0' character at the end, so common string expressions can tell where the string ends. String functions like strcpy and printf("%s... look for this null termination in their operation. When you do this:
for(i=0; s1[i] != '\0'; i++)
s2[i] = s1[i];
You fail to copy the null terminator. This means when you print the string, printf will go through the string until it finds the first '\0' character somewhere after the end of your string. This is why you see the extra characters, and in the case where the NULL is outside your strings allotted memory you will actually cause undefined behaviour by accessing unallocated space, which is very very bad.
You either need to null terminate your string by adding:
s2[i] = '\0'
After your for loop. Or even better, use a standard c function strcpy.
int main()
{
int i, j;
char s1[100], s2[100];
printf("Enter a string : \n");
scanf("%[^\n]%*c", s1);
for(i=0; s1[i] != '\0'; i++)
s2[i] = s1[i];
s2[i] = 0; // null terminate the string
printf("\n the original string is %s\n", s1);
printf("\n the string after copying is %s\n", s2);
return 0;
}
Or simply use strcpy.
arrays - C - Copy a String without a library function - Stack Overflow
Implementing a string copy function in C - Stack Overflow
C program copy string without using strcpy() with enough memory - Stack Overflow
Safest way to copy a string?
Videos
I just fell foul of the fact that strncpy does not add an old terminator if the destination buffer is shorter than the source string. Is there a single function standard library replacement that I could drop in to the various places strncpy is used that would copy a null terminated string up to the length of the destination buffer, guaranteeing early (but correct) termination of the destination string, if the destination buffer is too short?
Edit:
-
Yes, I do need C-null terminated strings. This C API is called by something else that provides a buffer for me to copy into, with the expectation that itโs null terminated
Edit 2:
-
I know I can write a helper function thatโs shared across relevant parts of the code, but I donโt want to do that because then each of those modules that need the function becomes coupled to a shared helper header file, which is fine in isolation but โoh I want to use this code in another project, better make sure I take all the misc dependenciesโ is best avoided. Necessary if necessary, but if possible using a standard function, even better.
Your program has two bugs:
First
Your function CopyAString does not write a '\0' character to the end of the string. This means that the string s2[] does not have a '\0' character and you would not be able to pass s2[] to functions like printf() or other functions that expect an "input" string to end with '\0'.
However, in your program, this is not a problem because the for loop expects a fixed-length string.
Second
In your program, the following problem is more important:
You pass &str as first argument to CopyAString instead of str.
This means that s1 (the first argument of CopyAString) does not point to the character 'H' of "Hello world" but it points to the first byte of the value stored in the variable str...
Note that the variable str is a pointer: It does not store a "value" (here: the string "Hello world") but it stores an address of a value!
If the string "Hello world" is stored in the RAM at address 0x20 44 00 40 (this means: 0x40004420 on an x86 or ARM computer or 0x20440040 on a PowerPC), the variable str will contain the value 0x20 44 00 40.
s1[0] will be 0x20 (which is the space character). s1[1] will be 0x44 (which is 'D')...
For starters you should declare the function like
char * CopyAString( char *s1, const char *s2 );
similarly to the standard string function strcpy.
In this function call
CopyAString( &str1, s2 );
the expression &str1 has the type const char ** and yields the address of the pointer str1 but the function expects an argument expression of the type const char * that points to the first element of a string (the string literal).
Within the function you are not copying the terminating zero character
while (*p1 != '\0') {
s2[index] = *p1;
index++;
p1++;
}
So the destination character array in general will not contain a string.
The function can be defined the following way
char * CopyAString( char *s1, const char *s2 )
{
for ( char *p = s1; ( *p++ = *s2++ ); );
return s1;
}
Within main instead of this for loop with the magic number 12 in the condition that invokes undefined behavior
for (int i = 0; i <= 12; i++){
printf("%c", s2[i]);
}
it is better to write
for ( char *p = s2; *p != '\0'; ++p ){
printf("%c", *p );
}
putchar( '\n' );
Good interview question has several layers, to which to candidate can demonstrate different levels of understanding.
On the syntactic 'C language' layer, the following code is from the classic Kernighan and Ritchie book ('The C programming language'):
while( *dest++ = *src++ )
;
In an interview, you could indeed point out the function isn't safe, most notably the buffer on *dest isn't large enough. Also, there may be overlap, i.e. if dest points to the middle of the src buffer, you'll have endless loop (which will eventually creates memory access fault).
As the other answers have said, you're overwriting the buffer, so for the sake of your test change it to:
char buffer[ 12 ];
For the job interview they were perhaps hoping for:
char *mycpy( char *s, char *t )
{
while ( *s++ = *t++ )
{
;
}
return s;
}
There are multiple problems in your code:
The loop test in the
lengthfunction is incorrect: instead ofi < str[i], it should be:for (i = 0; str[i] != '\0'; i++)the same problem in the
concatfunction. Change the loop to:for (j = 0; src[j] != '\0'; j++) {also in the
concatfunction,ishould be the length ofdst, not that ofsrc. You might useleninstead ofifor this variable.The array
str4in functionmaindoes not have any space available at the end forconcatto append anything. Define it with a larger size this way:char str4[MAXSIZE] = "Plain old string";
Here is the corrected version:
#include <stdio.h>
#include <string.h>
#define MAXSIZE 32
void concat(char dest[], char src[]) {
int len = length(dest);
int j;
for (j = 0; src[j] != '\0'; j++) {
dest[len + j] = src[j];
}
dest[len + j] = '\0';
}
int length(char str[]) {
int len = 0;
int i;
for (i = 0; i < str[i]; i++) {
len++;
}
return len;
}
int main(void) {
// Variable declarations for all parts
char str2[MAXSIZE] = "Troy";
char str4[MAXSIZE] = "Plain old string";
char str6[MAXSIZE];
// Part 6
printf("\n----- Part 6 -----\n");
// Make a copy of the destination string first, to be reused later
strcpy(str6, str4);
concat(str4, str2);
strcat(str6, str2);
printf("Comparing results of concat and strcat ...\n");
printf("strcmp(\"%s\", \"%s\") says: %d\n",
str4, str6, strcmp(str4, str6));
return 0;
}
You have several problems in both functions:
concat
for(j; j<src[j] !='\0'; j++) {
What is the for exit condition here?, src[j] != '\0' is enough.
dest[i+j] = src[j];
Here you add data with an offset of i, but I is the length of src, not dst.
So the corrected function could be:
void concat(char dest[], char src[])
{
/* descriptive variable name */
int len_dst = length(dst);
int j=0;
/* clear exit condition */
for(; src[j] != '\0'; j++) {
dest[len_dst+j] = src[j];
}
dest[len_dst+j] = '\0';
}
length
for(i=0;i<str[i];i++) {
Same remark, what is this exit condition? src[i] != '\0' is enough
So the corrected function could be:
int length(char str[])
{
int len=0;
int i;
/* clear exit condition */
for ( i=0; str[i] != '\0'; i++) {
len++;
}
return len;
}
main
And warning in main function:
char str4[] = "Plain old string";
concat(str4, str2); /* <- erases what is after str4 */
You do not have enough space to store result. Write something like:
char str2[] = "Troy";
char str4[MAXSIZE] = "Plain old string"; /* <-- reserve spaces after str4*/
/* ... */
concat(str4, str2);