Calculating Blood Alcohol Content (BAC)

  • Thread starter Thread starter franznietzsche
  • Start date Start date
  • Tags Tags
    Alcohol Blood
Click For Summary
SUMMARY

This discussion focuses on a C program designed to calculate Blood Alcohol Content (BAC) based on user inputs such as the number of drinks consumed, weight, gender, and time spent drinking. The primary issue identified is the double printing of the prompt for gender input due to an unhandled newline character left in the input buffer after previous scanf calls. The solution involves using getchar() to clear the buffer or restructuring the input loop to prevent the prompt from appearing multiple times.

PREREQUISITES
  • Understanding of C programming syntax and structure
  • Familiarity with data types such as float and char
  • Knowledge of input/output functions in C, specifically scanf and printf
  • Basic concepts of ASCII values and character handling in programming
NEXT STEPS
  • Implement getchar() to handle newline characters in C input
  • Explore character arrays for user input instead of single characters
  • Learn about buffer management in C to avoid input issues
  • Research best practices for user input validation in C programs
USEFUL FOR

Programmers, particularly those working with C, who are developing user-interactive applications and need to manage input effectively. This discussion is also beneficial for anyone interested in implementing calculations related to Blood Alcohol Content.

franznietzsche
Messages
1,503
Reaction score
6
Figured this forum might be able to help more than the homework help, if not, feel free to redirect.

I'm writing a program that calculates Blood Alcohol Content from various input the user gives (nothing fancy, straight forward simple calculation, prompting user for data, that sort of thing).

However it is doing something weird, and I cannot figure out for the life of me why it is doing this. The code is:

#include<stdio.h>

#define POUNDS_PER_KILO 2.2406
#define OZ_ALCOHOL_PER_DRINK 0.54
#define PERCENT_WATER_MALE 0.58
#define PERCENT_WATER_FEMALE 0.49
#define GRAMS_ALC_PER_OZ 23.36
#define PERCENT_WATER_BLOOD 0.806
#define METABOLISM_RATE 0.012

int main(void)
{

float numDrinks, weight, bac, mlWater, gramsAlc, alcPerMlWater, alcPerMlBlood, timeDrinking;
char gender = 'c';

printf("Welcome to the Percent Blood Alcohol Calculator!\n\n");
printf("Enter the number of drinks you've had so far: ");
scanf("%f", &numDrinks);

printf("How many hours ago did you start drinking: ");
scanf("%f", &timeDrinking);

while((gender!='m')&&(gender!='M')&&(gender!='f')&&(gender!='f')) {
printf("Enter your gender(m or f): ");
scanf("%c", &gender);
}


printf("How much do you weigh (yes, your real weight): ");
scanf("%f", &weight);

if (gender == 'M' || gender == 'm') {
mlWater = weight/POUNDS_PER_KILO * PERCENT_WATER_MALE*1000;
}else if(gender=='F' || gender == 'f') {
mlWater = weight/POUNDS_PER_KILO * PERCENT_WATER_FEMALE*1000;
}

gramsAlc = numDrinks*OZ_ALCOHOL_PER_DRINK*GRAMS_ALC_PER_OZ;
alcPerMlWater = gramsAlc / mlWater;
alcPerMlBlood = alcPerMlWater * PERCENT_WATER_BLOOD;
bac = alcPerMlBlood * 100;
bac = bac - METABOLISM_RATE * timeDrinking;

printf("Your BAC is: %f\n", bac);

printf("\n**Discalimer: The information from this calculator is only an estimate**\n");
printf(" In fact, you're probably not the least bit inebriated, go have five more.\n");

return 0;
}

The output is:

Welcome to the Percent Blood Alcohol Calculator!



Enter the number of drinks you've had so far: 5

How many hours ago did you start drinking: 1

Enter your gender(m or f): Enter your gender(m or f): m

How much do you weigh (yes, your real weight): 150

Your BAC is: 0.118923



**Discalimer: The information from this calculator is only an estimate**

What i can't figure out is why its printing that message (in bold) twice. I've checked the loop that prints that part in the code(also bolded) and have no idea what is wrong with it.
 
Computer science news on Phys.org
Are you piping this info into the program?
If so there might be a whitesapce or a incorect return char after you timeDrinking.

In any case it looks like there is somethign waitin gon the buffer for you that is not m, M, F,f.

Less likely answer is if you are typing it in by hand that the concole you are using uses a return char that is not regonized by scanf.

Find out what is there on the buffer by:
Code:
 while((gender!='m')&&(gender!='M')&&(gender!='f')&&(gender!='f')) {
printf("Enter your gender(m or f): ");
scanf("%c", &gender);
printf("Test output buffer char: %c %i \n",gender,gender);
}

That will at least tell you what is on the buffer.
 
I should have clarified, when it prints that bolded line, it only prompts me once, its prints both statements as one.

I initialised gender when i declared so that it was 'c', so the loop would run once for sure, and keep running until a proper input was given. But it double prints the prompt for some reason.
 
Right, probably because something is on the buffer before it enters the loop.

Then the program prints out your question. Scanf reads form the buffer and finds something, but it is not m,M,f,F so the loop runs again but this time the buffer is empty so it waits for your input.

This is just a guess btw.
 
Ok, i added that line like you suggested and the output becomes:

Welcome to the Percent Blood Alcohol Calculator!

Enter the number of drinks you've had so far: 5
How many hours ago did you start drinking: 1
Enter your gender(m or f): Test output buffer char
10
Enter your gender(m or f): m
Test output buffer char m 109


How much do you weigh (yes, your real weight): 150

Your BAC is: 0.118923

**Discalimer: The information from this calculator is only an estimate**

For some reason its not initialising gender correctly, since its supposed to be initialised to 'c' which is not 10(it should be 99). In fact, its initialising gender as a newline character...hmmm...Any idea why?
 
I was right something is on the buffer waiting for scanf.

The 10 is not inside the gender variable, it is in the input buffer. The buffer holds the input from the keyboard and other sources, then you program reads from the buffer to get its input.

You have two options, try and track down the source of the random char on the buffer, or if it is always something off the alphabet chart, just If statement out the printf statement when it is not in the correct range.
 
Question is it 10 each time? Or does it change each time you run the program?
 
Davorak said:
I was right something is on the buffer waiting for scanf.

The 10 is not inside the gender variable, it is in the input buffer. The buffer holds the input from the keyboard and other sources, then you program reads from the buffer to get its input.

You have two options, try and track down the source of the random char on the buffer, or if it is always something off the alphabet chart, just If statement out the printf statement when it is not in the correct range.


Right, the 10 is not the gender variable, but the newline character right before it is. So what's happening is the previous scanf for weight, reads in the weight, but then went i hit enter the newline character gets passed to the next scanf, so i need to do something to prevent that...

If i enter 1m for the time drinking, it reads the m into gender and jumps right out of the loop. So for some reason, whatever i enter immediately after the time drinking gets passed to scanf...
 
Davorak said:
Question is it 10 each time? Or does it change each time you run the program?

10 is the ASCII code for a newline. And it is 10 each time.
 
  • #10
Sounds like you just need to burn the newline then.

scanf(%c,&gender);

while(...

It also sounds like two spreate return chars are being used by the console and scanf only burns the first of the two. I think they are called newline and the return carriage. The console is putting them both in the buffer while scanf only expects there to be one.
 
  • #11
I fixed the problem.

Rather than trying to stop it from running the loop twice unnecessarily, i just pulled the printf statement that prompted the user out of the loop, so that no matter how many times the loop is run the prompt only appear once. So when the newline char gets passed to scanf and the loop runs a second time it is invisible to the user.
 
  • #12
So it willl not reask the question if the user enters in the wrong input?

Enter your gender(m or f):h
j
k
l
m

How much do you weigh (yes, your real weight):

Something like that?

It is also odd that it is not ignored in the first place scanf is supposed to ignore leading newlinesk, whitespaces, and carriage.

What library are you useing?
Are using the command console? I would assume with windows nt or higher?
 
  • #13
All you have to do is add a getchar() to your while loop (in your original program), like this:

Code:
while((gender!='m')&&(gender!='M')&&(gender!='f')&&(gender!='f')) {
    getchar();
    printf("Enter your gender(m or f): ");
    scanf("%c", &gender);
}

Your problem is each time the user enters a response (ended by a newline) to a question, scanf leaves the newline character in the buffer. On the next call to scanf, if scanf is looking for a number it discards that newline & keeps looking (and takes the number that the user enters). But in the while loop, scanf is looking for a char, so it simply accepts that leftover newline as the response & stores that as the value of gender. Adding getchar() soaks up and discards the extra newlines.
 
  • #14
Davorak said:
So it willl not reask the question if the user enters in the wrong input?

Enter your gender(m or f):h
j
k
l
m

How much do you weigh (yes, your real weight):

Something like that?

Exactly.

It is also odd that it is not ignored in the first place scanf is supposed to ignore leading newlinesk, whitespaces, and carriage.

What library are you useing?
Are using the command console? I would assume with windows nt or higher?

Gcc-3.3.4, on Linux.

I don't do any work for anything in windows. Not voluntarily anyway.
 
  • #15
This will correct the problem!

#include<stdio.h>

#define POUNDS_PER_KILO 2.2406
#define OZ_ALCOHOL_PER_DRINK 0.54
#define PERCENT_WATER_MALE 0.58
#define PERCENT_WATER_FEMALE 0.49
#define GRAMS_ALC_PER_OZ 23.36
#define PERCENT_WATER_BLOOD 0.806
#define METABOLISM_RATE 0.012

int main(void)
{

float numDrinks, weight, bac, mlWater, gramsAlc, alcPerMlWater, alcPerMlBlood, timeDrinking;
char gender = 'c';

printf("Welcome to the Percent Blood Alcohol Calculator!\n\n");
printf("Enter the number of drinks you've had so far: ");
scanf("%f", &numDrinks);

printf("How many hours ago did you start drinking: ");
scanf("%f", &timeDrinking);

printf("Enter your gender(m or f): ");
while((gender!='m')&&(gender!='M')&&(gender!='f')&&(gender!='F')) {

scanf("%c", &gender);
}

printf("How much do you weigh (yes, your real weight): ");
scanf("%f", &weight);

if (gender == 'M' || gender == 'm') {
mlWater = weight/POUNDS_PER_KILO * PERCENT_WATER_MALE*1000;
}else if(gender=='F' || gender == 'f') {
mlWater = weight/POUNDS_PER_KILO * PERCENT_WATER_FEMALE*1000;
}

gramsAlc = numDrinks*OZ_ALCOHOL_PER_DRINK*GRAMS_ALC_PER_OZ;
alcPerMlWater = gramsAlc / mlWater;
alcPerMlBlood = alcPerMlWater * PERCENT_WATER_BLOOD;
bac = alcPerMlBlood * 100;
bac = bac - METABOLISM_RATE * timeDrinking;

printf("Your BAC is: %f\n", bac);

printf("\n**Discalimer: The information from this calculator is only an estimate**\n");
printf(" In fact, you're probably not the least bit inebriated, go have five more.\n");

return 0;
}
 
  • #16
Thats what i already did.
 
  • #17
What did you change asher. You have "printf("Enter your gender(m or f): ");" out side of the loop, but franznietzsche already did that.
 
  • #18
Did you guys read post #13?
 
  • #19
One solution is to use a character string. Instead of
...
scanf("%c", &gender);
...

I would declare 'gender' to be a string, and then test

char gender[10];

...

do {
printf("Enter your gender(m or f): ");
scanf("%s", &gender);
}
while((gender[0]!='m')&&(gender[0]!='M')&&(gender[0]!='f')&&(gender[0]!='F'))

I believe the more elegant alternative is to use getchar() and echo the output, like so:
do {
printf("Enter your gender(m or f): ");
gender = getchar();
printf(gender);
}
while((gender!='m')&&(gender!='M')&&(gender!='f')&&(gender!='F'))

getchar() avoids having to deal with a newline, as it returns as soon as a key is pressed.
 
  • #20
gnome said:
Did you guys read post #13?


Yes. And i liked that idea more than moving the prompt out of the loop, but i had submitted it already.