I'm facing a little problem with fgets when the input string exceeds its predefined limit.
Taking the example below:
for(index = 0; index < max; index++)
{printf(" Enter the %d string : ",index+1)
if(fgets(input,MAXLEN,stdin))
{
printf(" The string and size of the string is %s and %d \n",input,strlen(input) + 1);
removeNewLine(input);
if(strcmp(input,"end") != 0)
{ //Do something with input
}
}
Now when I exceed the length MAXLEN and enter a string, I know that the input will append a '\0' at MAXLEN -1 and that would be it. The problem happens when I try to enter the 2nd string which is not asked for i.e
Output :
Enter the first string : Aaaaaaaaaaaaaaaaaaaa //Exceeds limit
Enter the second string : Enter the third string : ....Waits input
So, I thought I should clear the buffer the standard way as in C. It waits until I enter
return
two times, The first time it being appended to the string and the next time,expecting more input with another return.
1. Is there any method by which I can clear the buffer without entering the extra return?
2. How do I implement error handling for the same? Because the fgets return value will be Non-null and strlen(input) gives me the accepted size of the string by fgets, what should be done?
Thanks a lot
If I understood correctly, looks like you want to avoid twice enter press, when entered input is within range.
A work around would be
for(index = 0; index < max; index++)
{
printf(" Enter the %d th string :",index);
// if (strlen(input) >=MAXLEN )
if(fgets(input,MAXLEN,stdin))
{
removeNewLine(input);
if(strcmp(input,"end") != 0)
// Do something with input
;
}
if (strlen(input) == MAXLEN-1 )
while((ch = getchar())!='\n' && ch != EOF );
}
With a limitation that it will again ask for two times enter when entered characters are exactly MAXLEN-2.
Or else you can simply form your input using character by character input.
while ((c=getchar()) != '\n' && c != EOF)
;
or:
scanf("%*[^\n]%*c");
Related
I am fairly new when it comes down to C programmming. That's why i am working my way up by doing some of the easier exercises. The exercise i'm working on is the "guess the number" game, where the user must guess the number that lies between two numbers (upper and lower bounds). The program is doing what it must, with one exception: when the user enters a character instead of an integer, the program gets stuck in an infinite loop. The only way to break out of this loop is by using a break statement and restarting the program. What i want instead, is to have the program request for the users input again, untill an integer is entered.
Can someone tell me why the programm gets stuck in this infinite loop and why it is not requesting for input again trough scnanf like it did in the first iteration? your help will be appreciated. thank you.
//globals
int secret_nr;
int guess;
int upper_bound = 100;
int lower_bound = 1;
int total_guesses = 1;
void check_input(void) {
if (guess < lower_bound || guess > upper_bound) {
printf("Invalid input! Your guess must be between %d and %d\n", lower_bound, upper_bound);
}
else if (guess < secret_nr) {
printf("Higher\n");
total_guesses++;
}
else if (guess > secret_nr) {
printf("Lower\n");
total_guesses++;
}
else if (guess == secret_nr) {
printf("correct! You guessed the number after guessing %d times!\n", total_guesses);
}
}
int main(int argc, char* argv[]) {
srand(time(NULL));
secret_nr = (rand() % upper_bound) + 1;
printf("Guess the number between %d and %d:\n", lower_bound, upper_bound);
do {
if (scanf("%d", &guess)) {
check_input();
}
else {
printf("Invalid input! Only integer values are allowed!\n");
//break;
}
} while (guess != secret_nr);
return 0;
}
If scanf fails to parse its input according to the specified format, then the input will be left in the input buffer for the next call to scanf which will read the very same input and again fail. And so on and on and on...
The simple solution is to first of all read the whole line of input, using e.g. fgets. Then you can use sscanf in that (now extracted) input to attempt to parse it.
Further complicating your current code is the fact that if scanf fails in some other way, it will return EOF which is the integer -1, which is "true". That will of course lead to problems with your logic and looping as well.
I see this reply in another post: https://stackoverflow.com/a/1716066/5687321
scanf consumes only the input that matches the format string, returning the number of characters consumed. Any character that doesn't match the format string causes it to stop scanning and leaves the invalid character still in the buffer. As others said, you still need to flush the invalid character out of the buffer before you proceed. This is a pretty dirty fix, but it will remove the offending characters from the output.
char c = '0';
if (scanf("%d", &number) == 0) {
printf("Err. . .\n");
do {
c = getchar();
}
while (!isdigit(c));
ungetc(c, stdin);
//consume non-numeric chars from buffer
}
int main() {
char userInput[100]; //Store user input
//Take user input
//scanf(" %s",&userInput);
//scanf("%[^\n]s",&userInput);
//scanf("%[^\n]", &userInput);
//gets(userInput);
scanf("%[]s", &userInput); //This takes input but doesnt leave input loop
printf(" %s",userInput);
//i = index to start for looping through the string, starting at the beginning
//count = Stores occurrences of '$'
//inputLength = length of the input, used for limit of loop
int i =0,count =0;
int inputLength = strlen(userInput);
//Loop through the user input, if the character is '$', the integer count will be incremented
for (i; i < inputLength; i++){
if (userInput[i] == '$'){
count++;
}
}
printf("%d", count);
return 0;
}
Hi i'm having some issues with my code, i need to take an input of 3 lines and count the number of'$' in the input. The input method not commented "scanf("%[]s", &userInput);" is the one only i have discovered to take all 3 lines of input, BUT i can't break the input loop and continue with my program.
Any help would be greatly appreciateed
To read 3 lines with the cumbersome scanf(), code needs to look for '$', '\n', and EOF. The rest of input is discardable.
int count = 0;
int line = 0;
while (line < 3) {
scanf("%*[^$\n]"); // Scan for any amount of characters that are not $ nor \n,
// "*" implies - do not save.
char ch;
if (scanf("%c", &ch) != 1) { // Read next character.
break;
}
if (ch == '$') count++;
else line++;
}
printf("$ count %d\n", count);
As #chux suggested, reading with fgets provides a convenient way to protect from buffer overrun and without having to hard code field-width modifiers in scanf conversion specifiers.
Here, if all you need to do is count the number of '$' characters found in your input (regardless of how many lines), you can simply read ALL the input in fixed sized chunks of data. fgets does just that. It doesn't matter if you have one line, or one million lines of input. It also doesn't matter if your input lines are one-character or one million characters long. You can simply read each line and count the number of '$' found within each chunks of data read, keeping a count of the total found.
You can do this for any character. If you wanted to also count the number of line, you can simply check for '\n' characters and keep a total there as well. The only corner-case in counting lines with fgets is to insure you protect against a non-POSIX end-of-file (meaning a file with no '\n' as the final character). There are a couple of ways to handle this. Checking that the last character read was a '\n' is as good as any.
Putting the pieces together, and protecting against a non-POSIX eof, you could do something similar to the following, which simply reads all data available on stdin and outputs a final '$' and line count:
#include <stdio.h>
#define MAXC 100
int main (void) {
char buf[MAXC] = ""; /* buffer to hold input in up to MAXC size chunks */
size_t lines = 0, dollars = 0; /* counters for lines and dollar chars */
int i = 0;
while (fgets (buf, MAXC, stdin)) /* read all data */
for (i = 0; buf[i]; i++) /* check each char in buf */
if (buf[i] == '$') /* if '$' found */
dollars++; /* increment dollars count */
else if (buf[i] == '\n') /* if '\n' found */
lines++; /* increment line count */
if (i && buf[i-1] != '\n') /* protect against non-POSIX eof */
lines++;
/* output results */
printf ("input contained %zu lines and %zu '$' characters.\n",
lines, dollars);
return 0;
}
Look things over and let me know if you have further questions.
scanf("%[]s", &userInput);" is the one only i have discovered to take all 3 lines of input, BUT i can't break the input loop and continue with my program.
"%[]" is an invalid scanf() specifier. Anything may happen, it is undefined behavior, including taking all lines in and not returning.
The 's' in the format serves no purpose here - drop it.
Yes fgets() is best but let us abuse scanf() to read 3 lines and look for '$'.
char line[3][100] = {0};
// v--------- Consume all leading whitespace
// | vv ----- limit input to 99 characters as scan() appends a \0
// | || v-v-- Look for "not \n"
#define FMT_1LINE " %99[^\n]"
// Let the compiler concatenate the 3 formats into 1 string for scanf
int scan_count = scanf(FMT_1LINE FMT_1LINE FMT_1LINE, line[0], line[1], line[2]);
// Check return value
if (scan_count == 3) {
// Successfully read 3 lines
int count = 0;
for (int line_index = 0; line_index < 3; line_index++) {
char *s = line[line_index];
while (*s) { // no need for strlen(), just loop until the null character
count += *s == '$';
s++;
}
}
printf("$ count %d\n", count);
}
You write:
scanf("%[]s", &userInput); //This takes input but doesnt leave input loop
but the comment is at best misleading. Your format string is malformed, so the behavior of the scanf call is undefined. An empty scan set (between the [] in the format) does not make sense, because the resulting field could never match anything. Therefore, a ] appearing immediately after the opening ] of the scan set is interpreted as a literal character not the ending delimiter. Your scan set is therefore unterminated.
Note, too, that %[ is its own field type, separate from %s. An 's' following the closing ] of the scan set is not part of such a field descriptor, but rather an ordinary character to match.
A trivial way to do this with scanf would be to read characters one at a time in a loop via a %c field. This is probably not what the exercise is looking for, and it's a hack to use scanf() instead of getchar() for this purpose, but perhaps it would serve:
int nl_count = 0;
int dollar_count = 0;
do {
char c;
int result = scanf("%c", &c);
if (result != 1) {
break;
}
switch (c) {
case '\n':
nl_count++;
break;
case '$':
dollar_count++;
break;
}
} while (nl_count < 3);
I'm afraid it would be much more complicated to do it safely reading multiple characters at a time with a %[ field, and there is no safe way to read all three lines in one scanf call, unless you can rely on the input lines not to exceed a line length limit known to you.
int readMatrix() {
char userInput[100][3]; //Store user input
int j = 0, m = 0;
for(m = 0; m < 3; m++){
scanf("%s", &userInput[j][m]); //This takes input (Ex: 22 *(enter)* 33$ *(enter)* 66$ *(enter)*
j++; //increase the column
}
int i =0,count =0;
m = 0;
//Loop through the user input, if the character is '$', the integer count will be incremented
for (i = 0; i < 100; i++){
for(m = 0; m < 3; m++){
if (userInput[i][m] == '$'){
count++;
}
}
}
printf("%d", count);
return 0;
}
Here's a small portion of a practice I'm doing preventing erroneous inputs.
while(1) {
printf("Choose From 1 to 7 ");
if( scanf("%d", &nNum ) != 1) {
printf("Please only choose from the numbers 1-7.");
fgets(sErraticInputs, 100 , stdin);
} else if (nNum > 7 || nNum <= 0) {
printf("Please only choose from the numbers 1-7.");
} else {
break;
}
}
I was doing a good job, until I entered "6;p". It executed the 6 portion and ran correctly, but technically speaking it should have taken the whole thing as the input, and proceeded with the error message.
First of all I don't think the posted code can give the said result. The break statement will end the while(1) when 6 has been read so there will not be printed an error message.
If we assume that the break isn't part of your real code this is what happens:
When scanf is told to read an integer, it will continue reading from the input stream as long as the next character (together with the previous read characters) can be converted into an integer. As soon as the next character can not be used as part of an integer, scanf will stop and give you the result of what it has parsed so far.
In your case the input stream contains
6;p\n
So scanf will read the 6 and stop (i.e. return 6). The input stream now contains:
;p\n
Consequently this will be the input for your next scanf and cause the input error, you saw.
One way to solve this would be to flush stdin after all scanf - both on success and on failure:
nNum = 0;
while(nNum != 7) // Just as an example I use input 7 to terminate the loop
{
printf("Choose From 1 to 7 ");
if( scanf("%d", &nNum ) != 1 || nNum > 7 || nNum <= 0)
{
printf("Please only choose from the numbers 1-7.");
}
else
{
printf("Valid input %d\n", nNum);
// **************************** break;
}
fgets(sErraticInputs, 100 , stdin); // Always empty stdin
}
note: Using fgets with size 100 doesn't really ensure a complete flush... you should actually use a loop and continue until a '\n' is read.
With the change above input like 6;p will be taken as a valid input with value 6 and the ;p will be thrown away.
If that's not acceptable, you could drop the use of scanf and do the parsing yourself. There are several options, e.g. fgets or fgetc
The example below uses fgetc
#include <stdio.h>
#include <stdlib.h>
int get_next()
{
int in = fgetc(stdin);
if (in == EOF) exit(1); // Input error
return in;
}
void empty_stdin()
{
while(get_next() != '\n') {};
}
int main(void) {
int in;
int nNum = 0;
while(nNum != 7)
{
printf("Choose From 1 to 7 \n");
in = get_next();
if (in == '\n' || in <= '0' || in > '7') // First input must be 1..7
{
printf("Please only choose from the numbers 1-7.\n");
if (in != '\n') empty_stdin();
}
else
{
nNum = in - '0';
in = get_next();
if (in != '\n') // Second input must be \n
{
printf("Please only choose from the numbers 1-7.\n");
empty_stdin();
}
else
{
printf("Valid input: %d\n", nNum);
}
}
}
return 0;
}
This code will only accept a number (1..7) followed by a newline
Here's why the "whole thing" is not taken as the input. From the man pages:
The format string consists of a sequence of directives which describe
how to process the sequence
of input characters. If processing of a directive fails, no further input is read, and scanf()
returns. A "failure" can be either of the following: input failure, meaning that input characters
were unavailable, or matching failure, meaning that the input was inappropriate...
Here's the full text. Have a look at this as well.
One approach would be to read in the whole input using fgets and check whether the length of the input is greater than 1. For an input of length 1, check if the input is a number and so on...
For my programming class I've written a program to calculate the sum of divisors. So I've gotten to my final part which is error checking, which I am having a problem with if I read a character in. I have searched on S.O. earlier,as well as tried to figure something out, and couldn't find a solution that works for endless negative numbers until 100.
When I hit a character it sets it to 0 and just goes to the end, where I want it to exit once it reads it in
int main (void){
int userIN=0;
int i = 0;
int next = 0;
int temp= 105;
int cycle;
puts("Enter up to 10 integers less than or equal to 100");
while(scanf("%d ", &userIN) !=EOF && (i < 10))
{
if(userIN > 100){
printf("Invalid Input\n");
exit(1);
}
else if(userIN < 100)
{
Thanks for the help in advance
EDIT: The program is cycling through correctly, My Issue is error checking for a character being entered not anything with the code itself
scanf() returns a value other than EOF if it cannot read the values specified by the format string (e.g. with %d, it encounters data like foo). You can check for that. The caveat is that it does not read the offending data from stdin, so it will still be there to affect the next call of scanf() - which can result in an infinite loop (scanf() reporting an error, call scanf() again, it encounters the same input so reports the same error).
You are probably better off reading a whole line of input, using fgets(). Then check the input manually or use sscanf() (note the additional s in the name). The advantage of such an approach is that it is easier to avoid an infinite loop on unexpected user input.
You could loop while i is less than 10. The first if will see if scanf failed. If so the input buffer is cleared and the while loop tries again. If EOF is captured, then exit. If scanf is successful, the input is compared to 100 and if in range, the while loop counter is incremented.
Declare int ch = 0;
while ( i < 10) {
printf("Enter %d of 10 integers. (less than or equal to 100)\n", i + 1);
if(scanf(" %d", &userIN) != 1)
{
while ( ( ch = getchar()) != '\n' && ch != EOF) {
//clear input buffer
}
if ( ch == EOF) {
exit ( 1);
}
}
else {
if(userIN > 100){
printf("Invalid Input\n");
}
else
{
i++;// good input advance to the next input
printf("Valid");
}
}
}
I've wrote a program that gets from the user a number, and then gets from the user a name for every number...
for example if the user entered the number 10, it'd take 10 names and put it in an array of structs...
Everything is working great, except that when I print the names, it skip'd the first letter...
like if I put in the name "Amit", it printed "mit"... , also, the last string I've entered didnt save at all..
Here is what I wrote :
const number_candidates; // Getting the number of candidates
#define MAX 256
#define min_candidate 10
#define max_candidate 60000
typedef struct candidate // Getting details for each candidate
{
char name[MAX];
int sing_grade;
int per_grade;
int cam_grade;
int sharmanti_grade;
}candidate;
void get_details_candidates(candidate candidate[MAX])
{
int i = 0;
printf ("\n");
for (i = 0 ; i < number_candidates ; i++)
{
printf ("Please enter the %d name: ", i + 1);
fgets (candidate[i].name, MAX, stdin);
getchar();
}
}
Here is the printing:
for (i = 0 ; i < number_candidates ; i++)
{
printf ("%s\n", candidates[i].name);
}
Thanks for your help!
Why do have the getchar() after the fgets()? I think that is your culprit.
The getchar() after the fgets() is eating the first letter of the following line.
Your problem reading the first name may be caused by a stray newline in the input stream. To flush stdin before your input loop you can use something like this:
while((c = getchar()) != '\n' && c != EOF)
/* discard the character */;
I think fflush(stdin) is undefined behaviour so don't do that.