Loop repeating scanf and printf - c

I've written a program that will scanf twice before printf and will output two of what should be a single printf. The issue seems to begin occurring from the point that asks the user to input a number between 1 to 4 to see the average temperature for the entered number of days.
I'm not sure what's causing this double inputs and outputs and the occasional delays. Here's my code:
#include <stdio.h>
#include <stdlib.h>
int main (void) {
int i;
int limit;
int day[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
int high[10], low[10];
printf("---===IPC Temperature Analyzer V2.0===---\n");
printf("Please enter the number of days between 3 and 10, inclusive: ");
scanf("%d", &limit);
while (limit <= 2 || limit >= 11) {
printf("Invalid entry, please enter a number between 3 and 10, inclusive: ");
scanf("%d", &limit);
}
for (i = 0; i < limit; i++) {
printf("Day %d - High: ", day[i]);
scanf("%d", &high[i]);
printf("Day %d - Low: ", day[i]);
scanf("%d", &low[i]);
}
printf("\nDay Hi Low\n");
for (i = 0; i < limit; i++) {
printf("%d %d %d\n", day[i], high[i], low[i]);
}
int max = 0;
int min = 0;
for (i = 0; i < limit; i++) {
if (high[max] < high[i])
max = i;
if (low[min] > low[i])
min = i;
}
printf("\nHighest temperature was: %d on day %d\n", high[max], day[max]);
printf("Lowest temperature was: %d on day %d\n", low[min], day[min]);
int n;
do {
printf("\nEnter a number between 1 and 4 to see the average temperature "
"for the entered number of days, enter a negative number to exit:");
scanf("%d\n", &n);
while (n > 4) {
printf("Invalid entry, please enter a number between 1 and 4, inclusive: ");
scanf("%d", &n);
}
while (n < 0) {
printf("Goodbye!\n");
exit(0);
}
float avgSum = 0.0;
for (i = 0; i < n; i++) {
float avgOfDay = (high[i] + low[i]) / 2.0;
avgSum += avgOfDay;
}
float overallAvg = avgSum / n;
printf("The average temperature up to day %d is: %.2f\n", day[n - 1], overallAvg);
} while (n > 0 || n < 4);
return 0;
}
Example output:
Enter a number between 1 and 4 to see the average temperature for the entered number of days, enter a negative number to exit:5
5
Invalid entry, please enter a number between 1 and 4, inclusive: Invalid entry, please enter a number between 1 and 4, inclusive: 3
The average temperature up to day 3 is: 2.50
Enter a number between 1 and 4 to see the average temperature for the entered number of days, enter a negative number to exit: 2
2
The average temperature up to day 2 is: 2.75
Enter a number between 1 and 4 to see the average temperature for the entered number of days, enter a negative number to exit: -1
The average temperature up to day 2 is: 2.75
Enter a number between 1 and 4 to see the average temperature for the entered number of days, enter a negative number to exit: -1
Goodbye!

The problem you are describing can be traced to the scanf() statement at the beginning of the do loop:
scanf("%d\n", &n);
The newline at the end of the format string is the trouble. When scanf() encounters a white-space character in the format string, it matches white-space characters in the input stream until a non-white-space character is encountered. The problem is that when you press the enter key to input your number, this is just another white-space character, so scanf() greedily continues waiting for more input, until either a non-white-space character, or EOF is encountered. When the user enters a non-white-space character at this point, the scanf() white-space match fails, the entered character remains in the input stream, scanf() finally returns to the calling function, and at last, the next scanf() picks up the character that was just rejected. This is the cause of the sporadic response that you observed.
The fix for this is simple. Just remove the \n from the end of the format string. It is usually the case that a white-space character at the end of a format string is the wrong thing to do.
There are other issues in the code. The test at the end of the do loop should be:
while (n > 0 && n < 4);
The test for an exit value would be better as an if statement instead of a while loop, and the test should be for n < 1 instead of n < 0 to avoid a division by zero error:
if (n < 1) {
printf("Goodbye!\n");
exit(0);
}
It seems that you should change the input prompt to:
printf("\nEnter a number between 1 and 3 to see the average temperature for the entered number of days, enter a negative number to exit:");
If the user chooses 4 here, but only entered data for 3 days, the calculation will access uninitialized values in the high[] and low[] arrays. You will also need to change this input loop to:
while (n > 3) {
printf("Invalid entry, please enter a number between 1 and 3, inclusive: ");
scanf("%d", &n);
}
There may be other issues, but this should get things running.

while (n > 0 || n < 4); => while (n > 0 && n < 4);

I was able to determine the solution to my problem. The new line function next to the scanf and printf of some parts of my code were causing the program to reiterate certain scanf and printf functions.
scanf("%d\n", &n) =>
printf("%d", &n)
printf ("The average temeprature up to day %d is: %.2f\n", day[n-1], overallAvg); =>
printf ("The average temeprature up to day %d is: %.2f", day[n-1], overallAvg);

Related

Program alters variable value during execution

I'm writing the following C program. At this stage, the program should take input from the user and store it into the variable days:
#include <stdio.h>
#define SIZE 10
int main(){
int days = 0;
int high_temp[SIZE] = {0};
int low_temp[SIZE] = {0};
printf("---=== IPC Temperature Calculator V2.0 ===---\n");
if ((days < 3) || (days > 10)) {
printf("Please enter the number of days, between 3 and 10, inclusive: %d");
scanf("%d", &days);
while ((days < 3) || (days > 10)) {
printf("\nInvalid entry, please enter a number between 3 and 10, inclusive: ");
scanf("%d", &days);
printf("\n");
}
}
for(int i = 1; i < days; i++){
printf("\nDay %d - High: ", i);
scanf("%d", &high_temp);
printf("\nDay %d - High: ", i);
scanf("%d", &low_temp);
}
}
However, during execution, the problem assigns an absurd value to days:
---=== IPC Temperature Calculator V2.0 ===---
Please enter the number of days, between 3 and 10, inclusive: 87585440
Mind you that days is initialized as 0 and the value is suppose to change within the if statement.
This statement
printf("Please enter the number of days, between 3 and 10, inclusive: %d");
has undefined behavior. Remove %d from the outputted string.
Just write
printf("Please enter the number of days, between 3 and 10, inclusive: ");
If you want to use the specifier as a prompt then write
printf("Please enter the number of days, between 3 and 10, inclusive: %%d");
that is used %%d.
Your printf() call contains a format specifier of %d but you aren't passing an integer after the format. That's undefined behavior and it's pulling some unknown value from memory.
If you want to print the value of days you need to pass it in the function call. If not then remove the %d specifier.
printf("Please enter the number of days, between 3 and 10, inclusive: %d", days);
here you go, hope that helps
#include <stdio.h>
#define SIZE 10
int main(){
int days = 0;
int high_temp[SIZE] = {0};
int low_temp[SIZE] = {0};
printf("---=== IPC Temperature Calculator V2.0 ===---\n");
if ((days < 3) || (days > 10)) {
printf("Please enter the number of days, between 3 and 10, inclusive: ");
scanf("%d", &days);
while ((days < 3) || (days > 10)) {
printf("\nInvalid entry, please enter a number between 3 and 10, inclusive: ");
scanf("%d", &days);
printf("\n");
}
}
for(int i = 0; i < days; i++){
printf("\nDay %d - High: ", (i+1));
scanf("%d", &high_temp[i]);
printf("\nDay %d - Low: ", (i+1));
scanf("%d", &low_temp[i]);
}
for (int i = 0; i < days; i++){
printf("\n Day # %d", (i + 1));
printf("\n\t High: %d", high_temp[i]);
printf("\n\t Low: %d", low_temp[i]);
}
}

C Programming - Getting the Median from User Inputs

I need help fixing my code. What my code does it asking users to input a number multiple times and will terminate the program once -1 is entered. Then, will get the Sum, Max, Min, Average and Median values.
Sum, Min and Max seems to be working fine. But on the "Average" it's treating the -1 as a userinput, also, I need help on how to get the median value.
Here's what I got so far.
#include <stdio.h>
int main(){
char name[30];
int userInput;
int count = 0;
int sum = 0; // changed from 1 to 0
int max, min = 1000;
float average;
printf("Please enter your name: ");
scanf("%s", &name);
printf("Hello, %s, ", name);
do {
printf("Enter an integer (-1 to quit): ");
scanf("%d", &userInput);
if (userInput == -1) break; // I added this line, average works fine now
sum = sum + userInput;
count = count + 1;
average = sum / count;
if (userInput > max){
max = userInput;
}
if (userInput < min && userInput >= 0){
min = userInput;
}
}
while (userInput >= 0);
printf("Sum: %d \n", sum);
printf("Average: %.2f \n", average);
printf("Max: %d \n", max);
printf("Min: %d \n", min);
return 0;
}
Here's my sample output:
Please enter your name: A
Hello, A, Enter an integer (-1 to quit): 10
Enter an integer (-1 to quit): 20
Enter an integer (-1 to quit): 10
Enter an integer (-1 to quit): -1
Sum: 40
Average: 10.00
Max: 20
Min: 10
So The rest seems to be working now after some modification except for getting the median value.
You do not want to increment the count when userInput == -1
You're incrementing the count and adding to the sum before checking whether userInput == -1. Try rewriting your loop:
while(1){
printf("Enter an integer (-1 to quit): ");
scanf("%d", &userInput);
if(userInput == -1)
break;
/* rest of loop body goes here */
}

Prompt user to re-enter number

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....
}

Outputting the maximum and minimum value from an array in C

I have written a program that asks the user the input the high and low temperature over the course of four days. Following this, the program calculates the mean temperature using the inputs from all four days. Everything is working fine however, I need to have the program determine and output the greatest high temperature and the day it occurred on as well as the smallest low temperature and the day it occurred on. Here's my code so far
#include <stdio.h>
#define NUMS 4
int main (void)
{
int high[NUMS];
int low[NUMS];
const int MAX = 40;
const int MIN = -40;
int totalhigh;
int totallow;
int sum;
float avg;
printf ("---===IPC Temperature Analyzer ===---\n");
printf ("Enter the high value for day 1: ");
scanf ("%d", &high[0]);
printf ("Enter the low value for day 1: ");
scanf ("%d", &low[0]);
while (high[0] > MAX || low[0] < MIN || high[0] < low[0]) {
printf ("Incorrect values, temperatures must be in the range -40 to 40, high must be greater than low.\n");
printf ("Enter the high value for day 1: ");
scanf ("%d", &high[0]);
printf ("Enter the low value for day 1: ");
scanf ("%d", &low[0]);
}
printf ("Enter the high value for day 2: ");
scanf ("%d", &high[1]);
printf ("Enter the low value for day 2: ");
scanf ("%d", &low[1]);
while (high[1] > MAX || low[1] < MIN || high[1] < low[1]) {
printf ("Incorrect values, temperatures must be in the range -40 to 40, high must be greater than low.\n");
printf ("Enter the high value for day 2: ");
scanf ("%d", &high[1]);
printf ("Enter the low value for day 2: ");
scanf ("%d", &low[1]);
}
printf ("Enter the high value for day 3: ");
scanf ("%d", &high[2]);
printf ("Enter the low value for day 3: ");
scanf ("%d", &low[2]);
}
printf ("Enter the high value for day 4: ");
scanf ("%d", &high[3]);
printf ("Enter the low value for day 4: ");
scanf ("%d", &low[3]);
while (high[3] > MAX || low[3] < MIN || high[3] < low[3]) {
printf ("Incorrect values, temperatures must be in the range -40 to 40, high must be greater than low.\n");
printf ("Enter the high value for day 4: ");
scanf ("%d", &high[3]);
printf ("Enter the low value for day 4: ");
scanf ("%d", &low[3]);
}
totalhigh = high[0] + high[1] + high[2] + high[3];
totallow = low[0] + low[1] + low[2] + low[3];
sum = totalhigh + totallow;
avg = sum/8.0;
printf ("The average (mean) temperature was: %.2f\n", avg);
if (high[0] > high[1] || high[0] > high[2] || high[0] > high[3]) {
printf ("The highest temperature was %d, on day 1\n", high[0]);
}
else if (high[1] > high[0] || high[1] > high[2] || high[1] > high[3]) {
printf ("The highest temperature was %d, on day 2\n", high[1]);
}
else if (high[2] > high[0] || high[2] > high[1] || high[2] > high[3]){
printf ("The highest temperature was %d, on day 3\n", high[2]);
}
else {
printf ("The highest temperature was %d, on day 4\n", high[3]);
}
return 0;
}
Your current code can use a loop and a helper function, which would shorten your code by reducing all those scanf() calls. You could also abstract a lot more, by using more functions, but it will show the general idea.
It is also good to check the result of scanf(), just in case the user enters a non-integer.
Your current code could look like this:
#include <stdio.h>
#include <stdlib.h>
#define NUMS 4
/* takes a pointer to a number */
void get_input(int *temp) {
if (scanf("%d", temp) != 1) {
printf("Invalid temp entered\n");
exit(EXIT_FAILURE);
}
}
int main(void) {
int high[NUMS];
int low[NUMS];
const int MAX = 40;
const int MIN = -40;
int day = 1, totalhigh = 0, totallow = 0, sum;
float avg;
for (size_t i = 0; i < NUMS; i++) {
printf ("Enter the high value for day %d: ", day);
/* takes the address of the pointer given by get_input() */
get_input(&high[i]);
printf ("Enter the low value for day %d: ", day);
get_input(&low[i]);
while (high[i] > MAX || low[i] < MIN || high[i] < low[i]) {
printf ("Incorrect values, temperatures must be in the range -40 to 40, high must be greater than low.\n");
printf ("Enter the high value for day %d: ", day);
get_input(&high[i]);
printf ("Enter the low value for day %d: ", day);
get_input(&low[i]);
}
day++;
}
for (size_t i = 0; i < NUMS; i++) {
totalhigh += high[i];
totallow += low[i];
}
sum = totalhigh + totallow;
avg = sum/8.0;
printf ("The average (mean) temperature was: %.2f\n", avg);
return 0;
}
In terms of finding the largest and smallest temperatures, here is a method you can use:
Set max and min to the first element of your array, array[0].
loop from i=1 to i=n.
If and element if bigger than max, set max to array[i]. If an element is smaller than min, set min to array[i].
The day for the highest and lowest temperatures will be i+1.
Since doing something like this will help you understand loops better, I decided to just describe the steps. The above code was just an improvement on your current code, and showing you a easier way to do it will show you a different perspective on how to do problems like these.
I updated my code to have the if statement mentioned in my above code to function correctly. Here it is:
if (high[0] > high[1] && high[0] > high[2] && high[0] > high[3]) { // Check to see if day 1 has the highest temperature against days 2,3 and 4.
printf ("The highest temperature was %d, on day 1\n", high[0]); // Output day 1 as the highest temperature and indicate the temperature value.
}
else if (high[1] > high[0] && high[1] > high[2] && high[1] > high[3]) { // Same function as the above function for day 1 except this is used for day 2.
printf ("The highest temperature was %d, on day 2\n", high[1]); // Refer to day 1 printf
}
else if (high[2] > high[0] && high[2] > high[1] && high[2] > high[3]){
printf ("The highest temperature was %d, on day 3\n", high[2]);
}
else {
printf ("The highest temperature was %d, on day 4\n", high[3]);
}
// Switch out high values with low values in order to determine lowest temperature and its corresponding day.

Prompt for 4 options in a loop and option 1 gets input for an array

The question is too long and complicated to put in the title so i'll try to describe it here:
A loop prompts for 4 options (1,2,3,q) and if you enter 1, you input an account # in accounts[MAX] array. If the total index # of accounts is greater than 10 then it no longer accepts input but if accounts[5] and accounts[11] have the same account # (both are 1400) then it continues to accept it. How can I check if the 2 accounts are the same and if they are to allow input to be entered?
my code so far:
do
{
printf ("Options Available: \n");
printf ("\n 1 - Enter a transaction");
printf ("\n 2 - View the general journal");
printf ("\n 3 - View the balance sheet");
printf ("\n q - Quit the program\n");
printf ("\nPlease enter 1, 2, 3 or q: ");
option = validateoption();
if (option == '1' && totalinput >= MAXtrans)
printf (" **Maximum number of transactions have been entered\n\n");
if (option == '1')
{
printf ("\nEnter an account number (between 1000 and 3999): ");
accounts[i] = validateaccount();
printf ("\n");
printf ("Enter d (debit) or c (credit): ");
debcred[i] = validatedebcred();
printf ("\n");
printf ("Enter transaction amount: ");
amount[i] = validateamount();
printf ("\n");
printf ("\n");
i++;
totalinput++;
}
if (option == '2')
journal(accounts, debcred, amount, &totalinput);
if (option == '3')
balancesheet(accounts, debcred, amount, &totalinput);
} while (option != 'q');
So in accounts[i] if there are 10 accounts entered then it no longer accepts more accounts but if I enter account # 1400 and account[3] or w.e also has the account # of 1400 then it accepts that input because they are the same account and the total number of accounts is still the same.
My validate account function:
long validateaccount() { // VALIDATE INPUT FOR ACCOUNT # IN TRANSACTION FUNCTION
int keeptrying = 1, rc;
long i;
char after;
do
{
rc = scanf ("%ld%c", &i, &after);
if (rc == 0)
{
printf (" **Invalid input try again: ");
clear();
}
else if (after != '\n')
{
printf (" **Trailing characters try again: ");
clear();
}
else if (i < 1000 || i > 3999)
{
printf (" **Invalid input try again: ");
}
else
{
keeptrying = 0;
}
} while (keeptrying == 1);
return i;
}
EDIT: Here is a sample output of what it should show hopefully thats more clear?
Options available:
1 - Enter a transaction
2 - View the general journal
3 - View the balance sheet
q - Quit the program
Please enter 1, 2, 3, or q: 1
Enter an account number (between 1000 and 3999) : 3999
Enter d (debit) or c (credit): d
Enter transaction amount: 10000
Options available:
1 - Enter a transaction
2 - View the general journal
3 - View the balance sheet
q - Quit the program
Please enter 1, 2, 3, or q: 1
Enter an account number (between 1000 and 3999) : 3998
**Maximum number of accounts has been entered
Options available:
1 - Enter a transaction
2 - View the general journal
3 - View the balance sheet
q - Quit the program
Please enter 1, 2, 3, or q: 1
Enter an account number (between 1000 and 3999) : 3999
Enter d (debit) or c (credit): c
Enter transaction amount: 1000
so what happens is 3999 account # is entered first, and then 3998 is entered after but after the 3999 was entered the maximum number of accounts was filled up (10 accounts or accounts[10]) but after 3998 was entered, account # 3999 was entered again and the program accepted that input. If it still isn't clear i'll try and explain more!
If i represents the number of accounts inputted (note that I don't know if you managed correctly the wrong states), j represents the position for the element, thinking that long int variables are stored in the array account, and I will assume that you want to add an update for the state.
So in accounts[i] if there are 10 accounts entered then it no longer
accepts more accounts but if I enter account # 1400 and account[3] or
w.e also has the account # of 1400 then it accepts that input because
they are the same account and the total number of accounts is still
the same.
if ( option == '1' )
{
long int j;
/* k represents position */
int k;
printf ("\nEnter an account number (between 1000 and 3999): ");
/* If is the last try and the account is inside the array let's update it. */
/* Pass by reference k. */
if( ( i == 10 ) && ( isAccount( validateaccount(), &k ) == 1 ) ){
accounts[ k ] = validateaccount();
printf ("\n");
printf ("Enter d (debit) or c (credit): ");
debcred[ k ] = validatedebcred();
printf ("\n");
printf ("Enter transaction amount: ");
amount[ k ] = validateamount();
printf ("\n");
printf ("\n");
i++;
}
/* Pass by reference k. */
else if( ( i == 10 ) && ( isAccount( validateaccount(), &k ) == 0 ) ){
printf (" Your input isn't allowed cause the account is not in the list. \n");
}
else{
accounts[ i ] = validateaccount();
printf ("\n");
printf ("Enter d (debit) or c (credit): ");
debcred[ i ] = validatedebcred();
printf ("\n");
printf ("Enter transaction amount: ");
amount[ i ] = validateamount();
printf ("\n");
printf ("\n");
i++;
}
}
/* I will think your array is a global variable, let's use a pass by reference function. */
int isAccount( long int a, int * k )
{
int result = 0;
int counter, j;
for( counter = 0; counter < 11; counter++ ){
if( accounts[ counter ] == a ){
* k = counter;
return 1;
}
}
return 0;
}
PD: you can use structsIt would have been 10x easier.

Resources