C code problem

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("\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

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

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

Related Computing and Technology 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

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

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.

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.

So it willl not reask the quesiton if the user enters in the wrong input?

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?

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.

Davorak said:
So it willl not reask the quesiton if the user enters in the wrong input?

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.

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("\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;
}

What did you change asher. You have "printf("Enter your gender(m or f): ");" out side of the loop, but franznietzsche already did that.

Did you guys read post #13?

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.

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.