#include "stdio.h"
void main()
{
char firstName[1] = "1";
char middleName[1] = "1";
char lastName[1] = "1";
printf("%p\t%s\n",firstName,firstName);
printf("%p\t%s\n",middleName,middleName);
printf("%p\t%s\n",lastName,lastName);
}
I compile this code use the gcc 4.8.2, what is confusing me is why it print:
>
root#ubuntu:~# ./main
0x7fff7124273d 111
0x7fff7124273e 11
0x7fff7124273f 1
I think it should print:
0x7fff7124273d 1
0x7fff7124273e 1
0x7fff7124273f 1
Can you help me?
char firstName[1] = "1";
It's legal to initialize a char array like this, but it's not a string, because it's not null-terminated.
"%s" in printf expects a string, so what you are doing is undefined behavior.
My guess is, the compiler puts the variables together, and what byte after them happens to be 0, that can explain what happened. But again, it's undefined behavior, anything could happen.
'1' '1' '1' 0
^ ^ ^
firstName | |
middleName |
lastName
Because size of array is 1 and you are assigning the array of length 2 (string literal also have null character \0 at the end). Hence, string pointed by the pointer may not be NULL terminated string. You need array of size 2.
char firstName[2] = "1";
char middleName[2] = "1";
char lastName[2] = "1";
or
char firstName[] = "1";
char middleName[] = "1";
char lastName[] = "1";
Also, do not use void main in C. Use int main.
"1" is actually two bytes in size - '1', '\0' - you're forgetting that C strings are null-terminated. The null bytes are getting trashed by the initialization. Your arrays need to be big enough to contain all the data in the initializer to avoid this.
Remember, C-style strings are null-terminated arrays, meaning that there should be '\0' after the string. Notes that might help you:
char firstName[2] = "1"; - Adds '\0' by itself, note the 2 instead of 1.
char firstName[] = {'1'} - Does not add '\0'.
char firstName[2] = {'1'} - adds '\0'.
You're getting this output because probably the chars are put together, this is undefined behavior.
in your code
printf("%p\t%s\n",firstName,firstName);
the first thing getting printed is the base address of the array firstName,
the second thing is actually undefined behaviour. for any character array to be a string it must have null character \0 at the end. your array is only 1 character long., and containing '1'. so you acnnot use %s to print that.
instead of %s use %c to print the character, like \
printf("%p\t%c\n",firstName,firstName);
In C, strings are NUL-terminated, i.e. the string "1" is the characters {'1', 0}. You have not allowed enough room for the terminator, so your strings are truncated and printf doesn't know where they end.
It would be better to define them as
char firstName[2] = "1";
and best to do
char firstName[] = "1";
so the compiler calculates the right amount of memory for you if you should ever deal with some with a first name which is longer than 1 character.
Related
I am quite new to C programming so feel free to correct me, I insist. My basic understanding of strings in C is when we initialize a string a null character is automatically assigned at the end of the string and the null character cannot be read read or written, but is used internally only.
So when I create a string of size 4 as char str[3] and assign a word to it say "RED" and print it using puts function or printf("%s",str), I get an unusual output printed as RED(SMIILEY FACE)
I then again reduce the size of string to char str[2] and assign RED to it and then compile it and the again receive a output stating RE(Smiley face)
If someone can explain it to me I will be thankful . Posting the C code below
int main()
{
char s1[3]="RED";
char s2[]="RED";
puts(s1);
puts(s2);
printf("%s",s1);
return 0;
}
char s1[3] = "RED";
Is a valid statement. It copies 3 characters from the constant string literal "RED" (which is 4 characters long) into the character array s1. There is no terminating '\0' in s1, because there is no room for it.
Note the copy, because s1 is mutable, while "RED" is not. This makes the statement different from e.g. const char *s1 = "RED";, where the string is not copied.
The result of both puts(s1) and printf("%s", s1) are undefined. There is no terminating '\0' in s1. Treating it as a string with one can lead to arbitrary behavior.
char s2[] = "RED";
Here, sizeof(s2) == 4, because "RED" has four characters, you need to count the trailing '\0' when calculating space.
The null character takes one exra character(byte). So you need to use an extra space in addition to the number of characters in the word you are initializing.
char s1[4]="RED"; //3 for RED and 1 for the null character
On the other hand
char s2[3]="RED";
there is no space for null character. "RED" is in there but you would encounter I/O problems when printing it as there is no null character stored at the end. Your data is stored fine but it can't be recognized properly by the printf as there is no null character.
char s2[]="RED";
This would work as memory of 4 (bytes) is automatically assigned which includes space for the terminating null character.
When I run the program, the second printf() prints string2 with whatever was scanned into string1 attached to the end.
e.g. 123 was scanned into string1 then it prints: Is before "12ab123".
as opposed to 12ab.
Why not just "12ab"?
char string1[MAX_STR_LEN];
char string2[4]={'1','2','a','b'};
char five='5';
char abc[3]={'a','b','c'};
printf("Enter a string:");
scanf("%s", string1);
printf("Is before \"%s\":",string2);
A string is a null terminated char array in C.
Change
char string2[4]={'1','2','a','b'};
to
char string2[5]={'1','2','a','b', '\0'};
(which is the same as char string2[] = "12ab";)
You need to terminate your array with NULL character as
char string2[5]={'1','2','a','b','\0'};
When you are doing the scanf(), string1 is stored in next memory so it is printing string2 with string1. It will print upto it gets \0 so its Undefined Behavior
In your code
char string2[4]={'1','2','a','b'};
string2 is not null-terminated. Using that array as an argument to %s format specifier invokes undefined behavior, as it runs past the allocated memory in search of the null-terminator.
You need to add the null-terminator yourself like
char string2[5]={'1','2','a','b','\0'};
to use string2 as a string.
Also, alternatively, you can write
char string2[ ]= "12ab";
to allow the compiler to decide the size, which considers the space for (and adds) the null-terminator.
Same goes for abc also.
That said, you're scanning into string1 and printing string2, which is certainly not wrong, but does not make much sense, either.
Expanding on the previous answers, the strings appear to be joined due to the order the variables are stored in the stack memory. This won't always work the same on every processor architecture or compiler (optimiser settings can change this behaviour too).
If the format specifier %s does not have the precision flag then the function outputs characters until it encounteres zero character '\0'
Character array string2 is defined such a way that it does not have the terminating zero
char string2[4]={'1','2','a','b'};
So the function outputs characters beyond the array until it meets zero character.
You could use the precision flag that to specify explicitly how many characters you are going to output. For example
printf("Is before \"%4.4s\":",string2);
Or you could define the array that includes the terminating zero. For example
char string2[5] = { '1', '2', 'a', 'b', '\0' };
Take into account that in this case the size of the array if it is specified shall be equal at least to 5 ( though the size can be greater than 5; in this case other characters that do not have initializers will be zero-initialized)
or simply
char string2[] = { "12ab" };
or without braces
char string2[] = "12ab";
I want to assign the first two values from the hash array to the salt array.
char hash[] = {"HAodcdZseTJTc"};
char salt[] = {hash[0], hash[1]};
printf("%s", salt);
However, when I attempt this, the first two values are assigned and then all thirteen values are also assigned to the salt array. So my output here is not:
HA
but instead:
HAHAodcdZseTJTC
salt is not null-terminated. Try:
char salt[] = {hash[0], hash[1], '\0'};
Since you are adding just two characters to the salt array and you are not adding the '\0' terminator.
Passing a non nul terminated array as a parameter to printf() with a "%s" specifier, causes undefined behavior, in your case it prints hash in my case
HA#
was printed.
Strings in c use a special convetion to know where they end, a non printable special character '\0' is appended at the end of a sequence of non-'\0' bytes, and that's how a c string is built.
For example, if you were to compute the length of a string you would do something like
size_t stringlength(const char *string)
{
size_t length;
for (length = 0 ; string[length] != '\0' ; ++length);
return length;
}
there are of course better ways of doing it, but I just want to illustrate what the significance of the terminating '\0' is.
Now that you know this, you should notice that
char string[] = {'A', 'B', 'C'};
is an array of char but it's not a string, for it to be a string, it needs a terminating '\0', so
char string[] = {'A', 'B', 'C', '\0'};
would actually be a string.
Notice that then, when you allocate space to store n characters, you need to allocate n + 1 bytes, to make room for the '\0'.
In the case of printf() it will try to consume all the bytes that the passed pointer points at, until one of them is '\0', there it would stop iterating through the bytes.
That also explains the Undefined Behavior thing, because clearly printf() would be reading out of bounds, and anything could happen, it depends on what is actually there at the memory address that does not belong the the passed data but is off bounds.
There are many functions in the standard library that expect strings, i.e. _sequences of non nul bytes, followed by a nul byte.
Consider this code:
char name[]="123";
char name1[]="1234";
And this result
The size of name (char[]):4
The size of name1 (char[]):5
Why the size of char[] is always plus one?
Note the difference between sizeof and strlen. The first is an operator that gives the size of the whole data item. The second is a function that returns the length of the string, which will be less than its sizeof (unless you've managed to get string overflow), depending how much of its allocated space is actually used.
In your example
char name[]="123";
sizeof(name) is 4, because of the terminating '\0', and strlen(name) is 3.
But in this example:
char str[20] = "abc";
sizeof(str) is 20, and strlen(str) is 3.
As Michael pointed out in the comments the strings are terminated by a zero. So in memory the first string will look like this
"123\0"
where \0 is a single char and has the ASCII value 0. Then the above string has size 4.
If you had not this terminating character, how would one know, where the string (or char[] for that matter) ends? Well, indeed one other way is to store the length somewhere. Some languages do that. C doesn't.
In C, strings are stored as arrays of chars. With a recognised terminating character ('\0' or just 0) you can pass a pointer to the string, with no need for any further meta-data. When processing a string, you read chars from the memory pointed at by the pointer until you hit the terminating value.
As your array initialisation is using a string literal:
char name[]="123";
is equivalent to:
char name[]={'1','2','3',0};
If you want your array to be of size 3 (without the terminating character as you are not storing a string, you will want to use:
char name[]={'1','2','3'};
or
char name[3]="123";
(thanks alk)
which will do as you were expecting.
Because there is a null character that is attached to the end of string in C.
Like here in your case
name[0] = '1'
name[1] = '2'
name[2] = '3'
name[3] = '\0'
name1[0] = '1'
name1[1] = '2'
name1[2] = '3'
name1[3] = '4'
name1[4] = '\0'
A String in C (and in, probably, every programming language - behind the scenes) is an array of characters which is terminated by \0 with the ASCII value of 0.
When assigning: char arr[] = "1234";, you assign a string literal, which is, by default, null-terminated (\0 is also called null) as you can see here.
To avoid a null (assuming you want just an array of chars and not a string), you can declare it the following way char arr[] = {'1', '2', '3', '4'}; and the program will behave as you wish (sizeof(arr) would be 4).
name = {'1','2','3','\0'};
name1 = {'1','2','3','4','\0'};
So
sizeof(name) = 4;
sizeof(name1) = 5;
sizeof returns the size of the object and in this case the object is an array and it is defined that your array is 4 bytes long in first case and 5 bytes in second case.
In C, string literals have a null terminating character added to them.
Your strings,
char name[]="123";
char name1[]="1234";
look more like:
char name[]="123\0";
char name1[]="1234\0";
Hence, the size is always plus one. Keep in mind when reading strings from files or from whatever source, the variable where you store your string, should always have extra space for the null terminating character.
For example if you are expected to read string, whose maximum size is 100, your buffer variable, should have size of 101.
Every string is terminated with the char nullbyte '\0' which add 1 to your length.
If I have an array declared as
char arr[1] = "";
What is actually stored in memory? What will a[0] be?
Strings are null-terminated. An empty string contains one element, the null-terminator itself, i.e, '\0'.
char arr[1] = "";
is equivalent to:
char arr[1] = {'\0'};
You can imagine how it's stored in the memory from this.
C-strings are zero-terminated. Thus, "abc" is represented as { 'a', 'b', 'c', 0 }.
Empty strings thus just have the zero.
This is also the reason why a string must always be allocated to be one char larger than the maximum possible length.
arr[0] = 0x00;
however, if you did not assign any value like
char arr[1];
then arr[0] = garbage value
a[0] is the null character, which can be referred to as '\0' or 0.
A string is, by definition, "a contiguous sequence of characters terminated by and including the first null character". For an empty string, the terminating null character is the first one (at index 0).
It will pique more if the array is declared as char arr[] = "";
In this case the sizeof(arr) is 1 and strlen(arr) is 0 .
But still self analysis can be done by adding print like this printf("%d", arr[0]); So that you can understand by yourself.
string is a sequence of characters, in your case there is no character is present inside "". So it stores only '\0' character in arr[0].
C string is end with NULL, so the empty string "" actually is "\0", Compiler help do this,
so strlen("") equal 0 but sizeof("") equal to 1.