I was reading about sscanf and i came across this:
Return Value
Each of these functions [including s_sscanf()] returns the number of fields that are successfully converted and assigned; the return value does not include fields that were read but not assigned. A return value of 0 indicates that no fields were assigned. The return value is EOF for an error or if the end of the string is reached before the first conversion.
I am doing error checking for my input file and i wanna make sure i get a valid line so i tried using sscanf but how do i make sure there are no more fields in the line than i expect. So if i have 3 values in a line but i only need two then that is an invalid line for me but when i use sscanf i only read in 2 variables and the rest are ignored. How do i check the entire line making sure there is no garbage in the line but im not sure what to expect so its not like i can add another variable cause the user can input anything. Someone mentioned to me that you can use * in your sscanf function but im not really sure how i haven't been able to find it anywhere where it is being implemented in code.
The scanf() family of functions returns the number of successful assignments made. If code is expecting three input items there is no way to tell from the value returned by sscanf() alone whether three or more input items were provided.
The scanf() functions operate by reading a character, attempting to match that character, making an assignment if applicable, then moving to the next character or returning from the function call. There is a conversion specifier, %n, that stores the number of characters read in this process so far (without incrementing the number of characters read). This conversion specifier can be used to determine if the input has been exhausted by the call to sscanf().
The code below provides a demonstration. Lines of input gathered by fgets() contain a newline, unless the input is too large to fit in the buffer array. Here buffer[] is large enough to store reasonably-sized inputs, but more robust code would handle oversized inputs more carefully. When sscanf() scans the input string, each character is read in turn until a failing match occurs or the end of the string is reached, so the number of read characters expected after matching "%d %d %d %n" is the same as the length of the input string, including any trailing whitespace characters.
#include <stdio.h>
#include <string.h>
#define BUF_SZ 1024
int main(void)
{
char buffer[BUF_SZ];
int x, y, z;
int pos;
printf("Enter three integers: ");
fflush(stdout);
// get user input
if (fgets(buffer, sizeof buffer, stdin) != NULL) {
// first check: does input match 3 integers?
if (sscanf(buffer, "%d %d %d %n", &x, &y, &z, &pos) != 3) {
puts("Incorrectly formatted input");
} else {
// second check: did sscanf() finish at the end of the buffer?
int expected = strlen(buffer);
if (pos != expected) {
puts("Extra input in buffer");
printf("expected = %d, pos = %d\n", expected, pos);
} else {
// everything OK
printf("You entered: %d, %d, %d\n", x, y, z);
}
}
}
return 0;
}
Sample interactions:
>$ ./a.out
Enter three integers: 1 2 3
You entered: 1, 2, 3
>$ ./a.out
Enter three integers: 1 2
Incorrectly formatted input
>$ ./a.out
Enter three integers: 1 2 3 4
Extra input in buffer
expected = 8, pos = 6
If it is desired to disallow even trailing whitespace characters, "%d %d %d%n" can be used instead. Note that in order for this to work, the newline character must be removed from buffer[] so that it is not counted as extra input. One typical way to do this is by using buffer[strcspn(buffer, "\r\n")] = '\0':
int main(void)
{
char buffer[BUF_SZ];
int x, y, z;
int pos;
printf("Enter three integers: ");
fflush(stdout);
// get user input
if (fgets(buffer, sizeof buffer, stdin) != NULL) {
// first check: does input match 3 integers?
if (sscanf(buffer, "%d %d %d%n", &x, &y, &z, &pos) != 3) {
puts("Incorrectly formatted input");
} else {
// remove trailing newline character
buffer[strcspn(buffer, "\r\n")] = '\0';
// second check: did sscanf() finish at the end of the buffer?
int expected = strlen(buffer);
if (pos != expected) {
puts("Extra input in buffer");
printf("expected = %d, pos = %d\n", expected, pos);
} else {
// everything OK
printf("You entered: %d, %d, %d\n", x, y, z);
}
}
}
return 0;
}
You may, first of all, give the conversion specifiers for the values that you are sure must be present, and then add an "assignment-allocation modifier" to capture any remaining input. I am not sure whether you are talking about sscanf, fscanf or scanf; I will just use scanf to illustrate.
The following program reads 2 integers, and places any remaining input in a string variable, the size of which is dynamically allocated:
Update: Using sscanf instead of scanf.
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
int main() {
int a,b;
char *s;
int n;
char src[]="1 2 This is the remainder";
n=sscanf(src,"%d %d %m[^\n]",&a,&b,&s);
if(n>2)
printf("s=%s\n", s), free(s);
return 0;
}
$ ./a.out
s=This is the remainder
Related
I am trying to take in user input with spaces and store it in an array of characters.
After, I want to take in a single character value and store it as a char.
However, when I run my code, the prompt for the character gets ignored and a space is populated instead. How can I take in an array of chars and still be allowed to prompt for a single character after?
void main()
{
char userIn[30];
char findChar;
printf("Please enter a string: ");
scanf("%[^\n]s", userIn);
printf("Please enter a character to search for: ");
scanf("%c", &findChar);
//this was put here to see why my single char wasnt working in a function I had
printf("%c", findChar);
}
scanf("%c", &findChar); reads the next character pending in the input stream. This character will be the newline entered by the user that stopped the previous conversion, so findChar will be set to the value '\n', without waiting for any user input and printf will output this newline without any other visible effect.
Modify the call as scanf(" %c", &findChar) to ignore pending white space and get the next character from the user, or more reliably write a loop to read the read and ignore of the input line.
Note also that scanf("%[^\n]s", userIn); is incorrect:
scanf() may store bytes beyond the end of userIn if the user types more than 29 bytes of input.
the s after the ] is a bug, the conversion format for character classes is not a variation of the %s conversion.
Other problems:
void is not a proper type for the return value of the main() function.
the <stdio.h> header is required for this code.
Here is a modified version:
#include <stdio.h>
int main() {
char userIn[30];
int c;
char findChar;
int i, found;
printf("Please enter a string: ");
if (scanf("%29[^\n]", userIn) != 1) {
fprintf(stderr, "Input failure\n");
return 1;
}
/* read and ignore the rest of input line */
while ((c = getchar()) != EOF && c != '\n')
continue;
printf("Please enter a character to search for: ");
if (scanf("%c", &findChar) != 1) {
fprintf(stderr, "Input failure\n");
return 1;
}
printf("Searching for '%c'\n", findChar);
found = 0;
for (i = 0; userIn[i] != '\0'; i++) {
if (userIn[i] == findChar) {
found++;
printf("found '%c' at offset %d\n", c, i);
}
}
if (!found) {
printf("character '%c' not found\n", c);
}
return 0;
}
scanf("%[^\n]s", userIn); is a bit weird. The s is guaranteed not to match, since that character will always be \n. Also, you should use a width modifier to avoid a buffer overflow. Use scanf("%29[^\n]", userIn); That alone will not solve the problem, since the next scanf is going to consume the newline. There are a few options. You could consume the newline in the first scanf with:
scanf("%29[^\n]%*c", userIn);
or discard all whitespace in the next call with
scanf(" %c", &findChar);
The behavior will differ on lines of input that exceed 29 characters in length or when the user attempts to assign whitespace to findChar, so which solution you use will depend on how you want to handle those situations.
This question already has an answer here:
How to read / parse input in C? The FAQ
(1 answer)
Closed 6 years ago.
I am trying to write a simple program which will read two input lines, an integer followed by a string. However, it doesn't seem to work for me.
int main()
{
int i;
char str[1024];
scanf("%d", &i);
scanf("%[^\n]", str);
printf("%d\n", i);
printf("%s\n", str);
return 0;
}
Immediately after entering the integer and pressing "Enter", the program prints the integer. It doesn't wait for me to enter the string. Whats wrong? Whats the correct way to program this?
What you need to know
The problem with %[^\n] is that it fails when the first character to be read is the newline character, and pushes it back into the stdin.
The Problem
After you enter a number for the first scanf, you press Enter. %d in the first scanf consumes the number, leaving the newline character ('\n'), generated by the Enter keypress, in the standard input stream (stdin). %[^\n] in the next scanf sees this \n and fails for the reason given in the first paragraph of this answer.
Fixes
Solutions include:
Changing scanf("%d", &i); to scanf("%d%*c", &i);. What %*c does is, it scans and discards a character.
I wouldn't recommend this way because an evil user could trick the scanf by inputting something like <number><a character>\n, ex: 2j\n and you'll face the same problem again.
Adding a space (any whitespace character will do) before %[^\n], i.e, changing scanf("%[^\n]", str); to scanf(" %[^\n]", str); as #Bathsheba mentioned in a comment.
What the whitespace character does is, it scans and discards any number of whitespace characters, including none, until the first non-whitespace character.
This means that any leading whitespace characters will be skipped when inputting for the second scanf.
This is my recommendation: Clear the stdin after every scanf. Create a function:
void flushstdin(void)
{
int c;
while((c = getchar()) != '\n' && c != EOF);
}
and call it after every scanf using flushstdin();.
Other issues:
Issues unrelated to your problem include:
You don't deal with the case if scanf fails. This can be due to a variety of reasons, say, malformed input, like inputting an alphabet for %d.
To do this, check the return value of scanf. It returns the number of items successfully scanned and assigned or -1 if EOF was encountered.
You don't check for buffer overflows. You need to prevent scanning in more than 1023 characters (+1 for the NUL-terminator) into str.
This can be acheived by using a length specifier in scanf.
The standards require main to be declared using either int main(void) or int main(int argc, char* argv[]), not int main().
You forgot to include stdio.h (for printf and scanf)
Fixed, Complete Program
#include <stdio.h>
void flushstdin(void)
{
int c;
while((c = getchar()) != '\n' && c != EOF);
}
int main(void)
{
int i;
char str[1024];
int retVal;
while((retVal = scanf("%d", &i)) != 1)
{
if(retVal == 0)
{
fputs("Invalid input; Try again", stderr);
flushstdin();
}
else
{
fputs("EOF detected; Bailing out!", stderr);
return -1;
}
}
flushstdin();
while((retVal = scanf("%1023[^\n]", str)) != 1)
{
if(retVal == 0)
{
fputs("Empty input; Try again", stderr);
flushstdin();
}
else
{
fputs("EOF detected; Bailing out!", stderr);
return -1;
}
}
flushstdin();
printf("%d\n", i);
printf("%s\n", str);
return 0;
}
This simply, will work:
scanf("%d %[^\n]s", &i, str);
Instaed of scanf() use fgets() followed by sscanf().
Check return values of almost all functions with a prototype in <stdio.h>.
#include <stdio.h>
int main(void) {
int i;
char test[1024]; // I try to avoid identifiers starting with "str"
char tmp[10000]; // input buffer
// first line
if (fgets(tmp, sizeof tmp, stdin)) {
if (sscanf(tmp, "%d", &i) != 1) {
/* conversion error */;
}
} else {
/* input error */;
}
// second line: read directly into test
if (fgets(test, sizeof test, stdin)) {
size_t len = strlen(test);
if (test[len - 1] == '\n') test[--len] = 0; // remove trailing ENTER
// use i and test
printf("i is %d\n", i);
printf("test is \"%s\" (len: %d)\n", test, (int)len);
} else {
/* input error */;
}
return 0;
}
I have to read a user input that look like this one:
1 "string with space between quotes" 9.99
I want to store the number at the beginning of the input into an integer variable, the string between quotes into a string and the number at a double variable. I am using fgets() to get the string, but the problem is that the fgets() function keeps reading the user input until I type 0 and the number at the end of the input goes together with the string. scanf function doesn't do the job either, since it stops reading at the first space. My code looks like this:
#include <stdio.h>
int main () {
int code;
char description[50];
double value;
printf("Type in: ");
scanf("%d", &code);
fgets(description, 50, stdin);
scanf("%lf", &value);
printf("%d\n", code);
printf("%s\n", description);
printf("%2.2f", value);
}
Any ideas of how to read and store separately this 3 inputs considering they have to be at the same line?
OP's approach hopes to use fgets() to read a portion of a line, yet fgets() reads until an end-of-line '\n' is encountered.
Read the entire line with fgets() and then parse.
Using "%n" is an easy way to see if the entire string was parsed as expected.
int code;
char description[50];
double value;
#define MAX_LINE_SIZE (20 + 2 + sizeof description + 2 + 20 + 2)
char line[MAX_LINE_SIZE];
printf("Type in: ");
fflush(stdout);
fgets(line, sizeof line, stdin);
int n = 0;
sscanf(line, "%d \"%49[^\"]\"%lf %n", &code, description, &value, &n);
if (n == 0 || line[n] != '\0') {
fputs("Input formatted incorrectly\n", stderr);
return 1;
}
printf("%d\n", code);
printf("\"%s\"\n", description);
printf("%2.2f", value);
"%d \"%49[^\"]\"%lf %n" details
"%d" scan & toss whitespace, scan and save integer
" " scan and toss any whitespace
"\"" scan and match a '\"'
"%49[^\"]" scan up to 49 char that are not '\"', save in description and append '\0'
"%lf" scan & toss whitespace, scan and save double
"%n" save current offset of scan into n.
if (scanf("%d \"%49[^\"]\" %lf", &x, y, &z) == 3)
…process valid data…
else
…report erroneous input…
The relevant part for you is %49[^\"]; it matches a string until " is encountered (or it runs out of space). Note that this will not include the " into the string.
I created a program to make a diamond out of *'s. I am looking for a way to check if the type of input is an integer in the C language. If the input is not an integer I would like it to print a message.
This is what I have thus far:
if(scanf("%i", &n) != 1)
printf("must enter integer");
However it does not display the message if it's not an integer. Any help/guidance with this issue would be greatly appreciated!
you can scan your input in a string then check its characters one by one, this example displays result :
0 if it's not digit
1 if it is digit
you can play with it to make your desired output
char n[10];
int i=0;
scanf("%s", n);
while(n[i] != '\0')
{
printf("%d", isdigit(n[i]));
i++;
}
Example:
#include <stdio.h>
#include <string.h>
main()
{
char n[10];
int i=0, flag=1;
scanf("%s", n);
while(n[i] != '\0'){
flag = isdigit(n[i]);
if (!flag) break;
i++;
}
if(flag)
{
i=atoi(n);
printf("%d", i);
}
else
{
printf("it's not integer");
}
}
Use fgets() followed by strtol() or sscanf(..."%d"...).
Robust code needs to handle IO and parsing issues. IMO, these are best done separately.
char buf[50];
fgets(buf, sizeof buf, stdin);
int n;
int end = 0; // use to note end of scanning and catch trailing junk
if (sscanf(buf, "%d %n", &n, &end) != 1 || buf[end] != '\0') {
printf("must enter integer");
}
else {
good_input(n);
}
Note:
strtol() is a better approach, but a few more steps are needed. Example
Additional error checks include testing the result of fgets() and insuring the range of n is reasonable for the code.
Note:
Avoid mixing fgets() and scanf() in the same code.
{ I said scanf() here and not sscanf(). }
Recommend not to use scanf() at all.
strtol
The returned endPtr will point past the last character used in the conversion.
Though this does require using something like fgets to retrieve the input string.
Personal preference is that scanf is for machine generated input not human generated.
Try adding
fflush(stdout);
after the printf. Alternatively, have the printf output a string ending in \n.
Assuming this has been done, the code you've posted actually would display the message if and only if an integer was not entered. You don't need to replace this line with fgets or anything.
If it really seems to be not working as you expect, the problem must be elsewhere. For example, perhaps there are characters left in the buffer from input prior to this line. Please post a complete program that shows the problem, along with the input you gave.
Try:
#include <stdio.h>
#define MAX_LEN 64
int main(void)
{ bool act = true;
char input_string[MAX_LEN]; /* character array to store the string */
int i;
printf("Enter a string:\n");
fgets(input_string,sizeof(input_string),stdin); /* read the string */
/* print the string by printing each element of the array */
for(i=0; input_string[i] != 10; i++) // \0 = 10 = new line feed
{ //the number in each digits can be only 0-9.[ASCII 48-57]
if (input_string[i] >= 48 and input_string[i] <= 57)
continue;
else //must include newline feed
{ act = false; //0
break;
}
}
if (act == false)
printf("\nTHIS IS NOT INTEGER!");
else
printf("\nTHIS IS INTEGER");
return 0;
}
[===>] First we received input using fgets.Then it's will start pulling each digits out from input(starting from digits 0) to check whether it's number 0-9 or not[ASCII 48-57],if it successful looping and non is characters -- boolean variable 'act' still remain true.Thus returning it's integer.
I would like to take an array of integers as an input . Even if some one enter a space or an alpahabet, I want to ignore it.
int i=0;
while(L--){
scanf("%d",&arr[i++]);
}
But if I enter: 4 wtf the arr[0] gets initialized to 4 and the loop ends. Is there a way I can ignore everything after a space in scanf and just take the integers.
The input can be of form: 4 abc 3 def 7 ghi.
I think like this?
int a;
scanf("%d %*s", &a);
printf("%d\n",a);
And
input: 11 wwwww
output: 11
The * is used to skip an input without putting it in any variable.
Try this
while(L--){
scanf("%d",&arr[i++]);
while(getchar() != '\n'); // Consumes all characters after space.
}
You can use fgets to get the input string from stdin and then use sscanf to filter out integer from input string.
char input[50];
int num;
fgets(input, 50, stdin);
sscanf(input, "%d %*s", &num);
The %*s rejects the string after the integer encountered.
I think that what you'd actually like to achieve here is to extract all numbers from a random input. I propose to use fgets to read the input into a buffer and next, using isdigit and strtol, extract the numbers:
#include <stdio.h>
int main(void)
{
char buff[255] = {0};
fgets(buff, sizeof(buff), stdin); // read data from stdin
char *ptr = buff;
do {
if(!isdigit(*ptr)) // check if current character is a digit
continue; // if not...
long val = strtol(ptr, &ptr, 10); // read a number
printf("%ld\n", val); // print it
} while(*ptr++); // ...move to next character
}
...and the quick test:
[root#dmudms01 temp]# ./a.out
1abc23 **4
1
23
4