The following code compiles and works as expected, despite one frustrating error in program flow that I don't understand ..
The loop in the middle of the main function works fine if I pass 2 or 5 as input. However, when I pass -3 or anything below zero (such as a character, which return -1), the loop continues forever and the program doesn't even pause for me to provide input for the scanf function ..
#include <stdio.h>
#include <stdlib.h>
void getNum(char * prompt, int*num)
{
printf("%s", prompt);
scanf("%d", num);
}
int main(int argc, char ** argv)
{
int num = -1;
while(num < 0) { // problem here
getNum("Number of times you go to the gym in a week: ", &num);
}
return EXIT_SUCCESS;
}
I wonder were the mistake is ..
I noticed something strange .. When I change the loop to a do-while loop it works just fine ..
int main(int argc, char ** argv)
{
int num;
do {
getNum("Number of times you go to the gym in a week: ", &num);
} while (num < 0); // this works fine ..
return EXIT_SUCCESS;
}
Also, for some reason, I recompiled the code and it worked fine ..
Can anybody explain this ?
After accept answer
scanf("%d", num);, upon reading non-numeric input simple returns 0, leaving *num alone. The offending text is still in stdin and subsequent calls will get the same text and same results. Code should check the scanf() result value.
// weak
scanf("%d", num); // fails to consume offending input.
// good
*num = 0; // default answer
int retval;
do {
printf("%s", prompt);
retval = scanf("%d", num); // returns EOF, 0, or 1
// consume rest of line
int c;
while ((c = fgetc(stdin)) != '\n' && c != EOF);
} while (retval == 0); // repeat is no number read and stdin still open
[Edit]
Avoid using scanf(). Offer How to test input is sane as a solution to well handle reading int.
You could try clearing STDIN data after you tried scanf :
void getNum(char * prompt, int*num)
{
printf("%s", prompt);
scanf("%d", num);
// clean stdin
char c;
scanf("%c",&c);
while (c != '\n' && c != EOF) scanf("%c",&c);
}
Related
I'm trying to create a program that asks to type something and check if it is an integer. If it is an integer, then print "the integer is ...". Else, print "try again" and waits for another input. However, the program prints an infinite number of "try again" if you type in a character. Here's the source code:
#include <stdio.h>
#include <stdbool.h>
int main()
{
int inp;
bool t = 1;
printf("type an integer\n");
while (t) {
if (scanf("%i", &inp) == 1) {
printf("The integer is %i", inp);
t = 0;
} else {
printf("try again");
scanf("%i", &inp);
}
}
}
OP's code fail to consume the offending non-numeric input. It remains in stdin, for the next input function. As it is unfortunately just another scanf("%i", &inp) which fails the same way - infinite loop.
After attempting to read an int, read the rest of the line.
#include <stdio.h>
#include <stdbool.h>
int main() {
int inp;
int scan_count;
printf("Type an integer\n");
do {
scan_count = scanf("%i", &inp); // 1, 0, or EOF
// consume rest of line
int ch;
while ((ch == fgetchar()) != '\n' && ch != EOF) {
;
}
} while (scan_count == 0);
if (scan_count == 1) {
printf("The integer is %i\n", inp);
} else {
puts("End of file or error");
}
}
An even better approach would read the line of user input with fgets(). Example
When you entered a char, the variable inp in scanf("%d", &inp) would get null, since the input that doesn't match the format string. And the character you input would remain in the buffer, so that's the reason both your scanf would not stop.
A simplest way to fix this is modify your second scanf("%i", &inp); to scanf("%c", &c); (don't forget to declare a char c in your main function).
check here while(t) its in an infinite loop because you have to set a condition for t something like while(t==1) or while(t>1) or (t<1) something like that. saying while(t) means that t can be anything and it will continue to run.
There is nothing in to break the while loop.
consider getting rid of the boolean, and simply using a while (1) loop with a break. Also you should be using "%d" to indicate an integer in scanf/printf. And there is no need for the scanf call in the else, since your program would loop back and call scanf again anyway.
#include <stdio.h>
int main() {
int inp = 0;
printf("type an integer\n");
while (1) {
if (scanf("%d", &inp) == 1) {
printf("The integer is %d", inp);
break;
}
else {
printf("try again");
}
}
return 0;
}
I hope this helped.
My teacher has asked me to "Fool proof" my code from any sort of misuse, So I have come up with an
program that can remove any empty values (by disallowing them entirely)
Here is the Un-foolproofed code
#include <stdio.h>
#include <conio.h>
int main()
{
char text[16];
printf("Type something: ");
fgets(text,16, stdin);
printf("You typed: %s",text);
getch();
}
I have made some simple adjustments to ensure there is no error, however, i cannot get the if filter to work properly, as it still allows the NULL input
#include <stdio.h>
#include <conio.h>
int main()
{
char text[16];
int loop;
do
{
printf("Type something: ");
fgets(text,16, stdin);
if( text[0] == '\0')
{
printf("Try again");
system("cls");
loop=1;
}
else
{
loop = -1;
}
}
while(loop > 0);
printf("You typed: %s",text);
getch();
}
I've tried google and i cannot get a solid answer, this probably is some very simple line of code, but sadly i have no idea what it is.
Edit: it's fixed, the if statement should be:
if (text[0] == '\n')
Using the return value from fgets() is the best first step to fool-proofing user I/O.
char text[16];
printf("Type something: ");
if (fgets(text, sizeof text, stdin) == NULL) {
if (feof(stdin)) Handle_stdin_is_closed(); // no more input
if (ferror(stdin) Handle_IOerror(): // very rare event, more common with files
}
// Test is input is is only a '\n'
if (text[0] == '\n')
printf("Try again");
// Look for long line.
size_t len = strlen(text);
if (len + 1 == sizeof text && text[len - 2] != '\n') HandleLongLine();
The next step is to look for scan errors. Let's assume code is to read a long.
errno = 0;
char *endptr;
long = strtol(text, &endptr, 10);
if (errno) Handle_NumericOverflow();
if (text == endptr) Handle_InputIsNotNumeric();
while (isspace((unsigned char) *endptr)) endptr++;
if (*endptr != '\0') Handle_ExtraTextAfterNumber();
Although this is a lot of code, robust handling of hostle user input is best spun off to a helper function where lots of tests can be had.
char * prompt = "Type something: ";
long number;
int stat = GetLong(stdin, prompt, &number); // put all tests in here.
if (stat > 0) Handle_SomeFailure();
if (stat < 0) Handle_EOF();
printf("%ld\n", number);
fgets reads a whole line including the newline into the buffer and 0-terminates it.
If it reads something and then the stream ends, the read line will not have a newline.
If the line does not fit, it won't contain a newline.
If an error occurs before it successfully reads the first character, it returns NULL.
Please read the man-page for fgets: http://man7.org/linux/man-pages/man3/fgets.3.html
According to the fgets() man page
char *fgets(char *s, int size, FILE *stream);
//fgets() returns s on success, and NULL on error or when end of file
//occurs while no characters have been read.
so, you can check the return value of fgets()
n = fgets(text,16, stdin);
if that value is NULL, then nothing have been read.
you can do this by checking the value of n in a for loop,
if( n == NULL)
{
printf("Try again");
system("cls");
loop=1;
}
else
{
loop = -1;
}
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'm having a problem with scanf freezing. I've looked around and while some questions are similar, they haven't helped in solving my problem.
main(int argc, char **argv) {
//FILE *stream = stdin;
if (stdin == NULL) {
printf("Could not open file");
return 0;
}
int exists = 0;
char letter;
char next = 'H';
char word[30];
int frequency = -1;
int sample = -1;
char *channels;
channels=malloc(sizeof(7*sizeof(char)));
int bitres = -1;
int secondE = 0;
while (exists == 0) {
scanf("%c", &letter); //this is the problem, possibly scanf
printf("AFTER");
if (letter == EOF) {
// printf(letter);
printf("HEADER NOT DETECTED");
return 0;
}
I've pinpointed the problem using printf. I'm currently piping in another file through command prompt into this program. When I reach scanf it just hangs. If anyone knows the solution I would be very thankful.
On a side note, is using scanf bad practice? It's just as easy to assign stdin to a file pointer (I actually have this commented out) but scanf seemed just as easy.
what do you mean by freezing. i run this code. when your code reach in scanf it wait for your input. you give some input , then see what happen.
scanf is not a bad practice .
channels=(char*)malloc(sizeof(7*sizeof(char)));
int bitres = -1;
int secondE = 0;
while (exists == 0)
{
scanf("%c", &letter); // ok
printf("AFTER");
printf("\n");
printf("%c", letter);
printf("\n");
if (letter == EOF) {
// printf(letter);
printf("HEADER NOT DETECTED"); }
return 0;
}
scanf never return EOF also.
while (exists == 0)
{
scanf("%c", &letter); // ok
printf("AFTER");
printf("\n");
printf("%c", letter);
printf("\n");
if (letter == EOF) {
// printf(letter);
printf("HEADER NOT DETECTED"); }
return 0;
}
So when using this the
if (letter == E0F)
section above is a bit too literal. Why not just use a char to store your desired answer and use the following to create
if(strcmp(letter, *desired char here*) == 0){
just a guess considering the fact it may be client side if your scanf function is freezing only in debug but with the example above it is a bit more user friendly when reading the code and will not have any errors when dealing with other characters and integers later on in your program. Depending on what you want to accomplish with it.
#include <stdio.h>
#define SIZE 5
void func(int*);
int main(void)
{
int i, arr[SIZE];
for(i=0; i<SIZE; i++)
{
printf("Enter the element arr[%d]: ", i);
scanf("%d", &arr[i]);
}//End of for loop
func(arr);
printf("The modified array is : ");
for(i=0; i<SIZE; i++)
printf("%d ", arr[i]);
return 0;
}
void func(int a[])
{
int i;
for(i=0; i<SIZE; i++)
a[i] = a[i]*a[i];
}
Output :::
While I'm entering integer elements the output is OK.But as I entered a float value like 1.5, it didn't ask for other elements and the O/P is as shown in the figure.I think it should implicitly typecast 1.5 to 1 but it didn't happen..can u plz tell why this happened ? All the info about the compiler is shown in the figure.
When you scanf("%d") a value like 1.5 the scanning will stop at the decimal point and return 1.
The next time you call scanf, the pointer will still point to the decimal point and your scan will return immediately because there are no digits there to scan.
You should be checking the return value from scanf - it gives you the number of items successfully scanned which will be 1 initially for the 1 before the decimal point, and 0 from then on.
As an aside, scanf stands for "scan formatted" and I'll guarantee you won't find anything more unformatted than user input.
Investigate looking into fgets for line input. Here's a copy of a function I often use for such purposes:
#include <stdio.h>
#include <string.h>
#define OK 0
#define NO_INPUT 1
#define TOO_LONG 2
static int getLine (char *prmpt, char *buff, size_t sz) {
int ch, extra;
// Get line with buffer overrun protection.
if (prmpt != NULL) {
printf ("%s", prmpt);
fflush (stdout);
}
if (fgets (buff, sz, stdin) == NULL)
return NO_INPUT;
// If it was too long, there'll be no newline. In that case, we flush
// to end of line so that excess doesn't affect the next call.
if (buff[strlen(buff)-1] != '\n') {
extra = 0;
while (((ch = getchar()) != '\n') && (ch != EOF))
extra = 1;
return (extra == 1) ? TOO_LONG : OK;
}
// Otherwise remove newline and give string back to caller.
buff[strlen(buff)-1] = '\0';
return OK;
}
// Test program for getLine().
int main (void) {
int rc;
char buff[10];
rc = getLine ("Enter string> ", buff, sizeof(buff));
if (rc == NO_INPUT) {
// Extra NL since my system doesn't output that on EOF.
printf ("\nNo input\n");
return 1;
}
if (rc == TOO_LONG) {
printf ("Input too long [%s]\n", buff);
return 1;
}
printf ("OK [%s]\n", buff);
return 0;
}
Once you get a line in with that function, you can sscanf it to your heart's content, handling errors much easier.
What's happening is that scanf stops reading an integer when it sees the '.' character, and leaves it in the input buffer. Then subsequent calls to scanf fail because the next character is '.' and not something parseable as an integer.
How do you fix this? The first step is to forget you ever heard of scanf and always use fgets to read whole lines of input, then process them after you read them into a string buffer. You can use sscanf for this purpose, but a robust function like strtol would be a lot better.
Problem with buffer - I think the remaining part (.5) remains on the buffer.
use flushall(); after your scanf("%d..