I was writing a simple program to read a string and then print it.
#include<stdio.h>
// void printString(char *str){
// while(*str!='\0'){
// printf("%c",*str);
// str++;
// }
// printf("\n");
// }
int main(){
char str[50];
printf("Enter Your Name:-");
scanf("%s",&str); // scanf adds '\0' automatically at the end.
char *ptr = str;
// printString(ptr);
printf("Your Name is %s%s",ptr);
return 0;
}
I wrote the above code. At first I didn't know that scanf stops when encounters a space. So I thought that I need to have two %s for printing two words but when I got to know the former part about scanf. I understood the problem but in the process, I encountered another problem which I think is unexpected behavior.
OUTPUT:-
Enter Your Name:-Rachit Mittal
Your Name is Rachit Mittal
This Output, from my understanding is unexpected.
If scanf only reads till it encounter space or new line then string contains only "RACHIT" So in the output screen even after using double %s, It should only print "Rachit" instead of "Rachit Mittal"
I wanna ask why is this so? Is this unexpected behavior because of double %s or something else?
You are invoking undefined behavior by not passing enough arguments to printf. %s%s contains two format specifiers, so printf expects two string arguments to be passed, but you only gave one. In this case, the result could be anything.
Consider enabling warnings to help diagnose these errors (e.g. compiling with -Wall).
You have two %s in the format string, but only one additional argument. So there's no argument corresponding to the second %s. This causes undefined behavior. This means that anything can happen, so nothing should be "unexpected".
It's a bit surprising that this causes it to print the second name from the input. The register or memory location that would have contained an additional argument just happened to point to the remainder of the input buffer used by stdio. This is purely coincidence.
For starters the second argument expression in this call of scanf
scanf("%s",&str);
is incorrect. The type of the expression &str is char ( * )[50] while the conversion specifier %s expects an argument of the type char *. You have to write
scanf( "%s", str );
As for your problem then according to the C Standard (7.21.6.1 The fprintf function)
2 The fprintf function writes output to the stream pointed to by
stream, under control of the string pointed to by format that
specifies how subsequent arguments are converted for output. If
there are insufficient arguments for the format, the behavior is
undefined. If the format is exhausted while arguments remain, the
excess arguments are evaluated (as always) but are otherwise ignored.
The fprintf function returns when the end of the format string is
encountered.
You could write to read several words
scanf( "%49[^\n]", str );
Related
So I have this function that goes as follows f(char * str). The string argument is a file name that is accessed using another function. So if I do f("grille1.txt") the program works as expected. However, if I do
char * filename;
scanf("%s", filename);
f(filename);
the program doesn't work as expected. So I concluded that the issue is with the scanf. However I tried doing
printf("%d Are they equal?", !strcmp(filename, "grille1.txt"));
and I get a 1 as a result which means that they are indeed equal so what could the issue be that results in using the variable filename not giving the same results as manually using "grille1.txt"?
The function scanf requires the address of a sufficiently large memory location where it should write the string, and you are supposed to pass the address of that memory location as a parameter to scanf. However, you are instead passing an uninitialized (garbage) value. This causes undefined behavior.
Therefore, I suggest that you change the lines
char * filename;
scanf("%s",filename);
f(filename);
to:
char filename[100];
if ( scanf( "%99s", filename ) == 1 )
f( filename );
In the code above, the declaration
char filename[100];
will allocate an array of 100 characters, which is sufficient to store 99 characters and the terminating null character. When passing filename to scanf, the array will decay to a pointer to the address of the first character of the array.
I enclosed the scanf function call inside an if statement, because it is generally a good idea to check the return value of scanf, to make sure that the function was successful.
Also, I am using the %99s format specifier instead of %s to limit the input to 99 characters, otherwise a buffer overflow would occur if the user enters more than 99 characters.
I'm going through an exercise book on C and came across the statement
printf("%c", "\n");
Which when run in a console still works but displays the "$" symbol.
Why did this statement not crash the console like
printf("%s", '\n');
does?
a double quoted string like that produces a value of a pointer to char (aka char*), while the single quote produce a value that's a character (using the ASCII value of whats in the quotes. On some compilers you can stack multiple characters into the single quotes.
printf("%c", *("\n") );
would print your linefeed, as the * operator would dereference the pointer
( You could probably do *"\n" , I just tend to be conservative in writing expressions)
printf("%s", '\n');
crashes because %s expects a pointer, and a linefeed cast into a pointer is pointing off in the weeds and most likely causes an invalid memory access
It will invoke undefined behavior by passing data having wrong type. It just happened not to crash.
In some implementation, the pointer converted from the string literal is passed as an argument. Unlike %s, which will interpret the argument as pointer and go to read thete, %c will just take the argument as a number and print it, so it has less chance to crash.
Because %s expects a NUL terminated string where %c only wants a char. The string will read past the end of your buffer (the single char) looking for that NUL and quite likely cause a memory exception. Or not - hence undefined behavior.
Only the latter statement asked the implementation to dereference an invalid pointer. An invalid value will typically show as garbage. But most possible memory location values are inaccessible and attempting to access them will cause a crash on modern operating systems.
%s prints until it reaches a '\0' because \n has no escape it will read into memory. "%c" only needs a char
Can anyone please explain what will be the output and how? I am unable to understand the printf() function arguments. I want to know the difference between
1 and 2, and 3 and 4 printf() statements. Normally in printf(), we should give control string as first argument. But even though interchanging arguments, will I get the same output?
#include <stdio.h>
int main()
{
char *str;
str = "%s";
printf("%s\n", str); //.....1
printf(str, "%s\n"); //.......2
printf(str, "K\n"); //.......3
printf("K\n", str); //........4
return 0;
}
It is better to put the code into a compiler and look at the output. It will probably give better insight of things than asking in Stack Overflow.
The expected output is:
[%s\n] because str contains %s and it will be printed as is.
[%s\n] because str contains the format and the second argument will be printed. This form is very dangerous if str comes from the user.
[K\n] same as 2.
[K\n] str is ignored. gcc will warn you if configured correctly through command-line arguments.
Conclusion — always use #1.
The printf function arguments are comprised of
(1) an initial shift state
(2) format string
(3) list of arguments
In your case you have:
printf("%s\n",str); //.....1
No shift, a format string that takes the sting str = %s and prints it literally.
printf(str, "%s\n");//.......2
The values of str has no numeric shift (again 0) and a literal %s which is printed.
printf(str, "K\n"); //.......3
Here again you have a value of str and initial shift 0, but include a literal format string K which is printed.
printf("K\n",str); //........4
Finally, you have a format string with an insufficient number of conversion specifiers which generates the warning:
foo.c:11:1: warning: too many arguments for format [-Wformat-extra-args]
printf("K\n",str); //........4
but which contains the literal format string K which again is printed. In sum the output of the code being:
%s
%s
K
K
How can I make this print properly without using two printf calls?
char* second = "Second%d";
printf("First%d"second,1,2);
The code you showed us is syntactically invalid, but I presume you want to do something that has the same effect as:
printf("First%dSecond%d", 1, 2);
As you know, the first argument to printf is the format string. It doesn't have to be a literal; you can build it any way you like.
Here's an example:
#include <stdio.h>
#include <string.h>
int main(void)
{
char *second = "Second%d";
char format[100];
strcpy(format, "First%d");
strcat(format, second);
printf(format, 1, 2);
putchar('\n');
return 0;
}
Some notes:
I've added a newline after the output. Output text should (almost) always be terminated by a newline.
I've set an arbitrary size of 100 bytes for the format string. More generally, you could declare
char *format;
and initialize it with a call to malloc(), allocating the size you actually need (and checking that malloc() didn't signal failure by returning a null pointer); you'd then want to call free(format); after you're done with it.
As templatetypedef says in a comment, this kind of thing can be potentially dangerous if the format string comes from an uncontrolled source.
(Or you could just call printf twice; it's not that much more expensive than calling it once.)
Use the preprocessor to concatenate the two strings.
#define second "Second%d"
printf("First%d"second,1,2);
Do not do this in a real program.
char *second = "Second %d";
char *first = "First %d";
char largebuffer[256];
strcpy (largebuffer, first);
strcat (largebuffer, second);
printf (largebuffer, 1, 2);
The problem with using generated formats such as the method above is that the printf() function, since it is a variable length argument list, has no way of knowing the number of arguments provided. What it does is to use the format string provided and using the types as described in the format string it will then pick that number and types of arguments from the argument list.
If you provide the correct number of arguments like in the example above in which there are two %d formats and there are two integers provided to be printed in those places, everything is fine. However what if you do something like the following:
char *second = "Second %s";
char *first = "First %d";
char largebuffer[256];
strcpy (largebuffer, first);
strcat (largebuffer, second);
printf (largebuffer, 1);
In this example the printf() function is expecting the format string as well as a variable number of arguments. The format string says that there will be two additional arguments, an integer and a zero terminated character string. However only one additional argument is provided so the printf() function will just use what ever is next on the stack as being a pointer to a zero terminated character string.
If you are lucky, the data that the printf() function interprets as a pointer will a valid memory address for your application and the memory area pointed to will be a couple of characters terminated by a zero. If you are less lucky the pointer will be zero or garbage and you will get an access violation right then and it will be easy to find the cause of the application crash. If you have no luck at all, the pointer will be good enough that it will point to a valid address that is about 2K of characters and the result is that printf() will totally mess up your stack and go into the weeds and the resulting crash data will be pretty useless.
char *second = "Second%d";
char tmp[256];
memset(tmp, 0, 256);
sprintf(tmp, second, 2);
printf("First%d%s", 1,tmp);
Or something like that
I'm assuming you want the output:
First 1 Second 2
To do this we need to understand printf's functionality a little better. The real reason that printf is so useful is that it not only prints strings, but also formats variables for you. Depending on how you want your variable formatted you need to use different formatting characters. %d tells printf to format the variable as a signed integer, which you already know. However, there are other formats, such as %f for floats and doubles, %l% for long integers, and %s for strings, or char*.
Using the %s formatting character to print your char* variable, second, our code looks like this:
char* second = "Second";
printf ( " First %d %s %d ", 1, second, 2 );
This tells printf that you want the first variable formatted as an integer, the second as a string, and the third as another integer.
Is a NULL pointer allowed as the string to store result in in a call to sscanf?
I don't find anything about it in any documentation but it seems to be working fine. Same thing with scanf.
Example:
int main(int arc, char* argv[])
{
char* s = NULL;
sscanf("Privjet mir!", "%s", s);
printf("s: %s\n", s);
return 0;
}
Output: s: (null)
No:
Matches a sequence of non-white-space
characters; the next pointer must be a
pointer to character array that is
long enough to hold the input sequence
and the terminating null character
('\0'), which is added automatically.
The input string stops at white space
or at the maximum field width,
whichever occurs first.
(http://linux.die.net/man/3/sscanf)
As is mentioned by the other answers NULL is not valid to pass to sscanf as an additional argument.
http://www.cplusplus.com/reference/cstdio/sscanf says of additional arguments:
Depending on the format string, the function may expect a sequence of additional arguments, each containing a pointer to allocated storage where the interpretation of the extracted characters is stored with the appropriate type.
For the %s specifier these extracted characters are:
Any number of non-whitespace characters, stopping at the first whitespace character found. A terminating null character is automatically added at the end of the stored sequence.
So when the "non-whitespace characters" and "terminating null character" is stored, there will be a segfault. Which is exactly what Visual Studio will yield (you can test that this fails at http://webcompiler.cloudapp.net/):
Now as far as non-Visual Studio compilers, libc's extraction code for the %s specifier: https://github.com/ffainelli/uClibc/blob/master/libc/stdio/_scanf.c#L1376 has the leading comment: /* We might have to handle the allocation ourselves */ this is because:
The GNU C library supported the dynamic allocation conversion specifier (as a nonstandard extension) via the a character. This feature seems to be present at least as far back as glibc 2.0.
Since version 2.7, glibc also provides the m modifier for the same purpose as the a modifier.
[Source]
So because libc extracts to a buffer constructed internally to sscanf and subsequently checks that the buffer parameter has no flags set before assigning it, it will never write characters to a NULL buffer parameter.
I can't stress enough that this is non-standard, and is not guaranteed to be preserved even between minor library updates. A far better way to do this is to use the * sub-specifier which:
Indicates that the data is to be read from the stream but ignored (i.e. it is not stored in the location pointed by an argument).
[Source]
This could be accomplished like this for example:
s == NULL ? sscanf("Privjet mir!", "%*s") : sscanf("Privjet mir!", "%s", s);
Obviously the true-branch of the ternary is a no-op, but I've included it with the expectation that other data was expected to be read from the string.
The manpage says that, when using %s, the argument must be a pointer with enough space for the string and \0. So my guess would be that the behaviour in your case is undefined. It may work, it may also crash or corrupt memory and cause issues later.
No, this is not allowed.
sscanf %s expects a char* pointing to a sufficient large buffer, printf %s wants a nul char* buffer. Anything else results in undefined behavior. (And that means some implementations might detect and handle a null pointer in a certain way, other implementations might not)
I didn't find anything in the standard explicitly concerning NULL and *printf/*scanf.
I suppose that this is undefined behavior1, since it counts as passing an argument that is not coherent with the format specifier (§7.19.6.1 ¶13, §7.19.6.2 ¶13): %s means that a you're going to pass a pointer to the first element of a character array (large enough for the acquired string for *scanf, containing a NUL-terminated string for *printf) - and passing NULL doesn't satisfy this requirement.
1. In this case UB shows as "just ignoring the acquisition" and "printing (null)", on other platforms it may result in planes falling down the sky or the usual nasal demons.
Allocate the memory to s . Assign s to character array. Then run the program.
Following will work.
int main(int arc, char* argv[])
{
char s[100];
sscanf("Privjet mir!", "%[^\t]s", s);
printf("s: %s\n", s);
return 0;
}