Infinite loop with scanf in while loop - c

I'm a very beginner in C, and I'm trying to put a range in the numbers, but the infinite loop appears when a letter out of range is typed (for example: p).
If I type a number out of range, it works.
I read about and I think its a problem with the buffer and the function scanf, when I press "Enter" I include \n. So I tried to clean by scanning with a char, but didn't work.
I also tried to put a space (' ') before the %x, and didn't work.
The scanf it's been ignored after I put an invalid letter; if I put an invalid number, the program works.
#include <stdio.h>
int main()
{
int validity, pos; //validity 0:not valid, repeat the loop; validity 1: valid number
char enter;
while (validity == 0) {
printf("Player1 1, type the position in hexadecimal (1 to f):\n");
scanf(" %x%c", &pos, &enter); //here, the number pos is already in decimal
if (pos == NULL){
pos = 99; //if the letter typed is improper, I set 99, because is out of range
}
if(pos<=15 && pos >=0){
validity = 1;
} else {
printf("Invalid number, out of range\n");
validity = 0;
}
}
}

The very first time in your loop, validity does not have a defined value at all.
It might be 1, it might be 0, it might be 65,532.
You should assign it an initial value.
int validity = 0, pos; //validity 0:not valid, repeat the loop; validity 1: valid number
You declared pos as an int; it will never be NULL. It will have integer values.
This line makes no sense:
if (pos == NULL){
You should initialize that variable as well.
int validity = 0, pos = 99; //validity 0:not valid, repeat the loop; validity 1: valid number

C doesn't have default values for primitive data types. Hence in the line
int validity, pos;
You should probably set validity to some default value like 0 so that the loop runs at least once no matter what the input is(valid or invalid). Alternatively using a do while loop in this situation seems to be a more logical decision.
do
{
//Your code
} while(validity == 0);
In that case you won't have to worry about setting a default value to validity.
Also as #abelenky pointed out earlier, checking pos for NULL is a technically bad idea as well. You could as well just skip this part
if (pos == NULL)
{
pos = 99;
}
As pos is declared to be int, if the value of pos doesn't lie between 0 and 15 then it is automatically declared invalid by this part of your code.
if(pos<=15 && pos >=0)
{
validity = 1;
}
else
{
printf("Invalid number, out of range\n");
validity = 0;
}
Hence there is no need to make another block for checking it's validity.

The cause of the infinite loop is that if you input a letter, the "\n" that follows it is taken as the input of scanf(...) function within the next loop. So you can simply add "getchar()" to fix it. Note the ā€œ\nā€ after a number is ignored.
Differently, when you type a number out of range, it can be resolve with hex, and you can print it to see. But the letter can't(must be between a-f).
You can reference this:
#include <stdio.h>
int main(int argc, char *argv[])
{
int validity=0, pos=99;
while (validity == 0){
printf("Player1 1, type the position in hexadecimal (1 to f):\n");
scanf("%x", &pos);
if(pos<=15 && pos >=0){
validity = 1;
}else {
printf("Invalid number, out of range\n");
getchar();
}
}
}
Good luck.

Related

How to implement a user answer that will either start a loop again or end the program

The purpose of this code is to sum up to a number greater than zero and then ask the user if they want to sum another number. The summing part of the program works, but I can't seem to get the user input to work correctly. Any help or insight would be appreciated.
#include <stdio.h>
int main(void)
{
char * another;
int start = 0;
int x = 0;
int Input=0;
int sum = 0;
do
{
printf("Please enter a number greater than zero to sum up to: \n");
scanf("%d", &x);
if(start<x)
Input=1;
else
printf("The number needs to be greater than zero.\n");
}
while (Input ==0) ;
while (start <= x) {
sum += start;
start++;
if (start >x)
{
printf("The sum of the numbers 0 to %d is: %d \n" ,x , sum);
}
while (start >x)
{
printf("Would you like to sum another number? Y/N:");
scanf("%s",another);
}
} while ((another =="y")||(another=="Y"));
return 0;
}
There are quite a few things to address here.
char *another allocates no memory for a string to be placed. It is just an uninitialized pointer to memory, containing a garbage value. Utilizing this value in any way will invoke Undefined Behavior.
You must allocate some memory if you want to store a string. The easiest way is on the stack, as a character array:
char another[64];
Strings should not be compared with ==, as that compares their addresses, which even for two identical literals ("a" == "a") might not be the same. Use strcmp to compare strings.
There is no while ... while.
while (start <= x) {
/* ... */
} while ((another =="y")||(another=="Y"));
This is one while statement with a Compound Statement for a body, followed by another, separate while statement with an empty Expression Statement for a body.
More clearly read as:
while (start <= x) {
/* ... */
}
while ((another =="y")||(another=="Y"));
It is of course possible to have a do ... while whose body is itself a while statement
do
while (/* ... */) {
/* ... */
}
while (/* ... */);
but this is a bit confusing, and probably not what you really want.
The return value of scanf should be checked such that it matches the number of conversions you expected to succeed, in order to proceed to work with that data.
if (scanf("%d", &x) != 1) {
/* Something has gone wrong, handle it */
}
Failure to check this value can result in using uninitialized or otherwise indeterminate data.
This is also where one of the major pitfalls of scanf occurs:
In the event that scanf cannot apply a conversion to the input stream, the data is left in the input stream, and scanf fails early. Your next call to scanf will read that same data unless it is purged first (usually accomplished by consuming characters until a newline or end-of-file is reached).
This is why it is generally advised to separate your reading and your parsing to gain more control. This can be achieved with fgets and sscanf, to first read a line of input, and then parse it.
The other option is to simply terminate the program on any failure, which is what I've done in the example below (for simplicity's sake).
Additionally note that scanf("%s", buffer) is vulnerable to overflowing buffer. Always limit your input using field width specifiers, in the form scanf("%127s", buffer), which should be the length of your buffer minus one (leaving room for the NUL terminating byte).
Some things to consider:
Allocate memory for your string buffer.
Limit the amount of information that can be read into your buffer.
Handle errors in some way.
Use continue or break to help structure your flow.
Use separate functions to clarify a common task.
An example:
#include <stdio.h>
int seqsum(int from, int to) {
int sum = 0;
while (from <= to)
sum += from++;
return sum;
}
int main(void) {
char another[64];
int working = 1;
int n;
while (working) {
printf("Please enter a number greater than zero to sum up to: \n");
if (scanf("%d", &n) != 1) {
fprintf(stderr, "Invalid input or read error.\n");
return 1;
}
if (n < 0) {
printf("The number needs to be greater than zero. Retrying..\n");
continue;
}
printf("The sum of the numbers 0 to %d is: %d\n", n, seqsum(0, n));
printf("Would you like to sum another number? (y/n): ");
if (scanf("%63s", another) != 1) {
fprintf(stderr, "Invalid input or read error.\n");
return 1;
}
working = (another[0] == 'y' || another[0] == 'Y');
}
}
As an addendum, perhaps you were trying to read a single character?
Character constants are denoted by their enclosing single quotes (e.g., 'A'), and can be compared with the == operator.
The scanf format specifier for a single character is "%c". To skip leading white space (e.g., a line feed), you can add a space before the format specifier: " %c". The address of your char is given to scanf with the address-of operator (&).
char ch;
if (scanf(" %c", &ch) != 1)
/* failure */;
else if (ch == 'a' || ch == 'b')
/* do something */;

C programming function calling to return values

I'm a college student in my first year of software engineering. I am in the fourth week of my semester and am having trouble in my programming class. Currently, I was given this assignment in which I was given a function called "getNum()" and I had to use it in another function where the program user, would input a number and the function that I program (must be named isOdd()) would determine if the number is odd or even. Then the main function would print whether the number is odd or even. This is the way that my professor worded it:
" Write a program that uses the getNum() function provided to you in Assignment 2 to get anumber from the user (prompting them first, as always). Create and use a function called isOddwith parameters (the number) and return values (1 ifthe number is odd, 0 if the number is evenOR use a bool or boolean data type, your choice) to determine if thenumber is odd. In main(), tell the user (by displaying using printf()or cout) whether the number is evenor odd."
Now, the problem I am having is understanding programming as I am fairly new to it and some words confuse me, such as parameter and return value. To give you and idea of what I have written so far,
#include <stdio.h>
int isOdd(int numInput);
int getNum(void);
int main(void)
{
int number = 0;
while (number > -1)
{
if (isOdd(0))
{
printf("The number is even.\n");
}
else if (isOdd(1))
{
printf("The number is odd.\n");
}
}
return 0;
}
int isOdd(int numInput)
{
int myNumber = 0;
printf("Please enter a number: ", numInput);
myNumber = getNum();
if (myNumber % 2 == 0)
{
myNumber == 0;
}
else
{
myNumber == 1;
}
return myNumber;
}
#pragma warning(disable: 4996)
int getNum(void)
{
/* the array is 121 bytes in size; we'll see in a later lecture how we can improve this code */
char record[121] = { 0 }; /* record stores the string */
int number = 0;
/* NOTE to student: indent and brace this function consistent with your others */
/* use fgets() to get a string from the keyboard */
fgets(record, 121, stdin);
/* extract the number from the string; sscanf() returns a number
* corresponding with the number of items it found in the string */
if (sscanf(record, "%d", &number) != 1)
{
/* if the user did not enter a number recognizable by
* the system, set number to -1 */
number = -1;
}
return number;
}
This is what I have written, trying to do things accordingly to my professor's instructions, as I do not yet know how to properly use booleans. As you can see, at the bottom is the getNum() function that my professor has said is mandatory for this assignment. As of now, everything I input, I am told is even. I am not asking for you guys to solve and do everything for me but I want to understand what I am doing wrong, what my thinking is doing wrong and to overall better my understanding for future programming. Thank you
It's hard to help you without knowing why you did what you did. A lot of the code is just baffling:
if (isOdd(0))
Why are you passing a zero to isOdd?
printf("Please enter a number: ", numInput);
myNumber = getNum();
Is numInput supposed to be the number they enter or is myNumber supposed to be?
if (myNumber % 2 == 0)
{
myNumber == 0;
}
The statement myNumber == 0 compares myNumber to zero to see if they're equal. It does nothing useful here since you ignore the result of the comparison.
The function:
int getNum(void)
Takes no parameters (void), and returns an integer (int) value. The function itself accepts input from the standard input (stdin) stream - this is normally from the keyboard.
To complete your assignment you should write a function:
int isOdd( int value ) ;
Where value is an integer parameter and the return value is 1 if value is odd and 0 if it is even. Alternatively you are allowed to use the Boolean type:
#include "bool.h"
bool isOdd( int value ) ;
In which case you would return true for odd, and false for even.
Your isOdd() includes the getNumber() call and user prompt code. Not only is that not specified in the assignment, it is poor design making isOdd() difficult to use in more general situations. The assignment explicitly requires you to pass the value to be tested as a parameter.
The assignment does not require you to iterate the test (the while loop is not needed). The user input prompt and acceptance should be in main as follows:
int main(void)
{
printf( "Please enter a number: " ) ;
fflush( stdin ) ; // you'll may this on some platforms
int myNumber = getNum();
if( isOdd( myNumber ) )
{
printf("The number is odd.\n");
}
else
{
printf("The number is even.\n");
}
}
return 0;
}
Note that there are only two possible outcomes, so you do not need an else if( !isOdd( myNumber ) ... - if it is not odd it is implicitly even.
Your isOdd() function will work, but is over complicated. You are required to return a Boolean (a type with two possible values true/false - or an integer 1/0 which can be implicitly converted to a Boolean), and (myNumber % 2 == 0) is a Boolean expression (an expression with two possible results true or false). Anywhere you see the pattern:
if( <boolean expression> )
{
b = true ;
}
else
{
b = false ;
}
you can simply write:
b = <boolean expression> ;
In your case the Boolean determination of odd-ness is simply value % 2 != 0. You can return that directly:
bool isOdd( int value )
{
return value % 2 != 0 ;
}

Print output just beside the user input

According to the question, The user needs to enter the no of hours the vehicle is parked and the total charge for the hours should get printed beside it.
for example:
I created this simple program
#include<stdio.h>>
#include<math.h>
float calculateCharges(float hurs);
int main()
{
float hours;//total no of hours vehicle is parked
int i;
printf("%s%10s%10s", "Car", "Hours", "Charges");
for (i = 1; i <= 3; i++)
{
printf("\n%d\t", i);
scanf("%f", &hours);
printf("\t%f\n", calculateCharges(hours));
}
getch();
return 0;
}
float calculateCharges(float hurs)
{
float charges;
hurs = ceil(hurs);
if (hurs >= 24) charges = 10;
else
{
if (hurs <= 3) charges = 2;
else
{
hurs = hurs - 3;
charges = 2 + 0.5*hurs;
}
}
return charges;
}
But now every time I enter hours the charges are getting printed below it instead of beside it. As shown in the image:
Is there is a way to consume the newline after scanf? So that charges can be printed beside the scanf?
I have modified my code this way too, but it didn't make any difference.
printf("%s%10s%10s", "Car", "Hours", "Charges");
for (i = 1; i <= 3; i++)
{
printf("\n%d\t", i);
printf("\t%f\n",(scanf("%f", &hours),calculateCharges(hours)));
}
Let me know if the original question is required. I'm using Visual studio 2017 RC.
You can use something like this:
#include <iostream>
#include <windows.h>
//This will set the position of the cursor
void gotoXY(int x, int y) {
//Initialize the coordinates
COORD coord = {x, y};
//Set the position
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord);
return;
}
void getCursorXY(int &x, int&y) {
CONSOLE_SCREEN_BUFFER_INFO csbi;
if(GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi)) {
x = csbi.dwCursorPosition.X;
y = csbi.dwCursorPosition.Y;
}
}
I found it here.
As already written in one of the answers this solution is not platform independent.
But i guess there are similar solutions on other platforms and you can easy set the cursor on the position you want.
Example usage in your main:
for (i = 1; i <= 3; i++)
{
printf("\n%d\t", i);
scanf("%f", &hours);
gotoXY( 20, i + 1);
printf("\t%f\n", calculateCharges(hours));
}
Workarounds for scanf can be found here.
scanf_s always generates a new line upon enter and unfortunately other user input capturing platform independent functions I know of (getc & getchar) do so too. Anyway on Windows it could be done using _getch() from conio header.
#include <conio.h>
#include <stdlib.h>
#include <stdio.h>
int getIntFromUser()
{
char readCharacters[10];
int index = 0;
for (int currentChar = _getch(); currentChar != '\r'; currentChar = _getch())
{
if (currentChar == EOF)
{
// Some error that shouldn't occour in your simple homework program
}
if (index > 9)
{
// Another possible error case where you would start to write beyond 'readCharacters' array
}
// We might as well disallow anything but digits, enter & backspace (You don't need anything else, do you?)
if ((currentChar < '0' || currentChar > '9') && currentChar != '\b')
{
continue;
}
else if (currentChar == '\b')
{
if (index > 0)
{
// Delete last character
printf("\b \b");
readCharacters[index] = '\0';
--index;
}
}
else
{
printf("%c", currentChar);
readCharacters[index] = currentChar;
++index;
}
}
if (index == 0)
{
// User pressed enter without having entered a number, let's give him a zero then
return 0;
}
readCharacters[index] = '\0';
int retVal = atoi(readCharacters);
// Worth noting that the value of converted user given string shouldn't be greater than what a signed int can hold
return retVal;
}
int main(int argc, char* argv[])
{
// Unlike scanf_s this will not generate a new line on enter
printf("getIntFromUser() sample (enter a number)\n");
int someValue = getIntFromUser();
printf(" -- This will be printed on the same line. (someValue is %d)\n\n", someValue);
// scanf_s sample
int anotherValue;
printf("scanf_s() sample (Insert a number.)\n");
scanf_s("%d", &anotherValue);
printf("This will be printed on a new line\n\n");
printf("Press any key to exit.");
_getch();
return 0;
}
EDIT
I feel like the above would become less readable if I were to add a comment over every code line. Instead I'm going to paste some blocks of code 1 by 1.
But first about the _getch function: It waits for the user to type something into the console and then returns the user given char as an int. char implicitly converts to int, so you may compare the _getch result to a character as I did many times in getIntFromUser (e.g. if (currentChar == '\b') { ... }).
You should also know about the values a char can hold and what their values are as an int (check out http://en.cppreference.com/w/cpp/language/ascii).
Going by the table the char '0' would be value 48 as an int, which is what _getch would return if the user were to type a 0.
First declare an array/string of 10 elements. Hope you know about them already. In this case the array is basically a chain of 10 elements that are all of type char, which are also referred to as string.
char readCharacters[10];
An indexer for the string is required.
int index = 0;
Below we have the usual for loop that...
1st: creates a variable of type int and assigns the result of _getch to it.
2nd: will determine if the loop shall keep executing. In this case the loop will break when currentChar is not '\r', which is an escape sequence that represents enter as a character.
3rd: will execute stuff inside once and then update currentChar with a new _getch.
for (int currentChar = _getch(); currentChar != '\r'; currentChar = _getch())
Checks if the user input (retrieved via _getch) is smaller than '0' (value 48 as an int) and greater than '9' (value 57 as an int). If either of them is true it will additionally check if the value of currentChar is not '\b' (value 8 as an int), which is the escape sequence for a backslash.
When that additional check evaluated to true as well then the keyword continue is used. Meaning that the rest of the block in the loop is not executed and instead the loop will start at the top again by getting a new user input and evaluating if the loop is to be continued by checking if obtained currentChar was enter.
if ((currentChar < '0' || currentChar > '9') && currentChar != '\b')
{
continue;
}
NOTE: You might want to read the comments on the else statement before you read these.
When the above if statement was false we get to the next if-statement (actually else if) that we see below.
As mentioned above: '\b' is backslash and if this is the user given char as well as string/array index being greater than 0 we move one character backwards in the console by "printing" '\b' and then write an empty character in order to delete what was written at that place previously. That puts us back to the position we were before so we print another backslash. At this point you might wonder why not just go back to the previous line that scanf_s causes, but that won't work. We must also not forget to replace the last string character with a null terminator and then set the index back by 1.
else if (currentChar == '\b')
{
if (index > 0)
{
// Delete last character
printf("\b \b");
readCharacters[index] = '\0';
--index;
}
}
When we hit this point we know that currentChar is something between 48 and 57 ('0' and '9').
_getch told the program what the user's input was, but we cannot see it in the console unless we print it there. So let's do that.
Also append the user's given character to the string as well as incrementing the index by 1.
else
{
printf("%c", currentChar);
readCharacters[index] = currentChar;
++index;
}
Lastly we call the atoi function that will convert our string/array to an integer.
int retVal = atoi(readCharacters);

How to allow user to exit while loop from terminal?

For example, if I want to write a code to average an unspecified number of numbers that the user enters, how can I make it so that the user can determine the number of numbers? ie. if the user wants to average just three numbers, he types them in one at a time, and then types in something to signal that this is it.
I wrote something like
while(i!=EOF){
printf("type in a number: \n");
scanf("%f",&i);
array[x]=i;
x++;
}
"and then some code to average the numbers in the array".
The idea was that if the user wants to signal that he finished entering numbers, he types in EOF and then the while loop will stop, however this isn't working. When I type in EOF at the terminal, it just writes "type in a number:" indefinitely.
scanf returns information in two different ways: in the variable i, and as its return value. The content of the variable i is the number that scanf reads, if it is able to return a number. The return value from scanf indicates whether it was able to read a number.
Your test i != EOF is fundamentally a type error: you're comparing the error indicator value EOF to a variable designed to hold a floating-point number. The compiler doesn't complain because that is accidentally valid C code: EOF is encoded as an integer value, and that value is converted to a floating-point value to perform the comparison. In fact, you'll notice that if you enter -1 at the prompt, the loop will terminate. -1 is the value of the EOF constant (on most implementations).
You should store the return value of scanf, and store it into a separate variable. If the return value is EOF, terminate the loop. If the return value is 1, you have successfully read a floating-point value.
If the return value is 0, the user typed something that couldn't be parsed. You need to handle this case appropriately: if you do nothing, the user's input is not discarded and your program will loop forever. Two choices that make sense are to discard one character, or the whole line (I'll do the latter).
double i;
double array[42];
int x = 0;
int r = 0;
while (r != EOF) {
printf("type in a number: \n");
r = scanf("%f", &i);
if (r == 1) {
/* Read a number successfully */
array[x] = i;
x++;
} else if (r == 0) {
printf("Invalid number, try again.\n");
scanf("%*[^\n]"); /* Discard all characters until the next newline */
}
}
You should also check that x doesn't overflow the bounds of the array. I am leaving this as an exercise.
I want to do it by typing in something that's not a number
Then get the input as a string, and exit if it cannot be converted to a number.
char buf[0x80];
do {
fgets(buf, sizeof(buf), stdin);
if (isdigit(buf[0])) {
array[x++] = strtod(buf);
}
} while(isdigit(buf[0]);
In case of no input scanf() does not set i to EOF but rather can return EOF. So you should analyze scanf() return code. By the way you can receive 0 as result which actually means there is no EOF but number cannot be read.
Here is example for you:
#include <stdio.h>
#define MAX_SIZE 5
int main()
{
int array[MAX_SIZE];
int x = 0;
int r = 0;
while (x < MAX_SIZE)
{
int i = 0;
printf("type in a number: \n");
r = scanf("%d",&i);
if (r == 0)
{
printf("ERROR!\n");
break;
}
if (r == EOF)
{
printf("EOF!\n");
break;
}
array[x]=i;
x++;
}
}
You cannot write 'EOF'.. since you are reading into a number...
EOF equals -1.. so if he enterd that, the loop would stop
You can test for the return value of the scanf function. It returns EOF on matching failure or encountering an EOF character.
printf("type in a number:" \n);
while(scanf("%f",&i)!=EOF){
array[x]=i;
x++;
printf("type in a number:" \n);
}

How do I force user to input a positive integer?

Force user to input a positive integer and put user in a loop till they do.
So I want everything including characters not allowed just over > 0
I tried the following:
while (i < 0) do {
printf("please input a number that's positive");
scanf("%d", i);
}
For positive integer use the following code
int i;
do
{
printf("please input a number that's positive");
scanf("%d", &i);
}while (i < 0);
The c language provides no error checking for user input. The user is expected to enter the correct data type. For instance, if a user entered a character when an integer value was expected, the program may enter an infinite loop or abort abnormally.
Both of these while functions manage the numbers, the int k is the set integer which can only be set below 20, the first while loop makes a statement that calls for another scan if the number is greater than 20
and the second loop prints a k*k box.
Hope this helps.
int main ( )
{
int i, j,k;
printf("Please enter Box size:\n\n");
scanf("%d",&k);
while(k>20){
printf("Please enter a value below 20\n\n");
scanf("%d"),&k;
}
while(k<=20)
{
for (i = 0; i < k; i++)
{
printf("\n");
for (j = 0; j < k; j++)
{
printf("#");
}
}
return 0;
}
}
I would do this: declare char term and int wrong = 0.
do {
printf("Enter a number: ");
fflush(stdin);
if (scanf("%d%c", &n, &term) != 2 || term != '\n' || n <= 0) {
printf("Only positive numbers.\n");
wrong = 1;
}
else {
wrong = 0;
//do something here if correct;
}
} while (wrong);
The code above detects invalid input if the user entered a mixture of characters and numbers, or negative numbers (and zero).
However, it doesn't detect if the user entered trailing zeros in front followed by valid digits eg. 001or 00000738. If anyone else could figure this out, please share below. Thanks! :)
Here is another alternative of a function which takes in a char str[20] (of say, maybe 20 elements), analyses the string to check for positive integers, and returns a 0 or 1 accordingly. Lastly, convert that string to an integer using atoi().
int checkPositiveIntegers(char str[]) {
char *ptr = str;
if (*ptr == '-' || *ptr == '0') //checks for negative numbers or zero
return 1;
else {
do {
if (isdigit(*ptr) == 0) { //checks for non-digit at ptr location; isdigit() returns 0 if non-digit
return 1;
break;
}
ptr++;
} while (*ptr != '\0' && *ptr != '\n');
return 0; //returns 0 if positive integer
}
}
So the function only accepts positive numbers from 1 to 9,999,999,999,999,999,999 (up to 19 digits if char str[] holds 20 elements).
However, if you converted the string back to int n = atoi(str);, the maximum value it could reach would be 2,147,483,647 since n is declared as a signed integer. Play around with different datatypes for exploration.
Hope this helps! :)

Resources