Issues with using scanf inside a while loop - c

I’m brand new to programming. I ‘m working on a homework assignment in order to help us understand scanf and arrays. The program is supposed to ask the user to input an unknown set of numbers. Each set of numbers should be separated by a space like below without hitting enter.
14 15 16
The user can also input numbers on a separate line instead using spaces, but again on the last number inputed the user isn’t supposed to hit enter.
12 13
44 55
5
The user should hit ctrl-d to indicate end of input. The program should display the number of elements entered by the user, along with displaying the numbers the user entered. I have been reading around and think I have a basic concept of how scanf works, but I am still having some difficulty. The code kind of works. However, if the user just enters the numbers on one line they need to hit ctrl-d three times in order for it to exit the loop and display the information.
From what I have found online and understand, I think it’s not working because the user hasn’t hit return, so the input hasn’t been flushed into the stdin. So if I'm understanding correctly, the first time I hit ctrl-d it while flush the input. Then the second time I hit ctrl-d it will finally put the EOF into the stream and the third time it will finally read the -1 produced by the EOF and exit the loop.
Is there anyway to force the input stream once ctrl-d is entered.
#include <stdio.h>
int main()
{
int numbers[20];
int i = 0, count, result, n;
int flag = 0;
printf("Please enter a seiries of numbers:\n");
while (flag == 0)
{
result = scanf("%d", &n); //scan user input into n variable along with getting scanf return value and storing in result variable
printf("result =%i \n", result); //Just printing scanf return value to insure it doing what I think it should be doing
if (result == 1)
{
numbers[i] = n; //if scanf return value is 1 places value of n into first element of array
i++; //used to increment my array
flag = 0;//keeps value of flag equal to 0 in order to stay in loop
}
if(result == -1) //checks to see if result = to -1 should be value returned if cntl +d is entered
{
flag = 1; //sets flag to 1 when cntrl +d is entered in order to exit loop.
}
}
for (count = 0 ; count < i ; count++) //loop to print I which is representing number of user inputs and the actual numbers entered by the user.
{
printf("\ni= %i numbers= %i\n", i, numbers[count]);
}
return 0;
}

I won't give you a solution directly, but will try to help you improve coding in C. The more you work with C the more you will find out that one can write pretty compact code, once the language is mastered.
You can omit flag because it depends on result.
And you could omit result because it is just the return value of scanf.
You can omit n and use numbers array directly.
And you could make use of the preprocessor to use a constant number (often for array sizes as in your case).
Have a look at this. Maybe it helps you get an idea:
#include <stdio.h>
#define COUNT 20
main() {
int numbers[COUNT];
int i;
i = 0;
while (scanf("%d", &numbers[i]) == 1 && i < COUNT)
printf("\t%d\n", numbers[i++]);
return 0;
}
P.S.:
I recommend getting acquainted with the different ways of accessing an array and reading about pointers. The have a very close relationship really.
Address of first element in array : numbers
Access ith element of array : numbers[i]
Equivalently : *(numbers + i)
Another equivalence : *(i+numbers)
Surprise, but equivalent again : i[numbers]
Address of ith element of array : &numbers[i]
K&R is a great resource of information and learning.

Related

Are there better ways to clear stdin when looking for a specific kind of input in C?

fairly new programmer here just trying to understand if there is a better way to do this and hoping to get some feedback.
TL;DR: Is there a better way to clear stdin when looking for a specific input?
For some background, I've been learning C for the past 3 weeks and scanf() has been our "go to" function for user input. After looking around for answers to this question, I'm beginning to learn that scanf() is not always preferred.
In this part of the assignment that I'm working on, I created this while loop that is supposed to run while the user input is a nonzero, positive integer. It took a while, but to get to this point I now understand that if a string is inputted instead of an integer when scanf("%d", &variable); is assigned while using leads to an infinite loop as stdin does not get cleared.
I tried to solve this problem by checking to see the return of the scanf() functions, and running the loop while the return is equal or less than 0 (which would mean that the scanf() function broke and did not return anything since it saw a char instead of an int).
The thing is, the code seems to work great until we encounter one scenario, which is where we have characters followed by an integer.
For example:
Input = 1
program runs with no issues
Input = string
program runs loop, asks for new valid input
Input = string string
program runs loop, asks for new valid input
Input = 123string
program proceeds, but then next loop with an int scanf() is infinite. 123 is stored as an int to variable.
My current understanding of the issue is that scanf() reads the integers until we get to the characters and then "string\n" gets stored to stdin, creating an infinite loop in the next part. To solve the issue, I added a fflush(stdin); before the next integer scanf() loop which seems to work.
So my question is: Would somebody be willing to show me some other ways to do this other than adding a fflush(stdin); line before every int scanf() loop? I'm sure there are better ways but I don't rightly know who to ask and the internet seemed like a good resource. Thank you.
#include <stdio.h>
#include <stdlib.h>
int main()
{
int squareLen = 0;
int numColors = 0;
int infiniteLoopStop;
// Asks for user input of desired Square Length
printf("Please enter the finished side length (in inches) of one square.\n> ");
while (squareLen < 1) {
infiniteLoopStop = scanf("%d", &squareLen);
if (infiniteLoopStop <= 0 || squareLen < 1) {
printf("\nInvalid input. Enter a nonzero, positive integer.\n> ");
fflush(stdin);
}
}
// Temporary solution to problem
fflush(stdin);
// Asks for int input of colors and loops while number of colors is not 2 or 3
printf("How many colors are you using? Enter 2 or 3.\n> ");
while (numColors < 2 || numColors > 3) {
infiniteLoopStop = scanf("%d", &numColors);
if (infiniteLoopStop <= 0 || numColors < 2 || numColors > 3) {
printf("Invalid, please enter 2 or 3.\n> ");
fflush(stdin);
}
}
printf("\n");
return 0;
}

Check if user input is between 1 and 10

part of the program that i am working on is to get a number from the user , but the condition is that it has to be any number between 1 and 10 nothing else, so how could i force the user to only input one of these specific numbers , so that if he wrote any other number or a character , an error message to pop out and repeat the process till he choses correctly
here is the code
// getting a number from the user
int number;
printf("Please pick a number from 1 to 10 : ");
scanf("%d",&number);
printf("Oh ! You have chosen %d\n", number);
// what should i do here ?
C allows for very nice input control, but it is not free... Said differently you cannot rely on the language nor on the standard library but have to code everything by hand.
What you want:
control that the input is numeric
control that the number lies between 1 and 10
How to:
control the return value of the input function
if you got a number control its value
if you got an incorrect input (optionaly) give a message and loop asking
Possible code:
int number;
for (;;) { // C idiomatic infinite loop
printf("Please pick a number from 1 to 10 : ");
if (scanf("%d", &number) != 1) {
// non numeric input: clear up to end of line
int c; // c must be int to compare to EOF...
while ((c = fgetc(stdin)) != EOF && (c != '\n'));
}
else if (number > 0 && number <= 10) break; // correct input: exit loop
// error message
printf("last input was incorrect\n");
}
printf("Oh ! You have chosen %d\n", number);
If you want a more user friendly way, you could use different messages for non numeric input and incorrect values, but it is left as an exercise for you... (I am afraid I am too lazy ;-) )
What you likely envision is a fine-grained control over the character-by-character input of the user; for example, anything but digits should be impossible; or when they type a 2 and try to type another digit, that should be impossible, too.
That's something we know from graphic user interfaces. It requires that your program is "informed" about every key stroke at once.
For historical reasons, this capability is not part of the C standard library. The reason is that historically all kinds of input devices were used, for example punch cards or paper-based teletypes. The communication was line by line: Input was local until the user hit the aptly named "enter" key. Any stupid device can do that, a lowest common denominator which is why all languages which do not define GUI elements adhere to it.
Obviously, character-by-character input is entirely possible on modern terminals and computers; but it is system specific and has never been standardized in the language. It is also likely more complicated than meets the eye if you want to give the user the opportunity to edit their input, a phase during which it may be "illegal". In the end you'll need to catch the point when they submit the entire value and validate it, which is something you can do even with the crude facilities that C provides.
Hints for an implementation:
Let the user complete a line of input. Validate it, and if the validation fails, prompt for another attempt. Do that in a loop until the input is valid.
Use scanf because it is convenient and error free (compared to home-grown input parsing).
This is something often overlooked by beginners: Check the return value of scanf which will indicate whether the input could be parsed (read the scanf manual!).
int main()
{
int number = 0;
while (number < 1 || number > 10)
{
printf("please enter number between 1 - 10\n");
scanf("%d", &number);
if (number < 1 || number > 10)
{
printf("you entered invalid number!\n");
}
}
return 0;
}
while(1)
{
//input ....
if(number<0 || number>10)
{
// print error
continue;
} else {
while (getchar() != '\n') ;
break;
}
}
I think I made a mistake at the beginning.A character can be checked by if but scanf can't. If scanf can't get the input in the specified format, the illegal input in the input buffer will be kept all the time.
After looking at another question, I thought that when the input is wrong, we should use getchar() to clear the buffer before the next input.

Isdigit() not working for values in range of 48- 58 in C

I am trying to create program which checks if input from user is a number. This works fine for all of the number and charatcers entered, except for numbers in range of 48 to 57. I've been looking through StackOverflow forum and could not find the answer. Could you please advise, what I am doing wrong?
Here is my code:
#include<stdio.h>
#include<stdlib.h>
#include<ctype.h>
int main(){
int tab[100];
int input;
int index = 0,count=0;
printf("Podaj liczby:\n");
do{
scanf("%i", &input);
if(!isdigit(input)){
if(input!=0){
tab[index] = (int)input;
index++;
}
}else{
printf("Incorrect input");
return 1;
}
}while(input!=0 && index<100);
if(index<2){
printf("not enough data available");
return 2;
}
for(int i = 0; i <index; i++){
count = 0;
for(int j = i+1;j< index; j++){
if((tab[i] == tab[j]) && tab[i]!=0) {
count++;
tab[j] = 0;
}
}
if(count>0){
printf("%i ",tab[i]);
}
}
return 0;
}
scanf("%i", &input);
scanf with the format %i converts its input to an integer. If the user presses 4 2 Enter, that makes the scanf call equivalent to input = 42.
If the input can't be converted to an integer, scanf returns EOF and doesn't set input. Since you don't check the return value of scanf, your program continues with an indeterminate value in input. (In theory that's undefined behavior, but in practice your program will run with whatever happened to be in the memory location of input.)
if(!isdigit(input)){
This tests whether the number input is the numerical code of a digit character. In practice, the correspondence between characters and their numerical codes on your computer is ASCII, so digits occupy the range from 48 to 57 inclusive. So the body of this if clause only runs if input is not between 48 and 57.
I have no idea why you'd do that. If you meant to check whether the input is valid, check the return value of scanf. If you thought you were checking the first character of the input, then 1. no you aren't, you're checking the result of the conversion, you can't access the raw input from the user; and 2. you'd only be checking one character anyway so your check couldn't possibly be correct.
The if(!isdigit(input)) clause is checking whether input is a digit, and it jumps to the else part if it is. So, if this was ever going to work, you would have to get rid of the '!' operator.
Which leaves us with the next problem: you are using scanf() to read ints. There is no more checking to be done to see whether an int is a number. An int is already a number.
But what you do, is that you treat the int as a char and pass it to isdigit(), which will of course only succeed if the char is between 0 and 9, which corresponds to int numbers between 48 and 57. So, only these numbers succeed, and then you negate the result of isdigit(), so you think that only these numbers fail.
Long story short: quit checking whether your numbers are numbers, they are already numbers.

Stop a for loop when user is finished entering input in c

First of all, thank you for the assist!
I'm new to the C language (and programming in general) and I'm trying to write a program wherein the user inputs data points. The data points are then saved in an array where they can then be manipulated.
Where I am stuck: I want the user to be able to input (almost) any number of points, then use a 'keyword' of sorts to signal the end of data entry. In this case, the user would type 'done'.
Here's what I have so far:
#include <stdio.h>
#include <string.h>
int main(void) {
printf("\n Welcome! \n\n Please enter each data point. Enter 'done' when finished.\n\n");
double data[1048];
int i, count;
for (i = 1; ;i++) {
printf("Data[%i]: ", i);
scanf("%lf", &data[i]);
if (data[i] == 'done') {
break;
} else {
count++;
}
}
}
I've tried 'return 1;' and 'break;'. Each time, the program works well until the 'keyword' is entered, at which point I get:
Data[8]: Data[9]: ... Data[1120]: Data[1Segmentation fault 11
The only time it works is if I have it break when the user inputs a particular number (like -1 or 0). But that doesn't quite work for the user since they might have to enter those numbers as data points.
Sorry for the long post, but I appreciate the help!
You have received a number of good answers to your question, and there are several more ways to take input of doubles and stop on "done". Since you are learning C, always, ALWAYS (in case it wasn't clear), check the return of scanf to validate the number of conversions you expected actually took place.[1] (this also provides your way to end input on "done" (or any non-double entered causing scanf to return less than 1)
As noted in the comment, arrays are zero based in C. When you are taking input, you will want to use count as your array-index, rather than i (in this case if you exit the read on each failure -- it doesn't matter, but you could just as easily prompt again for additional input and increment count only on a successful return from scanf) Back to your question. If you set up your read loop to continually loop until there is a scanf failure, you can make use of a temporary variable to initially capture the input value, and only assign the value to your array and increment your index on success. e.g. (with a constant MAXD = 1048)
for (;;) { /* loop until scanf input fails (with 'done') */
double tmp; /* block scope declarations are fine */
printf (" data[%4d]: ", count);
if (count < MAXD && scanf(" %lf", &tmp) == 1)
data[count++] = tmp;
else
break;
}
(you can even move a copy of the prompt above the loop, and move the one above after the if (....) {...} to eliminate the prompt when the array limit (MAXD) is reached -- that's left as an exercise)
In the example above you have 2 conditions you enforce before storing a value. (1) you limit the number of values your user can store to MAXD, and (2) you only store a value if a valid conversion to double takes place in scanf. You leave the loop if either of the conditions fails (which if you enter "done" as a double-value, it will).
Putting the pieces together and dropping a few additional tips in the comments, you could test with something like the following:
#include <stdio.h>
enum { MAXD = 1048 }; /* declare constants instead of using magic numbers */
int main (void) {
double data[MAXD] = {0}; /* in ISO C declarations come before code */
int i, count = 0; /* initializing variable saves debug time */
printf ("\n Welcome! \n\n Please enter each data point. "
"Enter 'done' when finished.\n\n");
for (;;) { /* loop until scanf input fails (with 'done') */
double tmp; /* block scope declarations are fine */
printf (" data[%4d]: ", count);
if (count < MAXD && scanf(" %lf", &tmp) == 1)
data[count++] = tmp;
else
break;
}
printf ("\n %d values entered:\n\n", count);
for (i = 0; i < count; i++)
printf (" data[%4d] : %.2lf\n", i, data[i]);
return 0; /* main() is type 'int' and returns a value */
}
Example Use/Output
$ ./bin/scanfdoubles
Welcome!
Please enter each data point. Enter 'done' when finished.
data[ 0]: 1.1
data[ 1]: 1.2
data[ 2]: 1.3
data[ 3]: 1.4
data[ 4]: 1.5
data[ 5]: 1.6
data[ 6]: done
6 values entered:
data[ 0] : 1.10
data[ 1] : 1.20
data[ 2] : 1.30
data[ 3] : 1.40
data[ 4] : 1.50
data[ 5] : 1.60
Look things over and let me know if you have any questions.
footnotes:
1. while you can use scanf to take user-input in C, you are better off using a line-oriented function (like fgets) and then parsing the complete line (with, e.g. sscanf). The allows you to both (1) validate the read (e.g. the return of fgets) and then (2) separately validate the value entered by the user. This decoupling of your read, and your parsing has many advantages.
No element of data[] will ever be 'done' (they're floats). If you want to scanf() directly, you'll need to choose a double value that ends the sequence (commonly zero or -1 or something). If that won't work, you can either use something like:
Use fgets() to pull a string, then strncmp() to check for the terminating value and sscanf() to pull out the double, or:
Have the user use Ctrl-D to terminate and check the scan value for EOF.
Oh, and strictly speaking you have an upper limit of entries. You should check i to make sure that you don't exceed that. Never assume your input won't exceed boundaries. sizeof() on a statically-allocated variable or some #defined macro to track that.
Your data is of type double. It can't scan a literal "done".
Instead use EOF for checking end of input.
while(scanf("%lf",&data[i]) != EOF) {
...
}
Another way:
while(scanf("%lf",&data[i]) == 1) {
...
}
Another thing, initialize count to zero, i.e. count = 0;
Bottom line: don't use scanf.
Use something like
char inputline[100];
i = 0;
while(fgets(inputline, sizeof(inputline), stdin) != NULL) {
if(strncmp(inputline, "done", 4) == 0) break;
data[i++] = atof(inputline);
}
scanf is hard enough to use even when all your inputs are the numbers you expect. If the input might be either a number or the word "done", scanf will never work. But reading a line of text, as here, is generally easier and more flexible.
P.S. You also have to worry about the possibility that the user enters more than 1048 numbers.
For your task the loop of gathering input should control not only keyword, but also number if inputs. I suggest to do this as follows:
#include <stdio.h>
#include <string.h>
#define NUM_OF_DATA 1048
int main(void)
{
printf("\n Welcome! \n\n Please enter each data point. Enter 'done' when finished.\n\n");
double data[NUM_OF_DATA];
int i; // counter of entered numbers
char str[5] = { 0 }; // string to read 'done' or other word from input
for (i = 0; i < NUM_OF_DATA; i++) // the first index of data in array is 0 (the last NUM_OF_DATA-1)
{
printf("Data[%i]: ", i);
if (1 == scanf("%lf", &data[i])) // if number was successfully read
continue; // go to next iteration
// if some problem was with reading a loat number
// read the string
scanf("%4s", str); // read not more than 4 characters from input
if ( strcmp(str, "done") == 0)
{
break; // stop input if 'done' was entered
}
// clean input buffer before next input
while (getchar() != '\n');
// correct counter in case of wrong input
i--;
}
// output the number of correct inputs
printf("%d numbers were entered.\n", i);
// do something with data
// taking in account, that i is not index of the last element,
// but the number of elements (indexes are 0 ... i-1)
// ...
return 0;
}
This for loop stops in two cases:
1) when data array is full,
2) when 'done' without quotes entered.
Additional feature is skipping of incorrect input (try how it works).

Wondering about while loop

I started learning C 3 weeks ago, and while learning while loops I tried to build an addition program, basically you keep adding numbers it additions them and after 2nd number it gives you a subtotal for every addition, and if you press 0 to quit It gives you a final sum then quits.
Now I have one main, one additional question. The main question is, I had to use sum = 0 before the while functions, if I use it after "the while" it gives me the number I entered as the result. Now I really wonder what is the idea behind it. When I write it like below does it equates "sum with 0"
for the start and changes the value as I enter another number, or there is some other idea behind it.
And the additional question is , why do I need to use 2 getchar(); to make my program stay on the screen, why not one?
#include <stdio.h>
int main(void)
{
float num;
float sum;
printf(" please enter a number +0 to start the program (0 to quit): \n");
scanf(" %f", &num);
sum =0; //THIS HERE**********************
while (num > 0)
{
printf("please enter integer:\n");
scanf("%f", &num);
sum = sum + num;
printf("current sum is = %f\n", sum);
}
printf("final sum is = %f\n", sum);
getchar();
getchar();
return 0;
}
If you put sum=0 inside the while loop it will be called each time the while loop loops.
This means when you reach sum=sum+num, you will actually be calculating sum=0+num.
You have two use two getchar() calls because the first one is sucking up an additional character that was not absorbed by your scanf. Probably this character is a newline, so you cannot see it. The second getchar() then keeps your terminal open because it is waiting for a character.
To figure out if my hypothesis is correct about the first getchar() you could try this:
char temp = getchar();
printf("%d",(int)temp); //Print out the character number from the first getchar
getchar(); //This keeps the window open
If I use it after the while it gives me the number I entered as the result.
This is because when you do this
while (num > 0) {
sum = 0;
...
sum = sum + num;
}
the value that has been accumulated by sum on prior iterations of the while loop gets erased each time the loop iterates, meaning that only the last value would be added to sum (and kept as the result of the additions).
why do I need to use 2 getchar();
Because when scanf consumes the last number the end-user has entered, it reads everything up to, but not including, the '\n' character, which corresponds to the Enter key. This '\n' character remains in the buffer, waiting to be consumed by your program. The first call of getchar() consumes that "lingering" '\n', while the second one makes your program stay on screen until you press enter again.
= in most programming languages is different from the mathematical =. It does not mean that the two sides will permanently be equal to each other; rather, it means that the right-hand side should be computed and that the result should be assigned to the variable on the left-hand side. Later, another line might change the variable value to something else.
Thus, sum = sum + num; means that the current values of sum and and num are to be added, and the result is to be put back into sum. In order for this to work the way you wish, sum must be 0 the first time this line is executed; hence, you need sum = 0; somewhere. However, if this line is inside the loop, it is repeatedly executed, so that the result of the previous summation disappears and is replaced with 0 before each new number.

Resources