Scanf clarification in c language - c

Is it possible to read an entire string including blank spaces like gets() function in scanf()?
I am able to do it using the gets() function.
char s[30];
gets(s);
This will read a line of characters. Can this be done in scanf()?

You can read a line, including blank spaces, with scanf(), but this function is subtle, and using it is very error-prone. Using the %[^\n] conversion specifier, you can tell scanf() to match characters to form a string, excluding '\n' characters. If you do this, you should specify a maximum field width. This width specifies the maximum number of characters to match, so you must leave room for the '\0' terminator.
It is possible that the first character in the input stream is a '\n'. In this case, scanf() would return a value of 0, since there were no matches before encountering the newline. But, nothing would be stored in s, so you may have undefined behavior. To avoid this, you can call scanf() first using the %*[\n] conversion specifier, discarding any leading '\n' characters.
After the string has been read, there will be additional characters in the input stream. At least a '\n' is present, and possibly more characters if the user entered more than the maximum field width specifies. You might then want to discard these extra characters so that they don't interfere with further inputs. The code below includes a loop to do this operation.
The first call to scanf() will consume all newline characters in the input stream until a non-newline character is encountered. While I believe that the second call to scanf() should always be successful, it is good practice to always check the return value of scanf() (which is the number of successful assignments made). I have stored this value in result, and check it before printing the string. If scanf() returns an unexpected result, an error message is printed.
It is better, and easier, to use fgets() to read entire lines. You must remember that fgets() keeps the trailing newline, so you may want to remove it. There is also a possibility that the user will enter more characters than the buffer will store, leaving the remaining characters in the input stream. You may want to remove these extra characters before prompting for more input.
Again, you should check the return value of fgets(); this function returns a pointer to the first element of the storage buffer, or a NULL pointer in the event of an error. The code below replaces any trailing newline character in the string, discards extra characters from the input stream, and prints the string only if the call to fgets() was successful. Otherwise, an error message is printed.
#include <stdio.h>
int main(void)
{
char s[30];
int result;
printf("Please enter a line of input:\n");
scanf("%*[\n]"); // throw away leading '\n' if present
result = scanf("%29[^\n]", s); // match up to 29 characters, excluding '\n'
/* Clear extra characters from input stream */
int c;
while ((c = getchar()) != '\n' && c != EOF)
continue; // discard extra characters
if (result == 1) {
puts(s);
} else {
fprintf(stderr, "EOF reached or error in scanf()\n");
}
printf("Please enter a line of input:\n");
char *ps = fgets(s, 30, stdin); // keeps '\n' character
if (ps) {
while (*ps && *ps != '\n') {
++ps;
}
if (*ps) { // replace '\n' with '\0'
*ps = '\0';
} else {
while ((c = getchar()) != '\n' && c != EOF)
continue; // discard extra characters
}
puts(s);
} else {
fprintf(stderr, "EOF reached or error in fgets()\n");
}
return 0;
}
Note that these two methods of getting a line of input are not exactly equivalent. The scanf() method, as written here, does not accept an empty line (i.e., a line consisting of only the '\n' character), but does accept lines consisting of other whitespace characters. The fscanf() method will accept an empty line as input.
Also, if it is acceptable to ignore leading whitespace characters, it would be simpler to follow the recommendation given by Jonathan Leffler in the comments to use only a single call to scanf():
result = scanf(" %29[^\n]", s);
This will ignore leading whitespace characters, including newlines.

Do not use scanf() or gets() function — use fgets() instead. But for the above question please find the answer.
int main() {
char a[30];
scanf ("%29[^\n]%*c", name);
printf("%s\n", a);
return 0;
}
Its also highly recommended like I told in the beginning to use fgets() instead. We clearly do not understand the weird requirement. I would have used the fgets() to read the character.
fgets(a, size(a), stdin);

Related

C Program won't terminate after compared to empty string

I am attempting to terminate my C program by checking for an empty string ("") but it seems not to work. I have tried to compare to "\0" as well but it was to no avail.
#include <stdio.h>
#include <string.h>
int main(void) {
char nameInput[128];
for(;;) {
printf("Enter nation name: ");
scanf("%s", nameInput);
if(!strcmp(nameInput, "")){
break;
}
printf("Got nation named \"%s\"\n", nameInput);
}
printf("All done getting nations!\n");
return 0;
}
The "%s" specifier in scanf("%s", nameInput); first consumes1 and discards leading white-space including all '\n' from the Enter before scanning and saving to nameInput.
That is why repeated entries of empty lines do not advance the scan. "%s" is waiting for some non-white-space input.
A better alternative to scanf() is to read all user input with fgets() and then parse the string.
fgets() reads a line and saves the result as a string - usually including the line's ending '\n'.
// scanf("%s", nameInput);
if (fgets(nameInput, sizeof nameInput, stdin)) {
// Success at reading input.
nameInput[strcspn(nameInput, "\n")] = '\0'; // lop off the potential trailing \n
if(!strcmp(nameInput, "")){ // or simply `if(nameInput[0] == '\0')
break;
}
...
have tried to compare to "\0" as well but it was to no avail.
if(!strcmp(nameInput, "")) and if(!strcmp(nameInput, "\0")) do the same thing. strcmp() is comparing strings.
"" is a string literal of 1 char: the null character.
"\0" is a string literal of 2 char: two null characters.
The string compare stops at the first null character.
"%s" by itself also lacks a width limit. Code has no safe guard against input like "BlahBlah...(120_some_more)Blah" and can lead to undefined behavior due a buffer overrun of char nameInput[128];. Code could use "%127s" to prevent that, yet that only handles one of the short-comings of scanf().
1
Input white-space characters (as specified by the isspace function) are skipped, unless the specification includes a [, c, or n specifier. C17dr § 7.21.6.2 8
It's not that it won't terminate, it is awaiting the input that wasn't (yet) typed in.
scanf is not using the right pattern string to scan in anything (including nothing) before the carriage return. You'll need to look into scanf patterns, and alter your pattern from "%s" to something that scanf will accept as input.
If you test out your program, you will see that after pressing "enter" you can type in a word and press enter again, and since you now have a word in the input, the scanf picks it up (discarding the whitespace, as it should with "%s").

Search whitespace in string inC

problem is when I try to enter a string with space compiler render that as separate 2 strings. But requirement is whenever there is a space in string don't treat it as 2 strings,but rather a single string. The program should print yes only if my four inputs are MAHIRL,CHITRA,DEVI and C. my code is:
#include<stdio.h>
#include<string.h>
int main()
{
char str1[10],str2[10],str3[10],str4[10];
scanf("%s",str1);
scanf("%s",str2);
scanf("%s",str3);
scanf("%s",str4);
if(strcmp(str1,"MAHIRL")==0 && strcmp(str2,"CHITRA")==0 && strcmp(str3,"DEVI")==0 && strcmp(str4,"C")==0 ){
printf("yes");
}
else{
printf("no");
}
return 0;
}
I tried using strtok() and strpbrk(), but I'm not quite sure how to implement them in my code. Any help or suggestion is appreciated. Thanks.
problem is when I try to enter a string with space compiler render that as separate 2 strings
That's not a problem, that's the feature / behaviour of %s format specifier with scanf(). You cannot read space-delimited input using that.
For conversion specifier s, chapter §7.21.6.2, C11
s Matches a sequence of non-white-space characters. [...]
So, the matching ends as soon as it hits a white-space character, here, the space.
If you have to read a line (i.e., input terminated by newline), use fgets() instead.
The %s directive matches characters up to a whitespace before storing them, so it is not possible to get lines of input this way. There are other ways to use scanf() to read lines of input, but these are error-prone, and this is really not the right tool for the job.
Better to use fgets() to fetch a line of input to a buffer, and sscanf() to parse the buffer. Since the requirement here is that four strings are entered, this is a simple problem using this method:
#include <stdio.h>
#include <string.h>
int main(void)
{
char str1[10],str2[10],str3[10],str4[10];
char buffer[100];
if (fgets(buffer, sizeof buffer, stdin) == NULL) {
fprintf(stderr, "Error in fgets()\n");
return 1;
}
if (sscanf(buffer, "%9s%9s%9s%9s", str1, str2, str3, str4) == 4) {
if (strcmp(str1,"MAHIRL") == 0 &&
strcmp(str2,"CHITRA") == 0 &&
strcmp(str3,"DEVI") == 0 &&
strcmp(str4,"C") == 0 ){
printf("yes\n");
} else {
printf("no\n");
}
} else {
printf("Input requires 4 strings\n");
}
return 0;
}
An additional character array is declared, buffer[], with enough extra space to contain extra input; this way, if the user enters some extra characters, it is less likely to interfere with the subsequent behavior of the program. Note that fgets() returns a null pointer if there is an error, so this is checked for; an error message is printed and the program exits if an error is encountered here.
Then sscanf() is used to parse buffer[]. Note here that maximum widths are specified with the %s directives to avoid buffer overflow. The fgets() function stores the newline in buffer[] (if there is room), but using sscanf() in this way avoids needing to further handle this newline character.
Also note that sscanf() returns the number of successful assignments made; if this return value is not 4, the input was not as expected and the values held by str1,..., str4 should not be used.
Update
Looking at this question again, I am not sure that I have actually answered it. At first I thought that you wanted to use scanf() to read a line of input, and extract the strings from this. But you say: "whenever there is a space in string don't treat it as 2 strings", even though none of the test input in your example code contains such spaces.
One option for reading user input containing spaces into a string would be to use a separate call to fgets() for each string. If you store the results directly in str1,...,str4 you will need to remove the newline character kept by fgets(). What may be a better approach would be to store the results in buffer again, and then to use sscanf() to extract the string, this time including spaces. This can be done using the scanset directive:
fgets(buffer, sizeof buffer, stdin);
sscanf(buffer, " %9[^\n]", str1);
The format string here contains a leading space, telling sscanf() to skip over zero or more leading whitespace characters. The %[^\n] directive tells sscanf() to match characters, including spaces, until a newline is encountered, storing them in str1[]. Note that a maximum width of 9 is specified, leaving room for the \0 terminator.
If you want to be able to enter multiple strings, each containing spaces, on the same line of user input, you will need to choose a delimiter. Choosing a comma, this can be accomplished with:
fgets(buffer, sizeof buffer, stdin);
sscanf(buffer, " %9[^,], %9[^,], %9[^,], %9[^,\n]", str1, str2, str3, str4);
Here, there is a leading space as before, to skip over any stray whitespace characters (such as \n characters) that may be in the input. The %[^,] directives tell sscanf() to match characters until a comma is encountered, storing them in the appropriate array (str1[],..., str3[]). The following , tells sscanf() to match one comma and zero or more whitespace characters before the next scanset directive. The final directive is %[^,\n], telling sscanf() to match characters until either a comma or a newline are encountered.
#include <stdio.h>
#include <string.h>
int main(void)
{
char str1[10],str2[10],str3[10],str4[10];
char buffer[100];
if (fgets(buffer, sizeof buffer, stdin) == NULL) {
fprintf(stderr, "Error in fgets()\n");
return 1;
}
/* Each individual string str1,..., str4 may contain spaces */
if (sscanf(buffer, " %9[^,], %9[^,], %9[^,], %9[^,\n]",
str1, str2, str3, str4) == 4) {
if (strcmp(str1,"test 1") == 0 &&
strcmp(str2,"test 2") == 0 &&
strcmp(str3,"test 3") == 0 &&
strcmp(str4,"test 4") == 0 ){
printf("yes\n");
} else {
printf("no\n");
}
} else {
printf("Input requires 4 comma-separated strings\n");
}
return 0;
}
Here is a sample interaction with this final program:
test 1, test 2, test 3, test 4
yes
While reading strings from user, use __fpurge(stdin) function from stdio_ext.h. This flushes out the stdin. When you are entering a string, you press enter at last, which is also a character. In order to avoid that, we use fpurge function.
scanf("%s",str1);
__fpurge(stdin);
scanf("%s",str2);
__fpurge(stdin);
scanf("%s",str3);
__fpurge(stdin);
scanf("%s",str4);
__fpurge(stdin);
Also if you want to input a string from user containing spaces, use following:
scanf("%[^\n]", str1);
This will not ignore the spaces you enter while inputting string.
EDIT: Instead of using fpurge function, one can use following code:
while( getchar() != '\n' );

What does %[^\n] mean in C?

What does %[^\n] mean in C?
I saw it in a program which uses scanf for taking multiple word input into a string variable. I don't understand though because I learned that scanf can't take multiple words.
Here is the code:
#include <stdio.h>
#include <stdlib.h>
int main() {
char line[100];
scanf("%[^\n]",line);
printf("Hello,World\n");
printf("%s",line);
return 0;
}
[^\n] is a kind of regular expression.
[...]: it matches a nonempty sequence of characters from the scanset (a set of characters given by ...).
^ means that the scanset is "negated": it is given by its complement.
^\n: the scanset is all characters except \n.
Furthermore fscanf (and scanf) will read the longest sequence of input characters matching the format.
So scanf("%[^\n]", s); will read all characters until you reach \n (or EOF) and put them in s. It is a common idiom to read a whole line in C.
See also §7.21.6.2 The fscanf function.
scanf("%[^\n]",line); is a problematic way to read a line. It is worse than gets().
C defines line as:
A text stream is an ordered sequence of characters composed into lines, each line consisting of zero or more characters plus a terminating new-line character. Whether the last line requires a terminating new-line character is implementation-defined.
The scanf("%[^\n]", line) has the specifier "%[^\n]". It scans for unlimited number of characters that match the scan-set ^\n. If none are read, the specifier fails and scanf() returns with line unaltered. If at least one character is read, all matching characters are read and saved and a null character is appended.
The scan-set ^\n implies all character that are not (due to the '^') '\n'.
'\n' is not read
scanf("%[^\n]",.... fails to read a new line character '\n'. It remains in stdin. The entire line is not read.
Buffer overflow
The below leads to undefined behavior (UB) should more than 99 characters get read.
char line[100];
scanf("%[^\n]",line); // buffer overflow possible
Does nothing on empty line
When the line consists of only "\n", scanf("%[^\n]",line); returns a 0 without setting line[] - no null character is appended. This can readily lead to undefined behavior should subsequent code use an uninitialized line[]. The '\n' remains in stdin.
Failure to check the return value
scanf("%[^\n]",line); assumes input succeeded. Better code would check the scanf() return value.
Recommendation
Do not use scanf() and instead use fgets() to read a line of input.
#define EXPECTED_INPUT_LENGTH_MAX 49
char line[EXPECTED_INPUT_LENGTH_MAX + 1 + 1 + 1];
// \n + \0 + extra to detect overly long lines
if (fgets(line, sizeof line, stdin)) {
size_t len = strlen(line);
// Lop off potential trailing \n if desired.
if (len > 0 && line[len-1] == '\n') {
line[--len] = '\0';
}
if (len > EXPECTED_INPUT_LENGTH_MAX) {
// Handle error
// Usually includes reading rest of line if \n not found.
}
The fgets() approach has it limitations too. e.g. (reading embedded null characters).
Handling user input, possible hostile, is challenging.
scanf("%[^\n]",line);
means: scan till \n or an enter key.
scanf("%[^\n]",line);
Will read user input until enter is pressed or a newline character is added (\n) and store it into a variable named line.
Question: what is %[^\n] mean in C?
Basically the \n command prints the output in the next line, but in
case of C gives the Null data followed by the above problem only.
Because of that to remove the unwanted data or null data, need to add
Complement/negotiated symbol[^\n]. It gives all characters until the next line
and keeps the data in the defined expression.
Means it is the Complemented data or rewritten data from the trash
EX:
char number[100]; //defined a character ex: StackOverflow
scanf("%[^\n]",number); //defining the number without this statement, the
character number gives the unwanted stuff `���`
printf("HI\n"); //normaly use of printf statement
printf("%s",number); //printing the output
return 0;

Weird scanf behaviour when reading number and newline

I just realize this 'bug' of scanf now after 8 years with C.
Below scanf code will skip the leading whitespace characters from the second line of input.
int x;
char in[100];
scanf("%d\n",&x);
gets(in);
Input:
1
s
x will contain 1, but in will be just "s" not " s"
Is this standard C or just gcc behaviour?
A whitespace character in your scanf format string will cause scanf to consume any (and all) white space till a non-whitespace char occurs.
This seems to be standard scanf behaviour and is not limited to gcc.
Its not a Bug in scanf, the manual of scanf says,
A sequence of white-space characters (space, tab, newline, etc.; see
isspace(3)). This directive matches any amount of white space,
including none, in the input.
Which means any white space characters with directive as %d\n will read a number followed by consuming a sequence of white space characters in the input and only returns until you type a non white space character. That how you are able to see only "s" without a space before it.
The '\n' (and this is true for any whitespace character in the format string) in
scanf("%d\n", &x);
matches any number of whitespace characters in the input (characters for which isspace function returns 1, i.e, true, such as newline, space, tab etc.) and not just the newline character '\n'. This means that scanf will read all whitespace characters in the input and discard them till it encounters a non-whitespace character. This explains the behaviour you observed.
This is a part of the standard definition of the scanf function and not a gcc feature. Also, gets function is deprecated and unsafe. It does not check for buffer overrun and can lead to bugs and even program crash. In fact, gcc emits a warning against the use of gets on my machine. Use of fgets instead is recommended.
To do what you want, you can do the following:
int x;
char in[100];
scanf("%d", &x);
After scanf returns successfully, the input stream can contain any sequence of characters terminated by a newline depending on the input given by the user. Get rid of those extraneous characters before reading a string from the stdin.
char ch;
while((ch = getchar()) != '\n' || ch != EOF); // null statement
fgets(in, 100, stdin);
The above fgets call means that it will read at most 100-1 = 99 (it saves one character space for the terminating null byte which it adds to the buffer being read into before exiting) characters from the stream pointed to by stdin and store them in the buffer pointed to by in. fgets will exit if it encounters EOF, '\n' or it has already read 100-1 characters - whichever of the three condition occurs first. If it reads a newline, it will store it into the buffer.
Is the user enters 100 characters or more in this case, then the extraneous characters would be lying around in the input buffer which can mess up with the subsequent input operation of characters or strings by scanf, fgets, getchar etc. calls. You can check for this checking the length of the string in.
if(strlen(in) > 99) {
// extraneous chars lying around in the input buffer
// read and discard them
char ch;
while((ch = getchar()) != '\n' || ch != EOF); // null statement
}

What's the better way to read a char?

i write a little code to simply read a char from the keyboard but the program fails, why? How must i read a char?
int main(int argc, char** argv)
{
char op;
do
{
printf("¿Sigues?");
scanf("%c",&op);
}while(op=='s' || op=='S');
return 0;
}
Your problem is that the %c conversion specifier doesn't cause scanf() to skip leading whitespace. You need to handle the newline character that's still in the stream after reading your input.
The input stream is empty when scanf() is called the first time through the loop, so it waits for you to type something. You type s and hit the Enter key, so the input stream contains the characters s and \n (newline). scanf() removes the s from the input stream and assigns it to op. When scanf() is called the second time, the input stream is not empty; it still has the \n character in it, so scanf() reads it and assigns it to op, which causes the loop condition to fail, so your loop exits.
There are several ways to get around this problem. I'm going to recommend reading strings as opposed to individual characters using fgets(), as follows:
char op[3] = {0}; // input character + newline character + 0 terminator
do
{
printf("¿Sigues?");
if (fgets(op, sizeof op, stdin))
{
/**
* Check for a newline character in the input. If it's not there
* then the user typed in too many characters. In order to keep
* the input stream from getting clogged up with bad input, read
* until we find a newline character.
*/
char tmp[3];
char *newline = strchr(op, '\n');
while (!newline && fgets(tmp, sizeof tmp, stdin))
{
newline = strchr(tmp, '\n');
}
}
else
{
printf("Error while reading input\n");
op[0] = 0;
}
} while (tolower(op[0]) == 's');
op = getc(stdin);
scanf flushes only after reading a newline. it cant be done in platform independent way
You're seeing the line "Sigues" twice because there's a \n still in the input stream. If you type in a character and hit enter there are now two characters in your input stream. Your scanf formatter only specifies one char, so scanf reads in one char and then advances. However, the next character in the stream is a \n, hence the exit from the loop on the second go.
NB. #eduffy's technique of getc(stdin) will do the exact same thing, there's still a \n in stdin. You need to advance past that \n somehow.
How about reading in your char, and then chomping the rest of the stream up to the \n char? I tried this and it works for me:
char op;
do
{
printf("¿Sigues?");
scanf("%c",&op);
while(getchar() != '\n') continue;
}while(op=='s'|| op=='S');

Resources