#include <stdio.h>
void copy1(char *s1, const char *s2) {
int i;
for (i = 0; (s1[i] = s2[i]) != '\0'; i++)
;
}
void copy2(char *s1, const char *s2) {
for ( ; (*s1 = *s2) != '\0'; s1++, s2++)
;
}
int main() {
char string1[10];
char *string2 = "Hello";
char string3[10];
char string4[] = "Good Bye";
copy1(string1, string2);
printf("string1 = %s\n", string1);
copy2(string3, string4);
printf("string3 = %s\n", string3);
return 0;
}
I have a code like this but I expected that it should print :
Hello56789
Good Bye89
But it produced just:
Hello Good Bye
I couldn't understand why this occurs.I thought like that the loop will stop when string2 and string4 reaches the '\0'. If this happens why can't I see the remaining numbers which is in the array (56789..) ?
I mean that Hello's length is 5.When this happens : for ( i = 0; ( s1[ i ] = s2[ i ] ) != '\0'; i++ )Just after 5th element of Hello , \0 comes and loop is over.So,the elements of array which are 0,1,2,3,4 replaced by Hello's letters.Yet,there are still 5,6,7,8,9 in string1 which are not replaced.We print the string1 with %s can it be the reason why I couldn't see the numbers ?
The actual output I would expect is this:
string1 = Hello
string3 = Good Bye
Both functions implement the copy part of strcpy(), using index notation and pointer pushing respectively. They both copy characters from the source (second argument) into the destination (first argument) upto and including the null terminator. Evaluating the test actually copies the character: the null terminator is copied and the loop stops.
The rest of the destination arrays string1 and string3 remains uninitialized. They do not contain anything precise: these arrays are allocated on automatic storage (aka on the stack) and are not initialized. I don't know where you derive this notion of initial contents for arrays, maybe from some sample program that did initialize arrays with this contents, but no such thing happens by default.
printf() outputs the contents of the array string1 as an argument for the %s format, deemed to be a C string, and stops when it reaches the null terminator.
The loop exit condition is a null character (\0). This character is seen at the end of the string.
There is no source for the number characters to appear from, therefore they don't
You have to init string1 and string3 with 0..9 before you use your copy functions, but before init you have to extend the field length of string1 and string3 from 10 to 11 (the \0 char is added):
strcpy(string1,"0123456789");
strcpy(string3,"0123456789");
Related
I am trying to reverse a string in C with pointers but the output is really weird. The logic seems good but I am not sure why it gets outputted like this. Here is the code:
#include <stdio.h>
#include <string.h>
int main()
{
char str[20], reverse_str[20], *pointer;
int i = 0;
printf("%s", "Enter any string: ");
scanf("%s", str);
pointer = str;
int string_length = strlen(pointer);
//int count = 0;
for (int i = string_length; i > 0; i--){
reverse_str[i -1] = *pointer;
pointer++;
}
printf("%d\n", string_length);
printf("Original string = %s\n", str);
printf("Reversed string = %s\n", reverse_str);
}
The output looks like this:
Enter any string: Hello
Original string = Hello
Reversed string = olleH╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠Hello
This is when the role of null terminator comes in which is often ignored as a silly bit of information by beginners.
In C, every string is terminated by a null character because there needs to be some way to know when a particular string ends starting from its initial location in memory. If you properly initialize the string or put in \0 appropriately then the string can be displayed as is. Otherwise every character in memory starting from the zeroth index of the string will be displayed until it encounters a null character. This is how a printf("%s", str) works, in simple words.
You get that weird output because of this reason. This explains it much better.
Solution:
Add reverse_str[string_length] = '\0'; after you reverse your string using that for loop, so that your resultant string is properly null terminated.
Bonus:
And the reason why you got a considerably sane output is that you were lucky since the compiler allocated str and reverse_str close to each other in a direction such that even if you miss the null terminator on reverse_str you hit the null terminator of str.
To print a string, the string needs a NUL-terminator \0 but reverse_str doesn´t have one.
You need to set a \0 at the end of revers_str, like:
reverse_str[string_length] = '\0';
to make it print the right output.
I had to make a simple program to reverse a string. I eventually got this code from my own understanding but also help from google since I couldn't originally get it to work. It runs fine and outputs as it should and I understand all of it except for the reverse[j] = '\0' statement.
I kept getting symbols in my output when I didn't state it but I want to know how this works. Can anyone explain please?
#include<stdio.h>
int main(void)
{
char original[20], reverse[20];
int length, i, j;
printf("Enter a string:\n");
gets(original);
length = strlen(original);
for (i = length - 1, j= 0; i >= 0; i--, j++)
reverse[j] = original[i];
reverse[j] = '\0'; //I don't know what this statement does exactly
printf("The string reversed is:\n %s\n", reverse);
return 0;
}
If you want that a character array would contain a string then it has to have the terminating zero.
For example function strlen that is used in your program counts characters in a character array before the terminating zero.
Also function printf used with the format specifier %s outputs characters from a character array until the terminating zero will be encountered.
For example if you have an array like this
char s[10] = "Hello";
then the call strlen( s ) returns 5 instead of 10. And call printf( "%s\n", s ); outputs 6 characters (including the new line character).
Consider this demonstrative program
#include <stdio.h>
int main(void)
{
char s[10] = "Hello";
printf( "%d\n", printf( "%s\n", s ) );
return 0;
}
Its output is
Hello
6
This initialization
char s[10] = "Hello";
is fully equivalent to
char s[10] = { 'H', 'e', 'l', 'l', 'o', '\0', '\0', '\0', '\0', '\0'};
If you need to reverse the string stored in the array it is obvious that you need to reverse characters before the first terminating zero. And if you want to copy the string in the reversed order to another character array you need to append the destination array with the terminating zero.
This loop
for (i = length - 1, j= 0; i >= 0; i--, j++)
reverse[j] = original[i];
copies in the reversed order all characters except the terminating zero from the original character array starting with the last character before the terminating zero to the destination character array. You need to append the destination character array with the terminating zero
reverse[j] = '\0';
The \0 is not really a character. It's the way a c program mark the end of a string. So if you only want to reverse a string you don't have to move this character at the begining of the reversed string.
original string: hello\0
reverse string : olleh\0
In C, a string always has a \0 at the end. Read why and how.
\0 is for null terminating the string. This will mark the end of the string. If it is not null terminated, the data in the succeeding locations will also wrongly treat as part of string.
char str[50];
char strToCopy[16];
int numberOfBytesToFill = 7; // fills 1st n bytes of the memory area pointed to
char charToFillInAs = '*'; //48: ascii for '0' // '$';
void* targetStartAddress = str;
strncpy(strToCopy, "tO sEe The wOrLd", strlen("tO sEe The wOrLd")+1);
puts(strToCopy); // print
strcpy(str, "Test statement !##$%^&*()=+_~```::||{}[]");
puts(str); // print
memset(targetStartAddress, charToFillInAs, numberOfBytesToFill); // fill memory with a constant byte (ie. charToFillInAs)
puts(str); // print
memcpy(targetStartAddress, strToCopy, strlen(strToCopy)+1); // +1 for null char
puts(str); // print
The output is:
tO sEe The wOrLd
Test statement !##$%^&*()=+_~```::||{}[]
*******atement !##$%^&*()=+_~```::||{}[]
tO sEe The wOrLd*******atement !##$%^&*()=+_~```::||{}[]
Hence, my question is why
tO sEe The wOrLd*******atement !##$%^&*()=+_~```::||{}[]
instead of
tO sEe The wOrLd\0#$%^&*()=+_~```::||{}[]
with '\0' as the null char?
strncpy(strToCopy, "tO sEe The wOrLd", strlen("tO sEe The wOrLd")+1);
This is the wrong way to use strncpy. You should specify the size of the output buffer, not the size of the input. In this case the output buffer is 16 bytes, but you are copying 17 bytes into it, which results in undefined behavior.
Note that even if you do specify the output buffer size, strncpy won't write the null terminator if the string is truncated so you'd need to add it yourself:
strncpy(strToCopy, "tO sEe The wOrLd", sizeof(strToCopy));
strToCopy[sizeof(strToCopy)-1] = '\0'; //null terminate in case of truncation.
For this reason, some people prefer to use another function. For example, you can implement a safe copy function by using strncat:
void safeCopy(char *dest, const char *src, size_t destSize) {
if (destSize > 0) {
dest[0] = '\0';
strncat(dest, src, destSize-1);
}
}
To be used like:
safeCopy(strToCopy, "tO sEe The wOrLd", sizeof(strToCopy));
Note also that you won't actually see the null character and what comes after it as in your expected output. The output will simply stop at the null terminator because it indicates the end of the string.
reverser() reverses a cstring (not in place). 99% of the time it works but some input corrupts it for example it appears if aStr2[] is assigned a string made up of the same character it will have an error.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char* reverser(const char *str);
int main()
{
char aStr[] = "aaa";
char aStr2[] = "cccccc";
printf("%s %s", aStr, aStr2);
char* tmp = reverser(aStr2);//tmp now has garbage
printf("\n%s", tmp);
printf(" %s", aStr2);
return 0;
}
char* reverser(const char *str)
{
char* revStr = (char*)malloc(strlen(str));
int i;
for(i = strlen(str)-1; i >= 0; i--)
{
revStr[strlen(str)-1-i] = str[i];
}
return revStr;
}
Gives
aaa cccccc
cccccc9 cccccc
Process returned 0 (0x0) execution time : 0.068 s
Press any key to continue
Notice the 9 that shouldn't be there.
Change this malloc to strlen(str) + 1 , plus 1 for '\0'
char* revStr = (char*)malloc(strlen(str) + 1);
and after the for loop
revStr[strlen(str)+1] = '\0';
Your problem is that you don't put the string terminator in your reversed string. All strings in C are actually one extra character that isn't reported by strlen, and that is the character '\0' (or plain and simple, a zero). This tells all C functions when the string ends.
Therefore you need to allocate space for this extra terminator character in your malloc call, and add it after the last character in the string.
There are also a couple of other problems with your code, the first is that you should not cast the return of malloc (or any other function returning void *). Another that you have a memory leak in that you do not free the memory you allocate. This last point doesn't matter in a small program like the one you have here, but will be an issue in larger and longer running programs.
You haven't null-terminated your reversed string. You need to set the final index of revStr[] to 0.
How can I access s[7] in s?
I didn't observe any difference between strncpy and memcpy. If I want to print the output s, along with s[7] (like qwertyA), what are the changes I have to made in the following code:
#include <stdio.h>
#include <stdlib.h>
int main() {
char s[10] = "qwerty", str[10], str1[10];
s[7] = 'A';
printf("%s\n", s);
strncpy(str, s, 8);
printf("%s\n", str);
memcpy(str1, s, 8);
printf("%s\n", str1);
return 0;
}
Output:
qwerty
qwerty
qwerty
Others have pointed out your null-termination problems. You need to understand null-termination before you understand the difference between memcpy and strncpy.
The main difference is that memcpy will copy all N characters you ask for, while strncpy will copy up to the first null terminator inclusive, or N characters, whichever is fewer.
In the event that it copies less than N characters, it will pad the rest out with null characters.
You are getting the output querty because the index 7 is incorrect (arrays are indexed from 0, not 1). There is a null-terminator at index 6 to signal the end of the string, and whatever comes after it will have no effect.
Two things you need to fix:
Change the 7 in s[7] to 6
Add a null-terminator at s[7]
The result will be:
char s[10] = "qwerty";
s[6] = 'A';
s[7] = 0;
Original not working and fixed working.
As for the question of strncpy versus memcpy, the difference is that strncpy adds a null-terminator for you. BUT, only if the source string has one before n. So strncpy is what you want to use here, but be very careful of the big BUT.
Strncpy will copy up to NULL even you specified the number of bytes to copy , but memcpy will copy up to specified number of bytes .
printf statement will print up to NULL , so you will try to print a single charater , it will show ,
printf("\t%c %c %c\t",s[7],str[7],str1[7]);
OUTPUT
7 7
To make "qwertyA" you need to set s[6] = 'A' and s[7]='\0'
Strings are indexed from 0, so s[0] == 'q', and they need to be null terminated.
When you have:
char s[10] = "qwerty";
this is what that array contains:
s[0] 'q'
s[1] 'w'
s[2] 'e'
s[3] 'r'
s[4] 't'
s[5] 'y'
s[6] 0
s[7] 0
s[8] 0
s[9] 0
If you want to add an 'A' to the end of your string, that's at index 6, since array indexes start at 0
s[6] = 'A';
Note that when you initialize an array this way, the remaining space is set to 0 (a nul terminator), While not needed in this case, generally be aware that you need to make your strings nul terminated.
e.g.
char s[10];
strcpy(s,"qwerty");
s[6] = 'A';
s[7] = 0;
In the above example "qwerty" , including its nul terminator is copied to s. s[6] overwrites that nul terminator. Since the rest of s is not initialized we need to add a nul terminator ourselves with s[7] = 0;
As explained by Philip Potter, the main difference is that memcpy will copy all N characters you ask for, while strncpy will copy up to the first null terminator inclusive, or N characters, whichever is fewer. In the event that it copies less than N characters, it will pad the rest out with null characters.
Execute the below code and check the difference, you might find it useful.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char s[10] = "qwer\0ty", str[10], str1[10];
s[7] = 'A';
printf("%s\n",s);
strncpy(str,s,8);
printf("%s\n",str);
memcpy(str1,s,8);
printf("%s\n",str1);
for(int i = 0; i<8; i++)
{
printf("%d=%c,",i,str[i]);
}
printf("\n");
for(int i = 0; i<8; i++)
{
printf("%d=%c,",i,str1[i]);
}
return 0;
}
Output:
qwer
qwer
qwer
0=q,1=w,2=e,3=r,4=,5=,6=,7=,
0=q,1=w,2=e,3=r,4=,5=t,6=y,7=A,