Program that keeps running until the user inputs n to exit - c

I a working on an assignment that allows the user to input "type" and "weight" and it'll display the cost. Here is the code. I want it to keep running until the user enters 'n'.
main()
{
char type,chr;
float cost,weight;
do
{
printf("Insert the type of fish: "); /*inputs type and weight*/
scanf("%c",&type);
printf("insert weight: ");
scanf("%f",&weight);
switch(type)
{
case 'K':
case 'k':
cost=weight*9.00;
break;
case 'R':
case 'r':
cost=weight*10.00;
break;
case 'S':
case 's':
cost=weight*12.00;
break;
case 'G':
case 'g':
cost=weight*8.00;
break;
case 'T':
case 't':
cost=weight*15.00;
break;
default :
printf("Invalid type\n");
}
printf("The cost of fish is:%.2f \n",cost);
printf("Do you want to continue?Y/N: ");
scanf(" %c",&chr);
}
while(chr == 'Y' || chr == 'y');
}
I have used the do..while loop, it worked fine until I typed in 'y' and I cannot enter the type.

Reading types from the stdin stream assumes you know exactly what is next in the stream. As Streeragh mentions, you likely have a newline as the next input character. You can triage this by dumping out what chr is (try it in hex, like %0x). The mentioned article also offers good advice: Input the text as %s (or use readline) and then parse out the input. Look into strtok. And also be aware that stdin can be redirected from a pipe (i.e out.exe < sampleinput.txt) Cheers.

Related

Weird behavior of getchar()

Currently, I am doing a project in c language in which I have to write a while loop to constant receive either keyboard input or joystick input. The joystick input is okay but for the keyboard input, there are 2 types of inputs: arrow and normal input ('a', 'b', ...). For the keyboard input, I referred to this link (https://stackoverflow.com/a/11432632) to receive arrow keys.
Here is my code:
while(true){
if (getchar() == '\033') { // if the first value is esc
getchar(); // skip the [
switch(getchar()) { // the real value
case 'A':
printf("arrow up \n");
break;
case 'B':
printf("arrow down \n");
break;
case 'C':
printf("arrow right \n");
break;
case 'D':
printf("arrow left \n");
break;
}
}
if (getchar() != '\033'){
printf("non arrow \n");
}
}
However, the "non arrow" constantly appears even though I pressed arrow button.
If I changed the code from printf("non arrow \n") by have a variable char c, assign getchar() to it and later print c:
if (getchar() != '\033'){
printf("non arrow \n");
}
The output will be as expected for arrow key (receive and print as expected) but nothing appeared when 'e' or 'r' or other single character key is entered.
I wonder what is the problem for my code and how can I modify it to receive behavior as I want.
I hope to receive answer soon.
Thank you, Huy Nguyen.
You're reading another character when you do if (getchar() != '\033'), not testing the same character that you tested the first time.
Use else instead of calling getchar() again.
while(true){
if (getchar() == '\e') { // if the first value is esc
getchar(); // skip the [
switch(getchar()) { // the real value
case 'A':
printf("arrow up \n");
break;
case 'B':
printf("arrow down \n");
break;
case 'C':
printf("arrow right \n");
break;
case 'D':
printf("arrow left \n");
break;
default:
printf("non arrow\n");
}
} else {
printf("non arrow \n");
}
}
I've added a default: case to the switch in case they send a different escape sequence. You should probably also check that the first character after ESC is [, not just assume it will be.
If you have more than two conditions, you can use switch(getchar()) there, like you do with the character after ESC [, or you can assign the result of getchar() to a variable and test that in the conditions.
Also, you should use else if when you're testing mutually-exclusive conditions.

Multiple chars in SWITCH CASE in C

I have a school project and I'm working on a menu where the users chooses what he wants to do. I want the choice variable to be a char, not an int. Can I add multiple chars in a single switch case? I searched for a solution but I only found one when the value is an int, not a char. I tried this but it didn't work:
char choice;
scanf("%c", &choice);
switch(choice)
{
case 'S', 's':
// do something
break;
case 'I', 'i':
// do another thing
break;
default:
printf("\nUnknown choice!");
break;
}
For starters use the following format in scanf
char choice;
scanf( " %c", &choice );
^^^
(see the blank before the conversion specifier). Otherwise the function will also read white space characters.
You can use several adjacent case labels like for example
switch(choice)
{
case 'S':
case 's':
//do something
break;
case 'I':
case 'i':
//do anotherthing
break;
default:
printf("\n Unknown choice !");
break;
}
An alternative approach is to convert the entered character to the upper case before the switch. For example
#include <ctype.h>
//...
char choice;
scanf( " %c",&choice );
switch( toupper( ( unsigned char )choice ) )
{
case 'S':
//do something
break;
case 'I':
//do anotherthing
break;
default:
printf("\n Unknown choice !");
break;
}
You can use fall through like this:
case 'S':
case 's':
// do something
break;
case ...
You can put multiple case labels after each other:
switch(choice) {
case 'S':
case 's':
//do something
break;
case 'I':
case 'i':
//do anotherthing
break;
default:
printf("\n Unknown choice !");
break;
}

Switch / Case issue

For C language, I know I'm close, but for for any character inputted, the printout is "Consonant". What is wrong with my switch case statement. Will I need if statements?
#include <stdio.h>
#include <stdlib.h>
int main()
{
char name;
printf("Enter a character: ");
scanf_s("%c", &name);
switch (name)
{
case 'a':
printf("Vowel");
break;
case 'e':
printf("Vowel");
break;
case 'i':
printf("Vowel");
break;
case 'o':
printf("Vowel");
break;
case'u':
printf("Vowel");
break;
case 'y':
printf("Sometimes");
break;
default:
printf("Consonant");
}
return 0;
}
Note that the Microsoft page for scanf_s() says:
In the case of characters, a single character may be read as follows:
char c;
scanf_s("%c", &c, 1);
Your scanf_s() call is failing, but you are not checking the result, so you don't know that.
ALWAYS check the result of input functions!
And make sure you've read the manual page for functions you're using.
It's probably also a good idea to use " %c" as the format string to skip white space. However, that's a refinement for later.
You don't have a break; after the code in the default: case label. That's not a good idea.
You can use:
if (scanf_s("%c", &name, 1) == 1)
{
switch (name)
{
case 'a':
case 'e':
case 'i':
case 'o':
case 'u':
printf("Vowel\n");
break;
case 'y':
printf("Sometimes\n");
break;
default:
printf("Consonant\n");
break;
}
}
else
fprintf(stderr, "Failed to read a character\n");
Note that all upper-case letters, punctuation, white space and control characters are deemed to be consonants. That's not entirely accurate.

Why does getchar() read an entire line?

The sample of the program is as follow:
int main(void)
{
char input;
printf("\nEnter phone number: ");
while ((input = getchar()) != '\n') {
switch (toupper(input)) {
case 'A': case 'B': case 'C':
printf("2");
break;
case 'D': case 'E': case 'F':
printf("3");
break;
case 'G': case 'H': case 'I':
printf("4");
break;
case 'J': case 'K': case 'L':
printf("5");
break;
case 'M': case 'N': case 'O':
printf("6");
break;
case 'P': case 'R': case 'S':
printf("7");
break;
case 'T': case 'U': case 'V':
printf("8");
break;
case 'W': case 'X': case 'Y':
printf("9");
break;
default:
putchar(input);
}
}
printf("\n\n");
return 0;
}
My question is, how on Earth does the flow here work? I can't seem to understand the path the program took. Does the char variable magically become an array? How is it that putchar() prints the entire line instead of the first character entered? How exactly does something that's supposed to get and print one character, reads and prints an entire line of characters while altering them with the switch statement? Does it test each char as its entered? But then how is the string printed as a string?
Edit: I've done some research and I read about a keyboard buffer, which seems to be the cause of my confusion. To my knowledge, getchar() and putchar() receives and outputs a single character. I'm aware that the loop asks continuously for the next "buffered" char when the getchar() comes back around, still a bit confused by I should get it, but what's more confusing is putchar(). At the end of the loop, when it breaks and goes to the condition, does it print that one character then continues and prints the other one by one with each execution of the loop? Only stopping the loop at which point the new line was read? And if so, only what was previously printed, is displayed on the screen? And then if that's the case then the printed chars would print in line next to each other with each execution, giving the illusion of a string? I need confirmation on this and also, when is the char discarded and replaced? After its printed? And at which line does it receive the next char in the buffer queue?

Why does this invalid input still works? (switch case) char error

UPDATED CODE
Why does the input 12 works? It interprets 12 as option 1 and takes 2 for the first scanf of case'1'? I do not want to use int opcao as if I enter a leter it will run indefinitly.
I want that the user can only exit the program when he chooses option exit (one of the cases) thus the do... while.If the user enters an invalid character or leter or whatever the menu shows again and shows the default message. I also want that after the chosen case is executed, it presents the menu again for a new choice thus i am using an always valid condition of 1=1 on the while. I can't use integers as if you enter a leter the program goes bonkers a.k.a never stops running. just try it.
char opcao;
do {
menu();
scanf(" %c",&opcao);
switch(opcao) {
case '1':
printf("Massa do módulo (sem combustível):\n");
scanf("%f",&m_modulo);
printf("Massa de combustível:\n");
scanf("%f",&m_combustivel);
printf("Altitude no início da alunagem em relação a um ponto de referência:\n");
break;
case '2':
break;
case '3':
printf("Funcionalidade nao disponivel.\n");
break;
case '4':
printf("Funcionalidade nao disponivel.\n");
break;
case '5':
printf("Funcionalidade nao disponivel.\n");
break;
case '6':
exit(0);
break;
default:
printf("Opcao invalida, as seguintes opcoes estao disponiveis:\n");
break;
}
}
while(1==1);
That's because you're reading your input with a single %c.
This way, the first character of 12 (1) is used by the switch, while the second is used by the scanf of case '1':.
To avoid this behaviour, you can read the options as integers and use the placeholder %d in your very first scanf.
EDIT:
To avoid your infinte loop problem, you can do like this:
#include <stdio.h>
void clean_stdin();
int main() {
int opcao;
float m_modulo, m_combustivel;
int flag = 0;
do {
printf("Make a choice: ");
if (scanf("%d", &opcao) == 0) {
clean_stdin();
}
else {
switch(opcao) {
case 1:
printf("Massa do módulo (sem combustível): ");
scanf("%f", &m_modulo);
printf("Massa de combustível: ");
scanf("%f", &m_combustivel);
printf("Altitude no início da alunagem em relação a um ponto de referência.\n");
break;
case 2:
break;
case 3:
printf("Funcionalidade nao disponivel.\n");
break;
case 4:
printf("Funcionalidade nao disponivel.\n");
break;
case 5:
printf("Funcionalidade nao disponivel.\n");
break;
case 6:
flag = 1;
break;
default:
printf("Opcao invalida, as seguintes opcoes estao disponiveis:\n");
}
}
} while(flag == 0);
}
void clean_stdin()
{
int c;
do {
c = getchar();
} while (c != '\n' && c != EOF);
}
What I've done is the following:
Check the scanf output if it reads the input correctly (in this specific case, if the input was a number it returned a number different from 0).
Use the function clean_stdin (Credits) to clean characters that scanf read but didn't consumed (it expects a number and you give it a character, so the character stays in stdin and create the infinite loop)
I use a flag to control the loop condition, when the exit option is chosen, flag value is changed to a value that makes the condition fail
I added the main() because I need it to run the program; you can incorporate what's inside in your main. Remember to copy clean_stdin() function.
I suggest you to read some scanf documentation to understand its return value.
I suggest also to read about scanf alternatives, since it's a boring function: link 1 and link2.
Remember to format your code with the right indentation, it's a best practice.
That's how scanf works.
You asked scanf to read a single character from the input stream. The input stream originally contained 12 sequence (more likely, 12<newline> sequence). So, just like you asked it to, scanf consumed that first 1, leaving the rest in the input stream.
The next scanf continued to consume the input stream where the previous one left off.
scanf with the %c can read one character at once. '12' contains two characters '1' and '2'. So '1' will be consumed firstly by the scanf and hence,case '1': gets executed. The '2' is left in the input buffer(stdin) and it will be consumed by the next scanf with a %c.
To avoid this,you could declare opcao as an integer and use the following code:
while(1)
{
if(scanf("%d",&opcao)==0)
{
printf("Invalid input. Try again:");
scanf("%*s"); //remove the invalid input
continue;
}
if(opcao>0 && opcao<7)
break;
else
printf("invalid integer. Try again:");
}
switch(opcao) {
case 1://your code
break;
case 2://your code
break;
case 3://your code
break;
// etc...
case 6:exit(0);
}
//no need of do...while or a default case

Resources