Switch Case working differently - c

Consider two codes. Why are they giving different outputs though same value hass been assigned to i ,'i' being a char in both the codes.
first code-->
(here value is assigned to i directly)
void main()
{
char i=3;
clrscr();
switch(i)
{
default : printf("\nHi..\n");
break;
case 1:printf("\na");
break;
case 2:printf("\nb\n");
break;
case 3:printf("\nc");
break;
}
}
second using printf-scanf--->
void main()
{
char i;
printf("ENTER i");
scanf("%c",&i);
clrscr();
switch(i)
{
default : printf("\nHi..\n");
break;
case 1:printf("\n\na");
break;
case 2:printf("\nb\n");
break;
case 3:printf("\nc");
break;
}
}
in the second code when i m giving 3 as input, i get "Hi.." as output. What makes the two codes work differently..??

In the first you're using
char i = 3
But when you use scanf you essentially use:
char i = '3'
These two contain different values
See the following ASCII http://www.asciitable.com/

After reading the character from stdin:
scanf("%c",&i);
i will contain the ASCII code of 3 (51) and not the value 3, leading to taking the default branch of switch.
The solution is declaring your variable as int and using
scanf("%d",&i);
to read it.
In the first example you assigned to i the integer value 3, which is not the same as assigning the character '3'. In C, when you assign a value to a char variable that value would represent a code specific to a certain character (considering a standard).
In the second example the scanf function read a character from stdin, which was interpreted as a character due to the use of %c, and assigned to the given variable the code specific to the read character.

It is not related to the switch statement, but to the scanf function.
Read its documentation ie scanf(3) man page. See also this answer to a very related question.
Notice that the char '3' is not encoded as 3, but as 51 in ASCII
Learn to enable all warnings and debugging info (e.g. compile using gcc -Wall -g) and learn to use the debugger (i.e. gdb)

Change your code to
char i -> int i;
scanf("%c",&i) -> scanf(" %d",&i);

Related

Why program is giving unexpected output?

I'm stuck in a problem given in a book. The problem is -
The prototypical Internet newbie is a fellow name B1FF,who has a unique way of wriring messages.Here’s a typical B1FF communique.:
H3Y DUD3, C 15 R1LLY C00L
Write a “B1FF filter” that reads a message entered by the user and translates it into B1FF-speak:
Enter message: Hey dude, C is rilly cool
In B1FF-speak : H3Y DUD3, C 15 R1LLY C00L
Your program should convert the message to upper-case letters,substitute digits for certain letters (A=4,B=8,E=3,I=1,O=0,S=5).
My Program-
#include<stdio.h>
int main()
{
char arr[50]={0},ch[50]={0};
int i=0;
printf("\nenter the sentence : ");
while(arr[i-1]!='\n')
{
scanf("%c",&arr[i]);
i++;
}
i=0;
while(arr[i]!='\n')
{
if(arr[i]=='e')
ch[i]='3';
if(arr[i]==('A'||'a') )
ch[i]='4';
if(arr[i]==('B'||'b'))
ch[i]='8';
if(arr[i]==('I'||'i'))
ch[i]='1';
if(arr[i]==('o'||'O'))
ch[i]='0';
if(arr[i]==('S'||'s'))
ch[i]='5';
else ch[i]=arr[i]-32;
i++;
}
ch[i]='\n';
i=0;
printf("\nIn B1FF-SPEAK : ");
while(ch[i]!='\n')
{
printf("%c",ch[i]);
i++;
}
printf("\n");
return 0;
}
OUTPUT OF THE PROGRAM-
I don't understand why the program is not converting the alphabets and why scanf() is not accepting space as a character ?
First and foremost, you cannot chain the logical OR operator like
if(arr[i]==('A'||'a') )
and get what you're expecting, because this resolves to an always TRUE condition. [('A'||'a') evaluates to TRUE]
You have to use
if ( (arr[i]=='A') || (arr[i] =='a'))
That said,
ch[i]=='8';, ch[i]==1; are basically empty statements. You're comparing and discarding the comparison result. If you want assignment, you need to use =.
the else ch[i]=arr[i]-32; only binds with the previous if statement, no the whole if chains. You can either make use of switch case or if-else if-else constructs to take care of that part.
you did not handle whitespaces separately.
To elaborate, due to the second point above, you code basically reduces to
while(arr[i]!='\n')
{
if(arr[i]==('S'||'s')) //always false
ch[i]='5';
else ch[i]=arr[i]-32; //always TRUE
i++;
}
which is just a poor attempt to convert lowercase to UPPERCASE. In case a non-alpha input is there in the string, the code will blow up.
That said, regarding the
why scanf() is not accepting space as a character?
part, scanf() perfectly accepts a space as an input with %c, it's you just convert it no NUL (null) by blindly subtracting 32 from a space which has an ASCII value of decimal 32. A NUL is non printable, and does not appear in the output.
Some recommendations:
Don't use lots of little calls to scanf("%c"...). Use fgets() (manpage). fgets reads in a whole line from input, stores it in your buffer (including the newline), and sticks a '\0' byte at the end of it so you know how long the string is.
use toupper() (manpage). It takes an arbitrary character as input. If the input is a lower case letter, then the output is the upper-case version of that letter. Otherwise, the output is the same as the input.
Update the array in-place. You don't need two arrays. Read the array with fgets(), loop over it with your translation logic, updating each character as you go, then write the array out with fputs().
Learn about switch statements. A switch statement will make your code more compact and easier to read. You need one case for every letter->number transform, and a default case for everything else.
c = toUpper(c);
switch (c) {
case 'A': c = '4'; break;
case 'B': c = '8'; break;
....
default: break;
}

c optarg atoi with no args

Consider the following code:
int number;
while((w = getopt(argc, argv, "n:s:")) != -1) {
switch (w){
case 'n': {
opfile->filename = optarg;
}break;
case 's': {
number = atoi(optarg);
}break;
}
}
Now, when I leave both options or the option s blank, for example I start my program with no command line args, then the number variable still gets a random value.
What am I missing here? Some if-statement in the case of s? Specifically, I want to cover the case where the user doesn't assign a specific value/option to s in the command line arguments.
When there is no 's' option passed to the program, the case 's' branch is not executed at all, and nothing else sets number to a value, which means that subsequent reads trigger undefined behavior. (This is potentially much worse than just giving you a random value when you read from it later. It's a must-fix bug.)
But because nothing else touches number, it will be enough to change
int number;
to
int number = 0;
or whatever else you want your default to be.
(By the way, you should really be using strtol instead of atoi, because atoi ignores syntax errors.)

Ending a loop when fscanf reads a certain value from a text file

I'm trying to write a program that reads a character and a float from a text file and then saves these values to a variable.
The text file is formatted in this manner:
S 15.24
G 28.00
S 56.90
H 90.00
0
I'm attempting to have the character be read and then have it run through a switch to do a few calculations based on which character comes before the float(all S values are grouped together, all G values are grouped together, etc)
To have it go through all the lines available, I'm using a while loop that terminates when the read character reaches the 0 at the end of the list.
Just for testing purposes I'm having the program print "Done" when it exits the loop. However when I run the program, it runs through every character and prints it properly to the terminal until its printed the values before 0. once it reaches the 0, the program doesn't do anything else, but it doesn't print "Done" like I assumed it should.
This is the code I'm using:
int main()
{
int s_num,g_num,h_num,S,H,G,n_total;
float amount,s_total,s_sum,g_sum,h_sum;
char char_name;
FILE*Input;
Input = fopen("Input.txt","r");
FILE*Output;
Output = fopen("Output.txt","w+");
char_name = 1; //Just using 1 as a way to make the while loop occure
while(char_name != '0')
{
fscanf(Input,"%c%f",&char_name,&amount);
switch(char_name)
{
case 'S':
printf("S,%f\n",amount);
break;
case 'G':
printf("G,%f\n",amount);
break;
case 'H':
printf("H,%f\n",amount);
break;
}
}
printf("done");
return 0;
}
(disregard the unused values, those are to be used in the actual program)
What changes would I need to make to get the loop to terminate once it reaches 0?
The following code:
fscanf(Input,"%c%f",&char_name,&amount);
will fail to read a float upon hitting the last data line in the file. The switch statement is not needed. Use an if statement to check if the first char is '0' and either break or read the floating point number and print both the character and number.
while (TRUE)
{
fscanf(Input,"%c",&char_name);
if (char_name == '0')
break;
fscanf(Input,"%f",&amount);
printf("%c,%f\n",char_name,amount);
}
Using fgets() and then parsing the line is the best way to go. But using fscanf(), recommend:
Change format so white-space is ignored. otherwise '%c' will take on white-space values
// fscanf(Input,"%c%f",&char_name,&amount);
fscanf(Input," %c%f",&char_name,&amount); // add space
Check the return value from fscanf(). do not use values char_name,amount unless the return value from fscanf() indicates those values were indeed filled.
int cnt = fscanf(Input," %c%f",&char_name,&amount);
switch(cnt) {
case 1: Handle_OnlyCharName(); break; // Candidate only "0" line
case 2: Handle_BothCharNameAndAmount(); break; // OP's switch(char_name)
case EOF: Handle_IOErrorOrEndOfFile(); break; // No more data
default: NeverShouldGetHere();
}

why my case give me the errors?Why i can't put variables in switch cases?

I have 2 errors while trying to put a variable in switch case:
#include <stdio.h>
int main(int argc, char *argv[]) {
float conversie = 0;
float leu = 1;
float usd = 3.6 * leu;
float eur = 4.4 * leu;
float aur = 139 * leu;
float suma;
float valoare;
char tipmoneda;
printf("introdu moneda pe care vrei sa o schimbi:");
scanf("%c\n", &tipmoneda);
switch (tipmoneda) {
case 'usd':
default:
break;
}
}
These are the errors:
Untitled.c:14:8: warning: multi-character character constant [-Wmultichar] case 'usd': ^
Untitled.c:14:8: warning: overflow converting case value to switch condition type (7697252 to 100) [-Wswitch]
2 warnings generated.
If you are entering "usd" on the input line, this won't work; scanf will only read and store the leading 'u' character into tipmoneda (which won't match the multi-character constant 'usd'). Also, to be safe, you should put a leading blank space in the scanf control string:
scanf( " %c", &tipmoneda );
This will tell scanf to skip over any leading whitespace.
What you can do is simply enter 'u' for usd, 'e' for eur, 'a' for aur, and then switch as follows:
switch( tipmodena )
{
case 'u' :
// process for usd
break;
case 'e':
// process for eur
break;
case 'a':
// process for aur
break;
default:
// unrecognized option
break;
}
Edit
If you really want to enter "usd" instead of "u", you could do something like the following:
#include <ctype.h> // needed for the tolower call below
...
char tipmoneda[4] = {0}; // read tipmoneda as a 3-character string instead of
// a single char
...
scanf( "%3s", tipmoneda ); // note conversion specifier
switch( tolower( tipmoneda[0] )) // switch on lowercase form of first letter
{
// same cases as above
}
The tolower call will convert the argument to lower case, so you could enter "usd", "USD", "Usd", etc., and still have this work. Note that if you enter a string that's more than 3 characters long, the remaining characters will remain in the input stream, potentially fouling up the next scanf call.
C switch case only works with integer or single character types.
'usd' is a multi character integer constant (with portability problems), yet tipmodena is simply 1 char. A new approach is needed.
The below forms the case constants at compile time from 3 char. At run-time the string read forms the integer to switch on in the same fashion.
[Edit]
Reworked hash function to cope with signed char, overflow shifting of signed char and potential 16-bit int.
#include <stdio.h>
#include <string.h>
#define HASH(a,b,c) \
((unsigned char)(a)*0x10000u + (unsigned char)(b)*0x100u + (unsigned char)(c))
int main(void) {
char denom[4] = { 0 };
while (scanf("%3s", denom) == 1) {
switch (HASH(denom[0],denom[1],denom[2])) {
case HASH('u', 's', 'd'):
puts("usd");
break;
case HASH('e', 'u', 'r'):
puts("eur");
break;
case HASH('a', 'u', 'r'):
puts("aur");
break;
default:
printf("Unknown '%s'\n", denom);
}
memset(denom, 0, sizeof denom);
}
return 0;
}
This is simply part of the language definition. You may only use constant expressions for your case values. Examples include numeric and character literals as well as previously-defined constants.
Technically, 'usd' is a multi-character constant, which is interpreted as a numeric value. See Multiple characters in a character constant for reference.
This is generally not an advisable practice for portable code.
This also appears to conflict with the inferred intentions of the poster. It appears that the poster is attempting to read a currency as a string and calculate totals based on that input. Currently, this code will read a single character and switch on that value.

C switch statement , variable error(For a calculator program source code)

Greetings , today when I try something new(Concept and style that suddenly pop out in my mind) , I encountered a few problems which I don't understand why it happened.
The Code
// This program would get two numbers from user , and request for an arithmetic operator , and carry out arithmetic.
#include <stdio.h>
int main(void)
{
int fNum;
int sNum;
int status = 1;
int operator;
int ans;
printf("Enter the first operand :");
while(scanf("%d" , &fNum) == 0)
;
printf("Please enter the second operand :");
while(scanf("%d" , &sNum) == 0)
;
printf("Which operator you wanted to use\n");
printf("1 for +\n2 for -\n");
while(status)
{
scanf("%d" , &operator);
status = 0;
switch(operator)
{
case 1:
ans = fNum + sNum;
break;
case 2:
ans = fNum - sNum;
break;
default:
status = 1;
}
}
printf("The answer is %d\n" , ans);
return 0;
}
My Analysis and Question
First part :
1.)There's one thing I don't understand , when I try to run this code , I get an warning message from the compiler , "C:\Users\Znet\Documents\Pelles C Projects\Test1\Test.c(10): warning #2229: Local 'ans' is potentially used without being initialized." , but of course I still can run the program since it's not an error message.
2.)I just wonder why this warning message occured , out of curiosity , instead of just declaring the variable ans , I initialize it with an integer value(0 or any whole number) , and the warning message just gone.What causes this to happen??Is it because the variable ans is used in a switch statement that's why we should assign a value to it before using it?Because all the time (when i'm coding other program) I don't even initialize a variable with a value before using it to store a value evaluated by an arithmetic expression.
Second part :
1.)The problem arouse inside the switch statement , when the program is asking user to enter either number 1 or 2 for the arithmetic sign.
2.)If i enter an integer not within 1 and 2 , the program will not proceed but instead waited me to reenter the correct value , which is my main intention.
3.)But the thing is , if the value I enter is not an integer but instead a character , the program would just freeze , the cursor is still blinking but it's not respond to my keyboard input.In the end , I have to kill the program in order to close it.
4.)I know there're many ways for me to code this kind of program , but I just wonder why in this code , this situation would happened??
Thanks for reading my problem , hope to get explanations and knowledges from you guys :)
First question:
The compiler is detecting that ans is only getting a value assigned to it conditionally (for two specific cases in your switch statement). Some compilers warn about this and others do not. As a rule, it is always good practise to initialize any variable you create.
Second question:
This question has been answered many times before - see infinite scanf loop. The problem is that scanf only accepts an integer in this case. As mentioned in this link "Any character that doesn't match the format string causes it to stop scanning and leaves the invalid character still in the buffer." This is causing your while loop to never exit. If you are interested in more details, the link mentioned here should really help you.
Q: "warning #2229: Local 'ans' is potentially used without being initialized."
A: This means that ans can contain any value upon declaration (since stack variables aren't nulled out on declaration) - and since the compiler didn't see programming logic that guarantees that the variable is set when printed - it throws this warning. Doing int ans = 0; will remove it.
Q: If the value I enter is not an integer but instead a character , the program would just freeze , the cursor is still blinking but it's not respond to my keyboard input.In the end , I have to kill the program in order to close it.
A
.
do {
printf("Which operator you wanted to use\n");
printf("1 for +\n2 for -\n");
} while ( scanf("%d", &operator) != 1 );
scanf returns the amount of matches --- if it doesn't match an integer, it will return 0. Therefore; Check the return value.
First Part
Compilers can give warning when you use a variable without having it explicitly initialized. This is because uninitialized variables can create nasty bugs in your code. For example consider the following code segment.
int main()
{
/* NOTE: 'f' is uninitialized */
int f, n;
printf ("\nn : ");
scanf ("%d", &n);
while (n)
f = f * n--;
printf ("\nfactorial = %d", f);
return 0;
}
In the above code the output of the program in undefined. f is a local variable (automatic), so when the main starts to execute f can have any value, ie garbage, and the factorial computation relies on the initial value of f. So in such a case uninitialized variable will lead you to a catastrophe. To solve it you need to do int f = 1; and you get the correct output. This is not an error, but can be a logical error, so the compilers help you with it, that you might not accidentally left a variable uninitialized. In your case it is not required to be initialized, so you can simply do ans = 0; stop the warning.
Second Part
A character and an integer is interpreted differently. For example 12 are two characters, and also we can say that it is an integer. To input it as an integer you should use "%d" and as characters scanf ("%c%c",&var1, var2); as there are two characters. When you enter a character when the format string is "%d" it will detect that the input is not an integer (it is a character), and will stop at that moment and will return. Nothing will be stored in the operator variable. The scanf returns the number of components it has read. In this case when it encounters that you have entered a character it would return 0 as it has not read in the input and has stopped. But when you input an integer it will read it correctly in operator and return 1. So keep a check like:
/* Ask for input while the user does not input a
* valid integer.
*/
while (scanf ("%d", &operator) != 1)
{
/* Body is entered whenever an invalid integer is entered */
/* Your message */
}
/* When the user inputs a valid integer the condition
* in 'while' loop is false and program continues
*/

Resources