Why does this code actually print out "HI!" ? char *s is an adress to the first character of a string, so in the next line of code when we put variable s into printf it should return an adress to that character to printf which obviously can't be represented as a string with %s. But it does. Why?
#include <stdio.h>
int main(void)
{
char *s = "HI!";
printf("%s\n", s);
}
if you want to print the adress, you have to write printf("%p\n", s); instead of printf("%s\n", s);
7.21.6.1 The fprintf function...
8 The conversion specifiers and their meanings are:
...
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.
...
280) No special provisions are made for multibyte characters.
C 2011 Online Draft
The %s conversion specifier expects a pointer to the first character of a string - it will print that character and all characters following it until it sees the 0 terminator.
When you pass an array expression as an argument:
char s[] = "Hi!";
printf( "%s\n", s );
that array expression "decays" to a pointer to the first element.
Related
I created two arrays 'TEST' and 'arr' below,both contain characters "ABCDE".
#include <stdio.h>
#define TEST "ABCDE"
int main()
{
char arr[5];
int i;
for(i=0;i<5;i++)
{
arr[i] = i + 65;
}
printf("%s\n",arr);
printf("%zd %zd",sizeof arr,sizeof TEST);
return 0;
}
And the output is
ABCDE
5 6
Why are their size different, given that these two arrays both carry 5 characters ?
(I konw there is a null character at the end of each character string.)
After the macro expansion, the line
printf("%zd %zd",sizeof arr,sizeof TEST);
will be:
printf("%zd %zd",sizeof arr,sizeof "ABCDE" );
String literals will always have a terminating null character added to them. Therefore, the type of the string literal is char[6]. The expression sizeof "ABCDE" will therefore evaluate to 6.
However, the type of arr is char[5]. Space for a null-terminating character will not be automatically added. Therefore, the expression sizeof arr will evaluate to 5.
Also, it is worth noting that the following line is causing undefined behavior:
printf("%s\n",arr);
The %s printf format specifier requires a null-terminated string. However, arr is not null-terminated.
If you want to print the array, you must therefore limit the number of characters printed to 5, like this:
printf( "%.5s\n", arr );
Or, if you don't want to hard-code the length into the format string, you can also do this:
printf( "%.*s\n", (int)sizeof arr, arr );
#include <stdio.h>
int main(int argc, const char *argv[]) {
char name1[] = {'f','o','o'};
char name2[] = "foo";
printf("%s\n", name1);
printf("%s\n", name2);
return 0;
}
running the code above results in :
foox\363\277\357\376
foo
Program ended with exit code: 0
So, what's the difference between these 2 initializers?
name1 is an array of three characters {'f', 'o', 'o'}.
name2 is an array of four characters {'f', 'o', 'o', '\0'}.
printf("%s", ...) expects an array terminated with a null character. Because name1 isn't, you start dereferencing characters past the end of the array which can have the traditional undefined behavior.
The first array (i.e., {'f','o','o'}) will not have the null character '\0', wheres the second (i.e., "foo") will.
The printf specification when using the %s says the following:
If no l modifier is present: The const char * argument is expected to
be a pointer to an array of character type (pointer to a string).
Characters from the array are written up to (but not including) a
terminating null byte ('\0'); if a precision is specified, no more
than the number specified are written. If a precision is given, no
null byte need be present; if the precision is not specified, or is
greater than the size of the array, the array must contain a
terminating null byte.
Since, your printf did not include the precision, it will write up characters from the array until reaching the null byte ('\0'). Consequently, in the case of the char name1[] = {'f','o','o'}; resulting in the printf write up characters out of the memory that was allocated for the name1 array. Such behaviour is considered to be undefined.
This is the reason why printf("%s\n", name1); prints foo plus some extra symbols from the next positions in memory that should not have been accessed, whereas with printf("%s\n", name2); it prints exactly the string "foo" as it is.
There are no trailing symbols in the array.
But printf’s %s format expects a string, and the array name1 isn’t a string: by definition, C strings are zero terminated … and your array isn’t. So the behaviour is undefined, and what seems to happen in your particular case is that printf continues printing random values that happen to be in memory just behind the contents of name1.
In C language if you are initializing string with character by character initializer you need to put '\0' which is NULL/terminating character to indicate the end of string.
so name1 should be {'f', 'o', 'o', '\0'}
x\363\277\357\376 that you can see at the end of your output is just garbage value which is printed just because printf could not find '\0' at the end of your string name1.
For name2 you used double quote to initialize the string which automatically puts a '\0' at the end of string.
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);
}
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;
}
I have a string I composed using memcpy() that (when expanded) looks like this:
char* str = "AAAA\x00\x00\x00...\x11\x11\x11\x11\x00\x00...";
I would like to print every character in the string, and if the character is null, print out "(null)" as a substitute for '\0'.
If I use a function like puts() or printf() it will just end at the first null and print out
AAAA
So how can I get it to print out the actual word "(null)" without it interpreting it as the end of the string?
You have to do that mapping yourself. If you want to, that is. In C, strings are null-terminated. So, if you use a formatted output function such as printf or puts and ask it to print a string (via the format specifier %s) it'd stop printing str as soon as it hits the first null. There is no null word in C. If you know exactly how many characters you have in str you might as well loop over them and print the characters out individually, substituting the 0 by your chosen mnemonic.
The draft says 7.21.6.1/8:
p The argument shall be a pointer to void. The value of the pointer is
converted to a sequence of printing characters, in an
implementation-defined manner.
However, the following:
$ cat null.c
#include <stdio.h>
int main() {
printf("%p\n", (void *)0);
}
produces:
00000000
on both gcc 4.6 and clang 3.2.
However, on digging deeper:
$ cat null.c
#include <stdio.h>
int main() {
printf("%s\n", (void *)0);
}
does indeed produce the desired output:
(null)
on both gcc and clang.
Note that the standard does not mandate this:
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.
Relying on this behavior may lead to surprises!
Instead of printing the string with %s , you will have to come up with a for loop that checks a condition whther a given char in your char array is a \0 and then print the NULL
From C++ Reference on puts() (emphasis mine):
Writes the C string pointed by str to stdout and appends a newline
character ('\n'). The function begins copying from the address
specified (str) until it reaches the terminating null character
('\0'). This final null-character is not copied to stdout.
To process data such as you have, you'll need to know the length. From there, you can simply loop across the characters:
/* ugly example */
char* str = "AAAA\x00\x00\x00...\x11\x11\x11\x11\x00\x00...";
int len = ...; /* get the len somehow or know ahead of time */
for(int i = 0; i < len; ++i) {
if('\0' == str[i]) {
printf(" (null) ");
} else {
printf(" %c ", str[i]);
}
}
One of the key cornerstones of C is strings are terminated by '\0'. Everyone lives by that rule. so I suggest you not think of your string as a string but as an array of characters.
If you traverse the array and test for '\0', you can print "(null)" out in place of the character. Here is an example. Please note, your char * str was created either as a char array or on the stack using malloc. This code needs to know the actual buffer size.
char* str = "AAAA\x00\x00\x00...\x11\x11\x11\x11\x00\x00...";
int iStrSz = <str's actual buffer size>
int idx;
for(idx=0; idx<iStrSz; idx++)
{
if('\0' == *(str + idx)
{
sprintf("%s", "(null)");
}
else
{
putchar(*(str + idx));
}
}
printf("%s", "\n");