I'm doing a practice 'do while' program where I want the user to enter three numbers and the program will print the sum on screen. After receiving the answer, the program will ask the user if he wants to enter another three numbers to get another answer, and so on. I'm fine with this.
If user enters anything other than an integer ("A,!,%") etc, I want the program to prompt the user to re-enter a number. See comments in program.
#include <stdio.h>
/*
Do - While
This program shall ask the user to enter
three numbers and print out the sum. Entering letters
or special characters will ask the user to re-enter that
number.
example:
Enter Number 1: 2
Enter Number 2: 5
Enter Number 3: 9
Answer is 16
...
Enter Number 1: 2
Enter Number 2: yum here user incorrectly enters letters
Enter Number 2: 8 re-prompted to enter number to continue
Enter Number 3: 9
Answer is 19
*/
int main(void) {
int a,b,c,ans,n;
do{
do{
printf("Enter Number 1: ");
scanf("%d", &a);
printf("\n");
}
while((a>0) || (a<0)|| (a==0));
do{
printf("Enter Number 2: ");
scanf("%d", &b);
printf("\n");
}
while((b>0) || (b<0)|| (b==0));
do{
printf("Enter Number 3: ");
scanf("%d", &c);
printf("\n");
}
while ((c>0) || (c<0)|| (c==0));
ans = a+b+c;
printf("Answer is %d\n\n", ans);
printf("Press 1 to start over, or 0 to quit...");
scanf("%d",&n);
printf("\n");
}while (n!=0);
return 0;
}
Your program contains multiple repeated sections. Since you are gathering three numbers, you should use a for loop which runs three times.
for (int i = 0; i < 3; i++) {
/* ... */
}
Inside the for loop, you're gathering the i+1-th number each time. If the user doesn't enter a valid number, you keep trying to gather it. So the do-while loop containing the printf and scanf will go inside the for loop.
for (int i = 0; i < 3; i++) {
do {
printf("Enter Number %d: ", i+1);
scanf( /* ... */ );
} while ( /* ... */ );
}
scanf returns the number of input items successfully read as an int. So the do-while loop should repeat as long as the return value of scanf is zero. We could store the return value in a variable and check the variable in the while (...);, but we can just move the scanf itself into the while (...);. We also need an array to store the three input numbers.
int n[3];
for (int i = 0; i < 3; i++) {
do {
printf("Enter Number %d: ", i+1);
} while (scanf("%d", n+i) == 0);
}
The rest of the program would loop over the array and store the sum of the elements. You would then output the sum. This approach is robust and maintainable as changing the amount of input numbers is easy and repeated or similar code sections are eliminated.
You can use fgets to get the input and use strtol() to cast the string the user input into an int. If strtol returns 0 when the user input does not start with a number or have a number in it. From there you can check if the user input is 0 and then reprompt the user until a is not 0.
*instead of scanf()*
char num1[5];
char *end;
fgets(num1, 5, stdin);
a = strtol(num1, &end, 10);
while( a = 0){
fgets....
}
Related
I am still new to C programming and need to figure out why when I enter the "c" choice the program isn't printing out the grades entered in the program. I am not seeing what I am missing, can someone let me know if they see what I am missing please?
#include <stdio.h>
#include <stdlib.h>
int main()
{
//Add all of the variables and the array for the grades I want to enter.
char choice;
int gradeScore = 0;//percentage
//int gradeArray[100];//percentArrray //Comment Out
int gCount = 0,i;//count
//Allocate dynamic memory point using gradeArray.
int *gradeArray = (int*)malloc(sizeof(int));
/*The for loop is set to enable the user to enter no more than 100 grades. This is because the gradeArray variable
limit is set to 100. This will then loop through until the user has entered up to 100 grades to ensure there
is no buffering issue.*/
for (gCount = 0; gCount < 100;)
{
/*This prompts the user for a choice that enables them to either enter another grade or exit the program and
print the grades. It also reads the choice entered by the user.*/
printf("******************Enter Choice Selection in Parenthesis******************");
printf("\n\n To add grades, enter choice (a)");
printf("\n When finished entering grades, enter choice (c) \n \nEnter Choice: ");
scanf(" %c", &choice); //space is entered to ensure the compiler does not read whitespaces
/* Then I use an if with the condition set to a valid choice of 'a'. Then I prompt the user
to enter a grade, read it and move on to the next if statement.*/
if(choice == 'a')
{
printf("\nEnter grade: ");
scanf(" %d", &gradeScore);
/*If the grade entered does meet the if condition statement below it is added to the gCount
of grades entered. This will allow all of the grades entered to be printed with the exit condition.*/
if(gradeScore <= 100 && gradeScore >= 0)
{
gradeArray = realloc(gradeArray, sizeof(int) * gCount);
}
}
//The last if statement prints out each grade on a new line when the user choice is c.
if(choice == 'c')
{
break;
}
}
printf("Grades are:\n");
for(i = 0; i < gCount ; i++)
{
printf(" %d\%%\n", gradeArray[i]);
}
free(gradeArray);
return 0;
}
Thank you,
Annette
You are using wrong variable inside for loop according to your program. You are re-initialising gCount to 0 in for loop and not incrementing it. Later you are using same gCount to print grades. But since its value is 0 so no grades are printed.
Problem is that you never increased the value of a gCount variable, and for() loop is wrong too, I would recommend using while() here, also you never added gradeScore to gradeArray. You could write something like this:
#include <stdio.h>
#include <stdlib.h>
int main()
{
//Add all of the variables and the array for the grades I want to enter.
char choice;
int gradeScore = 0;//percentage
//int gradeArray[100];//percentArrray //Comment Out
int gCount = 0,i;//count
//Allocate dynamic memory point using gradeArray.
int arr_size = 20;
int *gradeArray = malloc(sizeof(int)*arr_size);
/*The for loop is set to enable the user to enter no more than 100 grades. This is because the gradeArray variable
limit is set to 100. This will then loop through until the user has entered up to 100 grades to ensure there
is no buffering issue.*/
while(gCount < 100)
{
/*This prompts the user for a choice that enables them to either enter another grade or exit the program and
print the grades. It also reads the choice entered by the user.*/
printf("******************Enter Choice Selection in Parenthesis******************");
printf("\n\n To add grades, enter choice (a)");
printf("\n When finished entering grades, enter choice (c) \n \nEnter Choice: ");
scanf(" %c", &choice); //space is entered to ensure the compiler does not read whitespaces
/* Then I use an if with the condition set to a valid choice of 'a'. Then I prompt the user
to enter a grade, read it and move on to the next if statement.*/
if(choice == 'a')
{
printf("\nEnter grade: ");
scanf(" %d", &gradeArray[gCount]);
/*If the grade entered does meet the if condition statement below it is added to the gCount
of grades entered. This will allow all of the grades entered to be printed with the exit condition.*/
if((gCount+1) == arr_size)
{
arr_size += 20;
gradeArray = realloc(gradeArray, sizeof(int) * arr_size);
}
gCount++;
}
//The last if statement prints out each grade on a new line when the user choice is c.
if(choice == 'c')
{
break;
}
}
printf("Grades are:\n");
for(i = 0; i < gCount ; i++)
{
printf(" %d\%%\n", gradeArray[i]);
}
free(gradeArray);
return 0;
}
Also, I want to point out that you shouldn't allocate array with just one element and constantly reallocate it. It is a bad practice, time-consuming, and can lead to some bigger problems later.
I recommend you to check this Do I cast the result of malloc? for malloc casting.
When the for loop is run for the first time the program waits for the users input. But after the first time the two scanf lines seems to be skipped.
I've commented out the misc code:
#include <stdio.h>
int n = 0;
struct student {
int age;
char name[20];
};
void enterStudents() {
printf("How many students do you want to enter? \n");
scanf("%d", &n);
struct student list[n];
for(int i=0; i<n; i++){
printf("Enter student number %d's age: ", i+1);
scanf("%d", &list[i].age);
printf("Enter student number %d's name: ", i+1);
scanf(" %c", list[i].name);
}
listSort(list);
}
/**int listSort(struct student list[n]) {
char tempName[20];
int tempAge;
for(int i=0; i<n-1; i++){
if(list[n].age < list[n+1].age) {
tempAge = list[n].age;
strcpy(tempName, list[n].name);
list[n].age = list[n+1].age;
strcpy(list[n].name, list[n+1].name);
list[n+1].age = tempAge;
strcpy(list[n+1].name, tempName);
}
}
}**/
int main() {
enterStudents();
}
One problem that beginners often overlook with scanf is that if the conversion
fails or the the conversion converts less characters than the user entered (for
example using %c instead of %s), then scanf leaves the not-converted
characters in the input buffer. A subsequent call of scanf will first try to
convert those characters that are in the input buffer, before it reads again
from the user.
In your case you used %c but the user enters something that is longer than a
single character. Only 1 character was used in the conversion the rest was left
in the input buffer. In the next for iteration scanf("%d") tries to convert
the characters that were left in the input buffer and because the user enter non-digits for the name, scanf fails and the next scanf reads only the first characters and
left the rest behind, etc. That's why it appears that scanf skips the calls.
You should check the return value of scanf, it returns the number of
successful conversion it made. This is great information, if you get less
conversions than expected, then you know the scanf call failed and you can
react to that. Also you may also clean the buffer if you are reading strings,
newlines and word after an empty space are left in the buffer and that can cause
some trouble with subsequent calls of scanf. You can use a function like this:
void clean_stdin(void)
{
int c;
while((c = getchar()) != '\n' && c != EOF);
}
So your function should look like this:
int enterStudents() {
printf("How many students do you want to enter? \n");
if(scanf("%d", &n) != 1)
{
fprintf(stderr, "Could not read from the user\n");
return -1; // failure
}
if(n <= 0)
{
fprintf(stderr, "invalid number of students\n");
return -1;
}
struct student list[n];
for(int i=0; i<n; i++){
printf("Enter student number %d's age: ", i+1);
if(scanf("%d", &list[i].age) != 1)
{
fprintf(stderr, "could not read age from the user\n");
return -1;
}
printf("Enter student number %d's name: ", i+1);
if(scanf("%19s", list[i].name) != 1)
{
fprintf(stderr, "could not read name from the user\n");
return -1;
}
// cleaning stdin
clean_stdin();
}
...
return n; // sucess
}
Note that I've changed the function so that it returns -1 on failure and the
number of students read on success, so the caller can know that something went wrong and get
the number of students at the same time. In general, in order to make your code
more robust, you should never trust the user and you should double check
user input. You have to check that the user didn't enter a negative number for
the student count. The "correct" mind set is "the user is trying to break your
code by entering incorrect data and I have to deal with that". I know, the code
become slightly more larger, but it is more robust and if something fails, you
can narrow down more quickly (based on the error messages) where something went
wrong. In your code, when something fails, you have really no idea where it
could have happened.
Also note that in the name scan I used scanf("%19s", ..) instead of %s. The
reason is that using %s you might overflow the buffer if the name is longer
than the buffer can hold. If the name is longer than 19 characters, it will
overflow the buffer. With "%19s" you are limiting how many characters should
be read, in this case scanf will convert at most 19 characters and ignore the
rest. Why 19 and not 20? You have to use 19, because strings in C are
'\0'-terminated, so the last space in the array should be used for the
'\0'-terminating bytes, hence 19.
Whenever you take input from user where input has sequence as first is any other data type and then character or character array as in your case sequence is integer and then character. First you enter the age of student like 21 now when u press 'enter key' this 'enter' is taken as the input for next character input. Then your input will look like this:
age=21
name='enter' (enter key that you pressed)
Now we can use a function that is fflush(stdin), this will flush out that enter key and allow you to enter name. this code will work:
void enterStudents()
{
printf("How many students do you want to enter? \n");
scanf("%d", &n);
struct student list[n];
for(int i=0; i<n; i++){
printf("Enter student number %d's age: ", i+1);
scanf("%d", &list[i].age);
//enter this line after your first input
fflush(stdin);
printf("Enter student number %d's name: ", i+1);
scanf(" %s", list[i].name);
}
listSort(list);
}
I am trying to get the user to re enter the the number again if they enter a value of less than ten
i am certain the problem lies with the while statement.
this what i have
printf_s("Enter the player first name: ");
scanf_s("%s", names[i], 25); //enters name and creates a newline <enter key>//
printf_s("Minimum number to stop in a turn: ");
scanf_s("%d", &min_number, sizeof(int));
do {
printf_s("please enter a number greater or egual to 10");
} while (min_number <= 10);
scanf_s("%d ", &min_number);
printf_s("please enter a number greater or equal to 10\n\n");
is a do while loop the best option or should i look at using another type of loop
enter image description here
As I was corrected, thoughfully scanf returns the number of receiving arguments successfully assigned.
Here is a fixed version:
void main(){
int num = 0;
while(num <=10){
scanf("%d ", &num);
printf_s("please enter a number greater or equal to 10\n\n");
}
}
After the authour edited the code in his question and upon his request:
do {
printf_s("please enter a number greater or egual to 10\n\n");
scanf_s("%d", &min_number);
} while (min_number < 10);
When doing the do/while loop the body of the loop is in the
do{body goes here}while(some condition);.
After another edit, on author request:
printf_s("Minimum number to stop in a turn: ");
scanf_s("%d", &min_number, sizeof(int));
while(min_number < 10){
printf_s("please enter a number greater or egual to 10\n\n");
scanf_s("%d", &min_number);
}
This will do the following it will ask for "Minimum number to stop in a turn: " if it is greater or equal to 10 it will continue after the loop. If it is not it will give clarification "please enter a number greater or egual to 10" and will receive another input. It will loop until it receive greater or egual to 10.
I am trying to create a program which takes a number and we match that number with a variable which has a specific number stored. We need to keep doing that until the user enters the correct number that matches the number we have stored in our variable:
#include <stdio.h>
int main(void) {
int i;
int j;
int num1;
int num2 = 2;
printf("Enter number");
scanf("%d", &num1);
while (num1 == 0) {
printf("Enter number");
scanf("%d", &num1);
}
while (num1 != num2) {
for(j=1;j
printf("This is not the correct number! \n");
printf("Enter number again: ");
scanf("%d", &num1);
}
if (num1 == num2) {
printf("The numbers have matched! \n");
}
}
I am confused with how do we create a loop where we don't know how many times the user will enter an incorrect number. What I want with the loop is to display
is how many times the user enters an incorrect number. Let say if they enter 3 times.
This is not the correct number 1!
This is not the correct number 2!
This is not the correct number 3!
But we don't know how many times the user will enter an incorrect number, so what condition do I put in a loop, so it counts.
You want to create a separate counter variable that keeps track of how many times you've gone through the loop. Set it to 0 before the loop, then increment on each iteration.
int count = 0;
...
while (num1 != num2) {
count++;
printf("This is not the correct number %d! \n", count);
printf("Enter number again: ");
scanf("%d", &num1);
}
Also, I'm presuming this is a typo:
for(j=1;j
CODE:
#include <stdio.h>
main() {
int nums[100], i;
char answer;
int count = 0;
double avg;
for (i = 0; i < 100; i++) {
printf("Enter number %d: ", i + 1);
scanf("%d", &nums[i]);
printf("Another? ");
scanf("%c", &answer);
count += nums[i];
}
}
RUN:
~> a.out
Enter number 1: 1
Another? Enter number 2: 2
Another? Enter number 3: 3
Another? Enter number 4: 4
Another? Enter number 5: 5
Another? Enter number 6: 6
Another? Enter number 7: 7
Another? Enter number 8: 8
Another? Enter number 9:
It's supposed to ask me if I want to enter another number, but for some reason the scanf is not working. Also, I need to make it so that the user can enter 100 numbers, or any number under that, being prompted with a question of "do you want to enter another number". If the answer is no, it terminates, if it is yes, it carries on.
Your first scanf leaves a newline in the buffer. It's because %d ignores trailing blanks while %c doesn't. Use this cheap trick to make the second scanf eat the blanks:
scanf(" %c", &answer);
^
The issue is common enough, you can read more about it in the C FAQ.
You need a space before the %c in order to skip the newline that wasn't read when scanf stopped at the end of the number.
I have some unsolicited advice...
Don't use scanf(3) directly, it's too hard to make it do what you want. It's usually better to use fgets(3) and then sscanf(3).
Compile with warnings turned on. (On my Mac that means cc -Wall ...)
And with warnings turned on, here your program with a few issues fixed:
#include <stdio.h>
int main(void) {
int nums[100], i;
char answer;
int count = 0;
// double avg;
for (i = 0; i < 100; i++) {
printf("Enter number %d: ", i + 1);
scanf(" %d", &nums[i]);
printf("Another? ");
scanf(" %c", &answer);
if (answer != 'y' && answer != 'Y')
break;
count += nums[i];
}
return 0;
}