Difference between strncpy and memcpy? - c

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,

Related

Assignment after initialization to specific index in an array

After assigning 26th element, when printed, still "Computer" is printed out in spite I assigned a character to 26th index. I expect something like this: "Computer K "
What is the reason?
#include <stdio.h>
int main()
{
char m1[40] = "Computer";
printf("%s\n", m1); /*prints out "Computer"*/
m1[26] = 'K';
printf("%s\n", m1); /*prints out "Computer"*/
printf("%c", m1[26]); /*prints "K"*/
}
At 8th index of that string the \0 character is found and %s prints only till it finds a \0 (the end of string, marked by \0) - at 26th the character k is there but it will not be printed as \0 is found before that.
char s[100] = "Computer";
is basically the same as
char s[100] = { 'C', 'o', 'm', 'p', 'u','t','e','r', '\0'};
Since printf stops when the string is 0-terminated it won't print character 26
Whenever you partially initialize an array, the remaining elements are filled with zeroes. (This is a rule in the C standard, C17 6.7.9 §19.)
Therefore char m1[40] = "Computer"; ends up in memory like this:
[0] = 'C'
[1] = 'o'
...
[7] = 'r'
[8] = '\0' // the null terminator you automatically get by using the " " syntax
[9] = 0 // everything to zero from here on
...
[39] = 0
Now of course \0 and 0 mean the same thing, the value 0. Either will be interpreted as a null terminator.
If you go ahead and overwrite index 26 and then print the array as a string, it will still only print until it encounters the first null terminator at index 8.
If you do like this however:
#include <stdio.h>
int main()
{
char m1[40] = "Computer";
printf("%s\n", m1); // prints out "Computer"
m1[8] = 'K';
printf("%s\n", m1); // prints out "ComputerK"
}
You overwrite the null terminator, and the next zero that happened to be in the array is treated as null terminator instead. This code only works because we partially initialized the array, so we know there are more zeroes trailing.
Had you instead written
int main()
{
char m1[40];
strcpy(m1, "Computer");
This is not initialization but run-time assignment. strcpy would only set index 0 to 8 ("Computer" with null term at index 8). Remaining elements would be left uninitialized to garbage values, and writing m1[8] = 'K' would destroy the string, as it would then no longer be reliably null terminated. You would get undefined behavior when trying to print it: something like garbage output or a program crash.
In C strings are 0-terminated.
Your initialization fills all array elements after the 'r' with 0.
If you place a non-0 character in any random field of the array, this does not change anything in the fields before or after that element.
This means your string is still 0-terminated right after the 'r'.
How should any function know that after that string some other string might follow?
That's because after "Computer" there's a null terminator (\0) in your array. If you add a character after this \0, it won't be printed because printf() stops printing when it encounters a null terminator.
Just as an addition to the other users answers - you should try to answer your question by being more proactive in your learning. It is enough to write a simple program to understand what is happening.
int main()
{
char m1[40] = "Computer";
printf("%s\n", m1); /*prints out "Computer"*/
m1[26] = 'K';
for(size_t index = 0; index < 40; index++)
{
printf("m1[%zu] = 0x%hhx ('%c')\n", index, (unsigned char)m1[index], (m1[index] >=32) ? m1[index] : ' ');
}
}

NUL character and static character arrays/string literals in C

I understand that strings are terminated by a NUL '\0' byte in C.
However, what I can't figure out is why a 0 in a string literal acts differently than a 0 in an char array created on the stack. When checking for NUL terminators in a literal, the zeros in the middle of the array are not treated as such.
For example:
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
int main()
{
/* here, one would expect strlen to evaluate to 2 */
char *confusion = "11001";
size_t len = strlen(confusion);
printf("length = %zu\n", len); /* why is this == 5, as opposed to 2? */
/* why is the entire segment printed here, instead of the first two bytes?*/
char *p = confusion;
while (*p != '\0')
putchar(*p++);
putchar('\n');
/* this evaluates to true ... OK */
if ((char)0 == '\0')
printf("is null\n");
/* and if we do this ... */
char s[6];
s[0] = 1;
s[1] = 1;
s[2] = 0;
s[3] = 0;
s[4] = 1;
s[5] = '\0';
len = strlen(s); /* len == 2, as expected. */
printf("length = %zu\n", len);
return 0;
}
output:
length = 5
11001
is null
length = 2
Why does this occur?
The variable 'confusion' is a pointer to char of a literal string.
So the memory looks something like
[11001\0]
So when you print the variable 'confusion', it will print everything until first null character which is represented by \0.
Zeroes in 11001 are not null, they are literal zeroes since it is surrounded with double quotes.
However, in your char array assignment for variable 's', you are assigning a decimal value 0 to
char variable. When you do that, ASCII decimal value of 0 which is ASCII character value of NULL character gets assigned to it. So the the character array looks something like in the memory
[happyface, happyface, NULL]
ASCII character happyface has ASCII decimal value of 1.
So when you print, it will print everything up to first NULL and thus
the strlen is 2.
The trick here is understanding what really gets assigned to a character variable when a decimal value is assigned to it.
Try this code:
#include <stdio.h>
int
main(void)
{
char c = 0;
printf( "%c\n", c ); //Prints the ASCII character which is NULL.
printf( "%d\n", c ); //Prints the decimal value.
return 0;
}
You can view an ASCII Table (e.g. http://www.asciitable.com/) to check the exact value of character '0' and null
'0' and 0 are not the same value. (The first one is 48, usually, although technically the precise value is implementation-defined and it is considered very bad style to write 48 to refer to the character '0'.)
If a '0' terminated a character string, you wouldn't be able to put zeros in strings, which would be a bit... limiting.

Unexpected Case In a Loop

#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");

What is with the null character in reverse string program?

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.

C char array has different length than expected

I have a very simple code:
secret[]="abcdefgh";//this is declared in different function and is random word
int len=strlen(secret);//ofc it is 8 in this case
char word[len];
for(int a=0;a<len;a++){//expecting this will put '_' at positions 0-7
word[a]='_';
}
printf("%d %s",(int)strlen(word),word);
However, strlen(word) returns 11 and word contains "________� #", thus there is some obvious memory leak I can't see. Any idea?
This character array initialized by a string literal
secret[]="abcdefgh";
has 9 elements because it also includes the terminating zero of the string literal. So the definition above is equivalent to
secret[9]="abcdefgh";
Function strlen returns the number of elements of a character array that are before the terminating zero. So in this declaration
int len=strlen(secret);
variable len is initialized by 8
As result declaration
char word[len];
is equivalent to
char word[8];
In this loop
for(int a=0;a<len;a++){//expecting this will put '_' at positions 0-7
word[a]='_';
}
all elements of the aray are set to '_'. The arry does not have the terminating zero. So applaying function strlen to the array has undefined behaviour.
You could change the loop the following way
int a = 0;
for(;a<len - 1;a++){//expecting this will put '_' at positions 0-7
word[a]='_';
}
word[a] = '\0';
In this case function strlen would return number 7 and the program would be well-formed.
You just need to nul terminate the string, increase len by 1 and nul terminate your string.
#include <stdio.h>
#include <string.h>
int main(void)
{
char secret[]="abcdefgh";
int len=strlen(secret);
char word[len+1];
for(int a=0;a<len;a++)
{
word[a]='_';
}
word[a]=0; //or word[a]='\0'
printf("%d %s",(int)strlen(word),word);
return 0;
}
Regarding memory leak yes it can.
At first glance it seems you have forgot to put null at the end of your char array (pointer).
From my experience this leads to buffer overruns or stack corruption .
One addition and one modification
char word[len]; needs to be changed with char word[len+1];
Add a line world[len] = '\0'; before the last printf line.
That will be it
No space for the '\0'.
// "abcdefgh"
// 01234567
You need to define word with space for the NUL terminator.
char word[len + 1];
// "abcdefgh"
// 012345678 -- word[8] gets '\0'

Resources