How does a null character behave in a char array in C? - arrays

I tried to reverse this char array with null characters in the middle and the end, without using string length. (original code)
#include <stdio.h>
#include <stdlib.h>
int main()
{
char string[4] ={'c', '\0', 's', '\0'};
printf("What do we love?\n");
printf("Yes, we love:");
for(int i=3; i>=0; i--){
printf("%d", string[i]);
}
return 0;
}
I expected the output to display nothing. But I got the reverse of the array with whitespaces at the places where I’m guessing are the null characters? (output)
Bcoz I have tried using %d too instead of %c and found that those spaces apparently do have the ascii value of 0. (code with slight change + output + ascii table)
So, does this mean that a loop will not always treat a null character in a char array as an indicator of termination? Does this also mean null characters, which automatically get appended on the empty spaces of a char array actually, get printed as spaces in display, but we just say that it prints nothing in the output after it encounters null character only coz we see 'nothing' on display with most codes?

A null byte is used in a char array to designate the end of a string. Functions that operate on strings such as strcpy, strcmp, and the %s format specifier for printf, will look for a null byte to find the end of a string.
You're not treating string as a string, but as just an array of char. So it doesn't matter whether or not a particular element of the array has the value 0 as you're not treating that value as special in any way. You're just printing the decimal value of each of the elements of the array.

Related

Array showing random characters at the end

I wanted to test things out with arrays on C as I'm just starting to learn the language. Here is my code:
#include <stdio.h>
main(){
int i,t;
char orig[5];
for(i=0;i<=4;i++){
orig[i] = '.';
}
printf("%s\n", orig);
}
Here is my output:
.....�
It is exactly that. What are those mysterious characters? What have i done wrong?
%s with printf() expects a pointer to a string, that is, pointer to the initial element of a null terminated character array. Your array is not null terminated.
Thus, in search of the terminating null character, printf() goes out of bound, and subsequently, invokes undefined behavior.
You have to null-terminate your array, if you want that to be used as a string.
Quote: C11, chapter §7.21.6.1, (emphasis mine)
s
If no l length modifier is present, the argument shall be a pointer to the initial element of an array of character type.280) Characters from the array are
written up to (but not including) the terminating null character. If the
precision is specified, no more than that many bytes are written. If the
precision is not specified or is greater than the size of the array, the array shall
contain a null character.
Quick solution:
Increase the array size by 1, char orig[6];.
Add a null -terminator in the end. After the loop body, add orig[i] = '\0';
And then, print the result.
char orig[5];//creates an array of 5 char. (with indices ranging from 0 to 4)
|?|?|?|0|0|0|0|0|?|?|?|?|
| ^memory you do not own (your mysterious characters)
^start of orig
for(i=0;i<=4;i++){ //attempts to populate array with '.'
orig[i] = '.';
|?|?|?|.|.|.|.|.|?|?|?|?|
| ^memory you do not own (your mysterious characters)
^start of orig
This results in a non null terminated char array, which will invoke undefined behavior if used in a function that expects a C string. C strings must contain enough space to allow for null termination. Change your declaration to the following to accommodate.
char orig[6];
Then add the null termination to the end of your loop:
...
for(i=0;i<=4;i++){
orig[i] = '.';
}
orig[i] = 0;
Resulting in:
|?|?|?|.|.|.|.|.|0|?|?|?|
| ^memory you do not own
^start of orig
Note: Because the null termination results in a C string, the function using it knows how to interpret its contents (i.e. no undefined behavior), and your mysterious characters are held at bay.
There is a difference between an array and a character array. You can consider a character array is an special case of array in which each element is of type char in C and the array should be ended (terminated) by a character null (ASCII value 0).
%s format specifier with printf() expects a pointer to a character array which is terminated by a null character. Your array is not null terminated and hence, printf function goes beyond 5 characters assigned by you and prints garbage values present after your 5th character ('.').
To solve your issues, you need to statically allocate the character array of size one more than the characters you want to store. In your case, a character array of size 6 will work.
#include <stdio.h>
int main(){
int i,t;
char orig[6]; // If you want to store 5 characters, allocate an array of size 6 to store null character at last position.
for (i=0; i<=4; i++) {
orig[i] = '.';
}
orig[5] = '\0';
printf("%s\n", orig);
}
There is a reason to waste one extra character space for the null character. The reason being whenever you pass any array to a function, then only pointer to first element is passed to the function (pushed in function's stack). This makes for a function impossible to determine the end of the array (means operators like sizeof won't work inside the function and sizeof will return the size of the pointer in your machine). That is the reason, functions like memcpy, memset takes an additional function arguments which mentions the array sizes (or the length upto which you want to operate).
However, using character array, function can determine the size of the array by looking for a special character (null character).
You need to add a NUL character (\0) at the end of your string.
#include <stdio.h>
main()
{
int i,t;
char orig[6];
for(i=0;i<=4;i++){
orig[i] = '.';
}
orig[i] = '\0';
printf("%s\n", orig);
}
If you do not know what \0 is, I strongly recommand you to check the ascii table (https://www.asciitable.com/).
Good luck
prinftf takes starting pointer of any memory location, array in this case and print till it encounter a \0 character. These type of strings are called as null terminated strings.
So please add a \0 at the end and put in characters till (size of array - 2) like this :
main(){
int i,t;
char orig[5];
for(i=0;i<4;i++){ //less then size of array -1
orig[i] = '.';
}
orig[i] = '\0'
printf("%s\n", orig);
}

While entering a string in an single element of array in c why does the following code gives the shown output?

#include <stdio.h>
int main(int argc, char *argv[])
{
int i, n, m;
scanf("%d %d", &n, &m);
char s[m][n];
for (i = 0; i < m; i++) {
printf("the string --\n");
scanf("%s", s[i]);
}
for (i = 0; i < m; i++) {
printf("the strings are %s \n",s[i]);
printf("\n");
}
return 0;
}
The output is:
2 2
the string --
10
the string --
11
the strings are 1011
the strings are 11
Why is the first string 1011 instead of 10?
In C, strings are represented as a sequence of char values, terminated by a null character (0 or '\0'). This means that to store a two-character string, you need space for three characters: the two characters of string content, plus the null terminator character.
Here, you've only allocated enough space for two characters in each string, but you need space for three.
So, it reads the first string into the array s[0], but the null terminator doesn't fit, and so it overflows into the second array s[1]. Now your array of arrays s looks like this: {{'1', '0'}, {'\0', ... }}.
Then, when it reads the second string into the array s[1], it overwrites the overflowed null terminator from before. And the null terminator for the second string doesn't fit into its own array, so it overflows again into the rest of the stack. The program might crash here, or corrupt other data, because you're overflowing past the end of the array.
So now your array of arrays s ends up looking like this: {{'1', '0'}, {'1', '1'}}, followed by a '\0' somewhere after the end of the array.
When printf goes to read your first string, it prints characters until it finds a null terminator. But it doesn't find one in the first string, so it keeps going, and hits the second string. It doesn't find one there either, and continues past the end of the array. In your case, luckily a null terminator was right there, but for all we know there could be something else.
To fix this, you need to allocate an extra character per string on line 9, for the null terminator:
char s[m][n+1];
There's another problem here, however. What if your input gives you the wrong length? For example, what if your input says 2 3, i.e. that the following strings will have a length of 3, but gives you the string foobar, which is 6 characters? Your code right now would overflow the buffer when it read that string, because it doesn't ensure it's the right length.
One way to avoid this would be to use gets_s instead of sscanf() for reading the strings on line 13:
gets_s(s[i], n+1);
This will read at most n characters, so avoid crashing your program or creating a security issue. However, gets_s is a C11 function, so you may not be able to use it.
You must set column size to 3 if you insert 2 characters per string, 4 for 3 characters per string and so on.
This because string in C have a termination character ('\0') in the last position.
#include <stdio.h>
int main(int argc, char *argv[])
{
int i, n, m;
scanf("%d %d", &n, &m);
char s[m][n+1];
for (i = 0; i < m; i++) {
printf("the string --\n");
scanf("%s", s[i]);
}
for (i = 0; i < m; i++) {
printf("the strings are %s \n",s[i]);
printf("\n");
}
return 0;
}
%s expects null terminated strings as an argument. When first string is read by scanf, there is not enough space for the null terminator within the allocated memory of first string. It will goes to the space next to the allocated space. Writing to unallocated space invokes undefined behavior.
While printing the strings with %s specifier, printf write the string character by character till it finds a null terminator '\0'. Here it may be the case that both the strings 10 and 11 are stored one after another in memory, so printf writes the first string till it read the null character of second string.
Input n as 3 and you will get the desire results.
In my opninion using scanf to read strings is just pure evil.
That said the array s[m][n] is just s[m*n] of course.
That said that evil thing scanf is going to load on *s[0] 10\n\0 and on *s[1*n] or *s[2] 11 and *s will be 1011\n\0
And this is a monument to bad C coding. I guess it's just an example but if I was asked this question i would say: "Come on, get me real things"

Trouble getting nth character of a string

In my program, I am making a char line[MAXLINE] and then using it in:
fgets(line, sizeof line, f);
I can then print this line with
printf("%s\n",line);
However, trying something like
printf("%s\n",line[10]);
warns me that line[10] is of type int, and something like
printf("%s\n",line + 10);
prints from character 10 onwards.
how can I just get the nth character of this string?
You can get the nth character like so:
char ch = line[10];
But you can't print it as a string, because it's not a string. Print it as a character:
printf("%c\n", line[10]);
What you are doing when you use %s in the format string in printf is printing the null-terminated string starting from the the provided pointer.
line+10 is the pointer to the 11th character in the string so it prints everything it finds in memory until it encounters /0 (null) character.
To print a single character you have to use %c in the format string.
printf("%c",line+10);
printf("%s\n",line + 10); // %s expects a char *
Instead print like this -
printf("%c\n",line + 10);
how can I just get the nth character of this string?
With strlen() function from <string.h> you can get length of string. Thus easily you can get the nth character. of the string.
The below will also work as a string in C is a char pointer to the first character. (Strings are terminated in memory with the character \0, that's how programs know where they end.)
line is a pointer to the first character and it can be advanced to the 10th character, as below (we have to advance it by 9, as no advance points to the first character).
* dereferences the pointer to get the actual value.
#include <stdio.h>
int main()
{
char line[] = "abcdefghijkl";
printf("%c\n", *(line+9));
return 0;
}

printing int array as string

I am trying to print int array with %s. But it is not working. Any ideas why?
#include<stdio.h>
main() {
int a[8];
a[0]='a';
a[1]='r';
a[2]='i';
a[3]='g';
a[4]='a';
a[5]='t';
a[6]='o';
a[7] = '\0';
printf("%s", a);
}
It prints just a.
I tried with short as well, but it also does not work.
This is because you are trying to print a int array, where each element has a size of 4 byte (4 chars, on 32bit machines at least). printf() interprets it as char array so the first element looks like:
'a' \0 \0 \0
to printf(). As printf() stops at the first \0 it finds, it only prints the 'a'.
Use a char array instead.
Think about the way integers are represented - use a debugger if you must. Looking at the memory you will see plenty of 0 bytes, and %s stops when it reaches a 0 byte.
It prints just a.
That's why it prints just a. Afterwards it encounters a 0 byte and it stops.
Because you declared a as an integer, so those signle characters you initialized would result in an error. You must change it to a char variable. However to save time, just make the variable a pointer using the asterisk character, which then allows you to make a single string using double quotes.
int a[8] means array of 8 ints or 8*(4 bytes) - Say 32 bit architecture
a[0] = 'a' stores in the first int index as 'a''\0''\0''\0'
a[1] = 'r' as 'r''\0''\0''\0' and so on . . .
%s represents any C-style string ie. any string followed by a '\0' character
So
printf("%s", a);
searches for trailing '\0' character and just prints "a" assuming it is the entire string

Undefined behavior of a program

While writing a program i am filling the entries of a char array with digits. After doing so the length calculated for an array having no zero is correct but for an array starting with zero is zero!
Why is this result coming so!I am not able to interpret my mistake!?
int main()
{
int number_of_terms,no,j,i;
char arr[100];
char c;
scanf("%d",&number_of_terms);
for(i=0;i<number_of_terms;i++)
{
j=0;
while(c!='\n')
{
scanf("%d",&arr[j]);
if(c=getchar()=='\n')
break;
j++;
}
printf("Length is:%d\n",strlen(arr));
}
return 0;
}
for eg if i input my array elements as 4 5
lenght is 2
and if my array elements as 0 5
length is 0..
You are using "%d" in your format specifier, which produces an integer, and you are passing in the address of a character array. This is, exactly like your title says, undefined behaviour. In particular, the value zero will take up 4 of the cells in your string, and will write zero to all of those. Since the character with value zero is the end marker, you get zero length string. However, on another architecture, the second character would probably cause a crash...
If you want to store integers in an array, you should use int arr[...];. If you want to store characters, use "%c".
You are copying the value 0 into the array. This eqals the character '\0' which is used to terminate strings. What you want is to copy the character '0' (has the value 48, see an ascii table).
Change %d to %c to interpret the input has character instead of decimal.
scanf("%c",&arr[j]);
Also your "string" in arr is not zero terminated. After all the characters of your string, you have to end the string with the value 0 (here a decimal is correct). strlen needs it, because it determines the length of the string by traversing the array and counting up until it finds a 0.

Resources