Integer and Decimal related - c

This is the part of my program I am stuck on. When I enter say 5.5 my program will run twice, however I want it to read as 5.5 not 5 then 5 again. I understand I need to add %f (hence added a float input), however, I'm not sure how I will implement it after I do a scanf for char. I only want the program to accept integer so it cannot accept 5.5 as a value. It is in a do-while loop. Any help would be greatly appreciated, please explain thoroughly because I am still kind of new to programming.
int amount;
float input;
do{
printf("\nPlease enter integer:");
if(scanf("%d", &amount)!= 1){
//if reads a character or symbol asks to try again
printf("\nEnter numbers only!\n");
getchar();
}
...

Using scanf with an integer format (%d) and then feeding non integer values is a recipe for disaster (or at least your program not working).
Either use scanf and only type integers or read strings and convert the strings to integers.
do {
char* line = NULL;
size_t sz = 0;
printf("\nPlease enter integer:");
getline(&line, &sz, stdin);
if (line == NULL) {
// TODO error handling
// Can also check the getline() -1 is an error.
} else {
// atoi returns 0 on error, so if 0 is a valid value you'll
// need special case handling to determine if you've got a
// "valid" 0 or not.
amount = atoi(line);
free(line);
}

Related

Validate integer against chars

I'm trying to make a program where the user inputs value to an array. What is actually required is that the program should validate against a char character. So if the user inputs a random char such as 'n' the program should tell him "You introduced a char, please input an integer: ".
How is that possible to make that without using a char variable?
for (i = 1; i <= size; i++) {
printf("Introduce the value #%d of the list: ", i);
scanf("%d", &list[i]);
if () { // I'm blocked right in this line of code.
printf("What you tried to introduce is a char, please input an integer: ");
scanf("%d", &list[i]);
}
Thanks in advance.
As #MFisherKDX says, check the return value of scanf. From the scanf man page:
These functions return the number of input items successfully matched
and assigned, which can be fewer than provided for, or even zero in
the event of an early matching failure.
The value EOF is returned if the end of input is reached before either
the first successful conversion or a matching failure occurs. EOF is
also returned if a read error occurs, in which case the error
indicator for the stream (see ferror(3)) is set, and errno is set
indicate the error.
So capturing the return value of scanf in an int variable and then comparing that variable to 1 (in your case, because you are only attempting to read 1 item) should tell you if scanf successfully read an integer value.
However, there is a nasty pitfall when using scanf that you should be aware of. If you do type n at the prompt, scanf will fail and return 0, but it will also not consume the input you typed. Which means that the next time you call scanf, it will read the same input (the n character you typed), and fail again. And it will keep doing so no matter how many times you call scanf. It always amazes me that computer science educators continue to teach scanf to students, given not only this potential pitfall, but several other pitfalls as well. I wish I had a nickel for every hour that some CS student somewhere has spent struggling to get scanf to behave the way their intuition tells them it should. I'd be retired on my own private island by now. But I digress.
One way around this particular pitfall is to check if scanf failed, and if so, to purposely consume and discard all input from stdin up to and including the next newline character or EOF, whichever comes first.
First let's look at some unfixed code that causes an infinite loop if you enter a non-integer as input:
// Typing the letter 'n' and hitting <Enter> here causes an infinite loop:
int num, status;
while (1) {
printf("Enter a number: ");
status = scanf("%d", &num);
if (status == 1)
printf("OK\n");
else
printf("Invalid number\n");
}
The above code will (after you type n and hit <Enter>), will enter an infinite loop, and just start spewing "Invalid number" over and over. Again, this is because the n you entered never gets cleared out of the input buffer.
There are a few possible ways to get around this problem, but the consensus seems to be that the most portable and reliable way to do so is as follows:
// Fixed. No more infinite loop.
int num, status;
while (1) {
printf("Enter a number: ");
status = scanf("%d", &num);
if (status == 1)
printf("OK\n");
else {
printf("Invalid number\n");
// Consume the bad input, so it doesn't keep getting re-read by scanf
int ch;
while ((ch = getchar()) != '\n' && ch != EOF) ;
if (ch == EOF) break;
}
}
The function scanf() will returns the number of elements read, so in this case it will return 1 every time it reads an int and 0 when it reads a char, so you just need to verify that return value.
Keep in mind that after reading a character it will remain in the buffer so if you use the scanf() command again it will read the character again and repeat the error. To avoid that you need to consume the character with while(getchar() != '\n');
With that in mind I modified your code so that it works properly printing an error message if a character is introduced and asking for a new int.
for (int i = 1; i <= size; i++) {
printf("Introduce the value #%d of the list: ", i);
while (!scanf("%d", &list[i])) { //verifies the return of scanf
while(getchar() != '\n'); //consumes the character in case of error
printf("What you tried to introduce is a char\n");
printf("please introduce the value #%d of the list: ", i);
}
}

Validation of integer inout and in general

How would I validate that the user enters a correct input, e.g. for an integer, since I am declaring the variables as ints before. (Meaning alpha would get numerical inputs.)
Also, is there a more general way of validating inputs and getting inputs; other than using scanf?
#include <stdio.h>
int main() {
printf("We will check if your number is odd, even, zero or negative \n");
int input;
printf("Enter your number: \n");
scanf("%d", &input);
if (input < 0){
printf("Number is Negative \n");
}
else if (input == 0){
printf("Number is Zero \n");
}
else if (input % 2 == 0){
printf("Number is Even \n");
}
else if (input % 2 == 1){
printf("Number is Odd \n");
}
return 0;
}
Using the scanf() family implies that the input is expected in perfect syntax for the conversion specifier given (in this case "%d" -> integer).
If you instead want to verify that correctness of the syntax of the input, then you need to take the input as a whole and then parse it yourself.
You can use e.g. fgets() (https://en.cppreference.com/w/c/io/fgets) to do so.
Once you have the input saved in a "string" (chars in an array or allocated memory), you can start "guessing" at what it is, using multiple sscanf() (https://en.cppreference.com/w/c/io/fscanf). This is much easier on a string which is already in memory than on the input stream. Because "wrong guess after partial success, try again from start" is easy in memory but hard on input.
As SomeProgrammerDude has already commented, the way to attempt scanning with sscanf() (in memory, or scanf() on input) is to check the return value; it will tell you about success or failure.

Having Difficulty with isdigit() in C

I have been trying to add some experience in C to my experience with Python and started with a basic addition program. One thing that I'm trying to do is check if the input is a number or a character as seen here:
#include <stdio.h>
#include <ctype.h>
int main()
{
int n, sum=0,c,value;
printf("Enter the Number of Integers You Want to Add\n");
scanf("%d", &n);
if(isdigit(n))
{
printf("Enter %d Integers\n", n);
for(c=1; c<=n; c++)
{
scanf("%d", &value);
if(isalpha(value))
{
printf("ENTER INTEGER NOT CHARACTER\n");
break;
}
else
{
sum = sum + value;
}
}
printf("Sum of Entered Integers = %d\n",sum);
}
else
{
printf("ENTER INTEGER NOT CHARACTER\n");
break;
}
return 0;
}
Initially I had tried this using isalpha(), and the program worked fine when adding numbers but interpreted characters as zeros instead of printing the "not an integer" statement. However, now that I reworked it to use isdigit(), it does not recognize ANY input as an integer, whether or not it is. Is there something that I'm just doing wrong?
When you use scanf to read an integer, you get just that, an integer. (To read a single character, you need %c and a pointer-to-char).
When you use isdigit(), you need to supply the representation of that character (e.g. in ASCII, the character '0' has the representation 48, which is indeed its value as an integer). To recap:
isdigit(0) is false
isdigit(48) is true (for ASCII, ISO8859, UTF-8)
isdigit('0') is true (no matter the character set)
isdigit('0' + n) is true for integers n = 0 ... 9
PS: Not testing the return value from scanf is asking for trouble...
Neither isdigit nor isalpha work as you think they do. The intent of those library functions is to check whether a given code point, represented as an int, is within a subset of points defined by the standard to be digit characters or alpha characters.
You should be checking the results of your scanf calls rather than assuming they just work, and acting on those results accordingly. If you request an integer and one is successfully scanned, then it will tell you so. If that fails, your course of action is probably to consume the rest of the line (through newline or EOF) and possibly try again:
#include <stdio.h>
int main()
{
int n,value,sum=0;
printf("Enter the Number of Integers You Want to Add\n");
if (scanf("%d", &n) == 1 && n > 0)
{
printf("Enter %d Integers\n", n);
while (n--)
{
if (scanf("%d", &value) == 1)
{
sum = sum + value;
}
else
{
// consume the rest of the line. if not EOF, we
// loop around and try again, otherwise break.
while ((value = fgetc(stdin)) != EOF && value != '\n');
if (value == EOF)
break;
++n;
}
}
printf("Sum of Entered Integers = %d\n", sum);
}
return 0;
}
Properly done you should be able to enter valid integers beyond single digits (i.e. values > 10 or < 0), which the above allows.
The %d marker to scanf tells it to interpret the input as a number (more accurately, it indicates that the pointer in the arguments points to an integer type). It can't do anything but put an integer into that argument. If it can't interpret the input as a number, scanf stops scanning the input and returns immediately.
isdigit() evaluates its argument as a character code, as Jens points out above. However, scanf already turned the character code into a pure number.
From the scanf man page:
On success, the function returns the number of items of the argument list
successfully filled.
In your program, you are trying to read just one item from stdin, so scanf should return 1. So check for that and you'll know that it all worked out ok:
printf("Enter the Number of Integers You Want to Add\n");
while(scanf("%d", &n) != 1) {
printf("That's not a valid integer. Please try again.\n");
}
You cannot use isdigit() the way you are using it because you're already using scanf to convert the user input to an integer. If the user had not input an integer, scanf would have already failed.
Look at the man pages for all the C functions you are using, they will show you what the function expects and what the return values will be under different circumstances.
In the case of isdigit(), the input is expected to be an unsigned char representing an ASCII character. This can be a bit confusing because ASCII characters are in fact represented as a type of integer, and a string is an array of those. Unlike languages like Python which hide all that from you. But there is a big difference between the STRING of a number (array of characters that contain the characters of the digits of the number) and the INTEGER itself which is in a form the processor actually uses to do math with... (simplified explanation, but you get the idea).

How do I avoid deadloop if a user enters a char into a scanf looking for an interger?

I've been searching the web for a while now, without finding a satisfying answer. Now I'll try my luck here. So here it goes:
In my program I want a user to enter a number, via the terminal, for this I use scanf(). Rather simple, I know... and I've got that working. But I also want to make it "idiot-proof". Thus I'm trying to make sure that if the user enteres a character and not an interger, the program won't deadloop.
As it is now, if a character is entered the program will deadloop.
My code is:
long fs = 0;
printf("Enter the samplefrequency(in Hz) and press 'ENTER': ");
while(fs<=0)
{
scanf(" %li", &fs);
if(fs <= 0)
{
printf("\nThe samplefrequency must be above 0 Hz. Please enter again: ");
}
}
This will keep printing the line in the if-statement.
How do I avoid this?
The only way to make user input from the console completely idiot-proof is this:
Do not use scanf.
Read the input as a string, using fgets. Do not read it as an integer.
Parse this string and see if it contains a valid number.
Convert the string to an integer by using strtol().
change it like this:
scanf(" %li", &fs);
while(fs <= 0)
{
printf("\nThe samplefrequency must be above 0 Hz. Please enter again: ");
scanf(" %li", &fs);
}
When you input a wrong number the loop will continue to prompt for a new number until it is correct.
Here's a sample that demonstrates how to use fgets with sscanf to solve the user input problem.
The function getInputFromUser displays prompt1, and then uses fgets to read a line of input from the user. (If fgets returns NULL, that indicates end-of-file from the user, and the program aborts.)
The function then uses sscanf to convert the input to a number. sscanf returns the number of successful conversions, so in this example a return value of 1 indicates that sscanf succeeded. (Additional range checking can be performed after the sscanf to make sure the number is acceptable.) If the sscanf fails, then the second prompt (prompt2) is displayed and the function tries again.
If and when the user gets around to entering a valid number, the function will return that value.
long getInputFromUser(char *prompt1, char *prompt2)
{
long result = 0;
char line[100];
printf("%s", prompt1);
for (;;)
{
if (fgets(line, sizeof(line), stdin) == NULL)
{
// user hit the EOF key
printf( "\nterminated by user...\n" );
exit(1);
}
if (sscanf( line, "%ld", &result) == 1 && result > 0)
break;
printf("%s", prompt2);
}
return result;
}
Call the function with the initial prompt, and the re-prompt for the user
long fs = getInputFromUser("Enter the samplefrequency(in Hz) and press 'ENTER': ",
"The samplefrequency must be above 0 Hz. Please enter again: ");

How to ensure user-input data is an integer

I am new to C, but I know C#. In C#, I could use TryParse to ensure that the user typed in the correct datatype.
Here is the basic code I have for C:
int shallowDepth;
do
{
printf ("\nEnter a depth for the shallow end between 2-5 feet: ");
scanf ("%d", &shallowDepth);
if (shallowDepth < 2 || shallowDepth > 5)
{
printf("\nThe depth of the shallow end must be between 2-5 feet.");
}
}
while (shallowDepth < 2 || shallowDepth > 5);
The problem is if I type characters, such as "asdf", the program goes crazy and repeatedly says "Enter a depth for the shallow end between 2-5 feet: ". I'm not sure why this is exactly happening, but it has to be because it expects an int and I'm passing characters.
So how do I verify that the user inputted data is of int type before trying to store it in a variable? Thanks.
This is happening because with %d scanf will refuse to touch anything that does not look like a number and leaves the text in the buffer. The next time around it will again reach the same text and so on.
I recommend that you ditch scanf for now and try something like fgets and then one of the functions in the strtoXXX family such as strtoul or strtoumax. These functions have a well-defined way of reporting errors and you can easily prompt the user for more text.
For example you could do:
char str[LENGTH];
long x;
if (!fgets(str, sizeof str, stdin)) {
/* Early EOF or error. Either way, bail. */
}
x = strtol(line, NULL, 10);
At this point you could use your number, but be aware that:
You can specify a pointer for strtol to fill and it will point to the first unacceptable character
If the result cannot be represented as a long then strtol will set errno = ERANGE. If you plan to test for this you must set errno = 0 before the strtol
If you want to use scanf you can't test it before. But you don't need too!
In your code if the user doesn't enter a number (or something that starts with a number), scanf returns 0, because it returns the number of parameters it could read.
So you need to check the return value of scanf to check if anything could be read.
Second, you need to remove everything that's still in the puffer.
You can use something like this for that:
while(getchar()!='\n');
If you want to handle files as well, you should catch EOF there, too.
int shallowDepth;
int invalid;
do {
int stat;
invalid = 0;
printf ("\nEnter a depth for the shallow end between 2-5 feet: ");
stat = scanf ("%d", &shallowDepth);
if(stat != 1){
invalid = 1;
while(getchar() != '\n');//clear stdin
} else if (shallowDepth < 2 || shallowDepth > 5){
invalid = 1;
printf("\nThe depth of the shallow end must be between 2-5 feet.");
}
}while (invalid);

Resources