What is the difference between the following two uses of `putchar`? - c

I was writing some code where I was getting an unexpected output in one part of the program, which in turn disrupted the entire system.
The code can be simplified and shortened to:
char ch;
printf("Enter Number: ");
while ((ch = getchar()) != '\n') {
if (ch >= 65 && ch <= 67) {
ch = 2;
}
putchar(ch);
}
As per the code above, I am trying to print a character/integer sequence of the user's choice. The numbers should remain unchanged whereas if the user enters letter A, then this should print 2.
Expected Output
Enter Number: 23-AB
23-22
Actual Output
Enter Number: 23-AB
23-☺☺
Once confronted with this problem, I decided to tweak some things and came up with the following code which worked perfectly. It uses the same approach but produces different output:
char input;
printf("\nEnter Number: ");
while ((ch = getchar()) != '\n') {
switch (toupper(ch)) { //toupper function not really needed since I am expecting the user to enter upper-case letters ONLY
case 'A': case 'B': case 'C':
printf("2");
break;
default:
putchar(ch);
}
}
Expected Output
Enter Number: 23-AB
23-22
Actual Output
Enter Number: 23-AB
23-22
I am unable to comprehend why I am failing to convert the ASCII value of the characters entered in the first code to a single integer. What is the reason for this difference in the outputs? I have simply changed the type of controlling expression, from if-statement to a switch-statement (or so I think). How can I alter the first code to provide me with the same output as the second code?

In the first version, setting ch=2; makes ch the character with ASCII value 2, not the character 2. ch=0x32; in your first version would probably work, since ASCII 50 = 0x32 is character 2. Even easier (and better, as Weather Vane points out) is ch='2';.
In your second version, you are using printf("2"). As a result, the compiler is producing the ASCII value for you when it processes the string "2", just as it would for ch='2';. Try printf("%d\n",'2'); and you should see 50.

Related

User input error when asking for a digit (switch case) C

For this program i'm asking the user to enter a digit and it returns the digit you've entered but in another language. I'm using a switch case to utilize this and for user input errors when typing a letter instead of the digits 0-9 it defaults to invalid user input, however, when I enter 10, 11, or 12 which is outside the range it prints out isa which is number 1 which shouldn't be happening. How do I make it so that if the user enters an invalid number outside the 0-9 range it also says invalid input?
Here's the code
#include <stdio.h>
int main(void) {
printf("This program will display the Filipino(Tagalog) word for a digit of your choice.\n");
printf("Enter a digit 0-9: ");
int digit = getchar();
switch(digit) {
case '0' :
printf("wala\n");
break;
case '1' :
printf("isá\n");
break;
case '2' :
printf("dalawá\n");
break;
case '3' :
printf("tatló\n");
break;
case '4' :
printf("ápat\n");
break;
case '5' :
printf("limá\n");
break;
case '6' :
printf("anim\n");
break;
case '7' :
printf("pitó\n");
break;
case '8' :
printf("waló\n");
break;
case '9' :
printf("siyám\n");
break;
default :
printf("Invalid input\n");
}
return 0;
}
Thank you!
It's because getchar() only retrieves one character from standard input. It doesn't read in an entire integer. When you pass 10, 11 or 12, your code is actually reading in 1 and leaving the second digit in standard input.
You have at least a couple of options:
Read in an integer from stdin, using scanf() instead of getchar(). Take a look at How can I get an int from stdio in C?, this should provide you all the information you need to do it this way, if you choose to do it. You will need to modify your switch-cases to use integer literals rather than character literals for the digits you want to switch on.
Alternatively, you could instead read in an entire line of input with fgets() and check to make sure it only contains 1 character, then retrieve that first character to use in the switch. This is in keeping with your intent of wanting to switch on digits, and also additionally will not fail if you pass a non-integer input to stdin, whereas if using scanf(), you need to check the return code to make sure malformed input was not given.
I recommend this approach because it is easier to make it fault-tolerant than the other one.
Echoing what the previous answerer said, getchar reads only one character from the standard input stream. Once it gets a character, it assigns it to digit.
getchar and friends return a value of type int in order to be able to return the EOF value (which is out of char range) so you know when your stream ends. So really digit is a character, just with int type for that extra little bit of range.
I'll add that getchar will leave behind any characters left behind on the input stream that were not used. If you're using this program on the command line and press 3 followed by the enter key in order to get the output tatló, the enter key will leave a '\n' character (in Linux--I'm honestly not sure if it will be '\n' or '\r' in Windows) on the standard input stream, which the first getchar does not consume.
So you could check this value with another call to getchar. Something like this:
...
printf("Enter a digit 0-9: ");
int digit = getchar();
if(getchar() != '\n') {
/*The user typed something after the initial digit, do something, like maybe assigning an invalid value to `digit`*/
digit = 'a';
}
switch(digit) {
...
The second call to getchar will return '\n' if your user entered just a single character; otherwise it will return the second character that the user entered.
This is a suitable solution to parsing a number from user input if you never intend to parse multi-digit numbers.

Ignoring scanf value in while loop

I'm learning C and I face a problem running this loop. I've wrote a while loop to prompt the user to key in the package and the quantity of it. I try to validate the input for the quantity to check is it integer or not (when a user key in a character it will prompt the user to key in again)
For the first run, everything is fine.
But when the loop runs a second time and so on, I try to key in a character for the quantity of the package, the message won't pop up to tell the user to key in again.
The value of the scanf is ignored and the value of tempQtty is equal to the previous quantity that the user keyed in.
Is there any way to fix this, or is there another way to validate the user input is integer?
Sorry for my broken English :")[input, expected input and actual input][1]
while(skip != 'x')
{
printf("\n\n%27sPACKAGE A/B/C/D ( x = skip ) : ", "");
rewind(stdin);
package = getchar();
switch (package)
{
case'x':case'X': skip = tolower(package); break;
case'A':case'a':case'B':case'b': case'C':case'c':case'D':case'd':
printf("%27sQUANTITY%21s: ", "", "");
rewind(stdin);
scanf("%d", &tempQtty); //here's the problem
while (tempQtty < 0)
{
printf("%27s(PLEASE KEY IN A CORRECT VALUE!)\n", "");
printf("%27sQUANTITY%21s: ", "", "");
rewind(stdin);
scanf("%d", &tempQtty);
}
switch (package)
{
case 'A':case 'a': qttyA = tempQtty; totalQttyA += tempQtty; break;
case 'B':case 'b': qttyB = tempQtty; totalQttyB += tempQtty; break;
case 'C':case 'c': qttyC = tempQtty; totalQttyC += tempQtty; break;
case 'D':case 'd': qttyD = tempQtty; totalQttyD += tempQtty; break;
}
break;
default:
printf("%27s(NO SUCH PACKAGE! PLEASE KEY IN AGAIN!)\n", "");
}
}
printf("\nA = %d", qttyA);
printf("\nB = %d", qttyB);
[1]: https://i.stack.imgur.com/hBD82.png
First of all, and as I mentioned in a comment, this is a surprisingly complicated problem, and you are not alone in facing it. It's not a problem with you, or with the C language; it's basically just a problem with the scanf function itself.
Partial answer:
(1) Everywhere you have things like
scanf("%d", &tempQtty);
while (tempQtty < 0)
...
that's wrong. If you ask for integer input using %d, and if the user types something non-numeric, what scanf does not do is fill in tempQtty as -1. What it does do is return a value saying it couldn't convert what you (the programmer) asked. So you want to change this to something more like
while (scanf("%d", &tempQtty) != 1)
...
(2) If the user does not type the integer you requested, and if scanf returns 0 to tell you so, there's a problem: the non-numeric input the user typed is probably still sitting on the input stream. It looks like you may have realized this, and that you're trying to get rid of the unread input by calling rewind(stdin). But that won't work; that's not the way to do it.
What you want to do is write a little "helper" function like this:
void flush_unread_input()
{
int c;
do {
c = getchar();
} while(c != EOF && c != '\n');
}
Then, wherever you've detected an error (that is, wherever scanf has returned something other than 1), instead of calling rewind(stdin), just call flush_unread_input().
A few more points:
You may have to experiment where to call flush_unread_input and where not to. You can't just blindly sprinkle it everywhere, because it basically reads and discards the rest of the line, but that it means it can also read and discard an entire line, which might sometimes be a line that you actually wanted.
There are many ways to write a flush_unread_input function. I've shown one way that should be easy to understand, but you'll often see something more compact like while((c = getchar()) != EOF && c != '\n');. (Also I haven't tested the version I've shown here.)
My answer might have suggested that scanf returns 1 if it succeeds and 0 if it fails, but it's more complicated than that. scanf actually returns the number of items successfully converted and stored, which might be more than 1 if you have a format specifier with multiple % signs in it.
There's much more to say on this topic, but I don't have time to write a longer answer this morning.
I try to key in a character for the quantity of the package, the message won't pop up to tell the user to key in again.
The value of the scanf is ignored and the value of tempQtty is equal to the previous quantity that the user keyed in.
Is there any way to fix this, or is there another way to validate the user input is integer?
There is no base for your assumption that tempQtty would receive a negative value if you entered z. In fact, the C standard mandates that tempQtty is not affected if the conversion fails. The way to fix this is to not ignore the scanf return value, which tells whether input was valid.

C : getchar() and putchar()

so I've been teaching myself C and I've come across the 'getchar()' and 'putchar()' methods from 'stdio.h'. As I understand it, 'getchar()' takes the most recent character from the text stream and stores it into a variable whilst 'putchar()' takes this variable and prints it to the terminal.
So I've written the following piece of code:
#import<stdio.h>
void main () {
printf("Enter a character and it will be repeated back to you:\n");
int c;
while (c != EOF) {
c = getchar();
printf("You entered : ");
putchar(c);
printf("\n");
}
}
and I expected it to read the keyboard input and print it to the screen one character at a time. As an example, if I were to type "home", the output would be:
You entered : h
You entered : o
You entered : m
You entered : e
but instead i get:
home
You entered : h
You entered : o
You entered : m
You entered : e
The characters are printed as im typing and then repeated afterwards. I'm not quite sure what I'm doing wrong here or if I am doing anything wrong and just don't quite grasp the concept. Can anyone explain whats happening here?
The output you're getting is expected.
Unless you make use of OS-specific functions to change the terminal settings, terminal input is only made available to the application when you enter a full line. The terminal driver buffers lines to allow you to edit before submitting it, and it echoes your input as you're typing it.
Once the line is entered, each call to getchar() retrieves one character from the line (as well as the final newline).
However, there is a bug in your program unrelated to your question. You're testing c before you assign it the first time. Also, the c != EOF test is checking the input from the previous iteration, which already tried to print that input, but you can't print EOF.
A better way to write the loop would be:
while ((c = getchar()) != EOF) {
printf("You entered : ");
putchar(c);
printf("\n");
}
Or if the combined assignment and test is confusing, you can do:
while (1) {
c = getchar();
if (c == EOF) {
break;
}
puts("You entered: ");
putchar(c);
putchar('\n');
}

Copy input from user and put it on screen

I have been going through The C Programming Language by Brian W. Kernighan and Dennis M. Ritchie and am at Character Input and Output, specifically on File Copying. The example in the book
#include <stdio.h>
int main(void)
{
int c;
c = getchar();
while (c != EOF)
{
putchar(c);
c = getchar();
}
return 0;
}
works perfectly.
But I decided to put my own spin on things and rewrite it a bit:
#define <stdio.h>
int main(void)
{
int c;
printf("Please enter a digit: ");
c = getchar();
while (c != EOF)
{
printf("The digit entered was: ");
putchar(c);
printf("Please enter a digit: ");
c = getchar();
}
return 0;
}
After compiling and executing, the result of my code is:
Please enter a digit: 9
The digit entered was: 9Please enter a digit: The digit entered was:
Please enter a digit: *cursor is here*
The input should be:
Please enter a digit: 9
The digit entered was: 9
Please enter a digit: *the cursor should be here*
Also, I have a little problem understanding EOF. It would be great if someone could help me with these issues.
Thank you!
Most 'terminals' do not send keyboard input to the program 'one key at at time'. Rather, the terminal will wait for the enter key, and then send all keys pressed (up to that point) to the target program. Hence, the question code suffers from getting newlines \n as input, as well as digits.
The code below throws away all non-digit values (but also allows for the EOF value):
#include <stdio.h>
#include <ctype.h>
int main(void)
{
int c;
do {
c=0;
/* Get user input */
printf("Please enter a digit: ");
while(!isdigit(c) && EOF != c)
c = getchar();
/* Produce output. */
if(c == EOF)
printf("\n");
else
printf("The digit entered was: %c\n", c);
} while (c != EOF);
return 0;
}
Compile the above (Linux GCC example: gcc -Wall -o test *.c)
Then execute: (Linux example: ./test)
Please enter a digit: 5
The digit entered was: 5
Please enter a digit: 6
The digit entered was: 6
Please enter a digit: <CTRL-D>
<CTRL-D> usually generates an EOF condition.
Because the ENTER value "\n" (ASCII value 10) will be get by
getchar(c);
so it will do second time of
printf("The digit entered was: ");
printf("Please enter a digit: ");
Well, it's the trouble about the new-line character that you feed the standard input with while handing your piece into the console screen.
Let me ask you this:
With the code that you have said to work perfectly, you probably have tried some input like "Hello!" let's say, or maybe just a single character like "9" as in your example. You have typed down 'H' then 'e' then 'l' ... then '!' and then hit the enter-key, or just '9' and then hit the enter-key.
After that, you had the following on your screen:
Hello!
Hello!
_
The last underscore there is for indicating the flashing cursor. My question is: Why is it there? Why is it not right next to the last '!'?
Same story with the 9, this would be the things on your screen:
9
9
_
Well, here's why: It is because your programme has printed one more character that you cannot see directly, a new-line character '\n'. Proof: If it hadn't printed that, the underscore would flash next to the '!' or '9'.
When you hit your enter-key, you feed the standard input with a new-line character '\n' in addition to whatever you had typed down so far in that session. Standard input gets fed with all that and getchar(); consumes them one by one.
In your code which doesn't work as you had expected, you feed the standard input with '9' '\n', getchar(); first gets the '9' and then '\n', and then it looks for more, but there isn't any more. Only then (when there isn't more) it asks from you for more.
And that's the story...
To get what you were expecting, you should do something else, I won't tell you that directly, it's a good exercise. I can hint you that you should be using another while loop within the one you already have with a condition checking for a '\n' encounter.
EOF is just a special character, or rather a value indicating a special case of being at the End Of File. For standard input, I guess it can be issued with the CTRL + D key combination on Linux, it is CTRL + Z on Windows. Using that combination and then hitting enter should get you out of that outer loop.
You're being tripped up by a trailing newline in your input; when you type 9 and hit Enter, the input stream that your code reads from will contain the encodings for two characters, the 9 and a newline (in ASCII, it would be the sequence of values [57,10]) . Here's how it breaks down:
Code prompts you to enter a digit
You type 9 and hit Enter
Input stream now contains the characters {'9', '\n'};
getchar returns the next available character from the input stream, which is '9'
'9' is not equal to EOF, so you print the digit and prompt for the next character
getchar returns the next available character from the input stream, which is '\n'
'\n' is not equal to EOF, so you print the character and prompt for the next character
The input stream is now empty, so getchar blocks until you type something else.
You can fix this relatively easily:
#include <ctype.h>
...
while (c != EOF)
{
printf("The digit entered was: ");
putchar(c);
printf("Please enter a digit: ");
do
{
c = getchar();
} while ( isspace( c ));
}
That last little do loop will read characters from the input stream until it sees something that isn't a newline or other whitespace character. You can add an additional check to make sure the character entered really was a digit [0-9]:
while (c != EOF)
{
printf("The digit entered was: ");
putchar(c);
do
{
printf("Please enter a digit: ");
do
{
c = getchar();
} while ( isspace( c ));
if ( !isdigit( c ))
printf( "%c is not a digit!\n" );
} while ( !isdigit( c ));
}
Now, something to be aware of; what you're storing in c is not the value 9, but the encoding for the character '9', which in ASCII is the integer value 57. If you want to store the value 9 in c, you'll have to do something different.

Menu that accepts single character in C language

I want to create a simple menu in C program that accepts single character. The menu will be like this:
[S]how
[E]xit
If the user enter '1','s' or 'S' the program will print "Hello" and prompt again for the input
else if the user enters '2',E or 'E' the program ends.
else it should print "invalid input" and prompt again.
I am able to create the program but the problem is that when user enters 12, 13, 14, 15, 16.....so on starting with 1, it shows Hello and same for other options.
My code is:
#include <stdio.h>
void clearBuffer();
int main() {
int i = 0;
char selection;
do
{
printf("\t1. [S]how\n");
printf("\t2. [E]xit\n");
printf("Enter your selection from the number or character noted above: ");
scanf("%s", &selection);
clearBuffer();
if (selection == '1' || selection == 's' || selection == 'S')
printf("Hello");
else if (selection == '2' || selection == 'E' || selection == 'x')
i = 0;
} while(i != 0);
}
void clearBuffer()
{
while(getchar() != '\n');
}
If you are going to receive only one character consider replacing the scanf() function for getchar() function:
printf("Enter your selection from the number or character noted above: ");
selection = getchar();
You could use strlen, which is part of the standard C library, to check the length of the string returned by scanf and reject entries longer than one character:
if (strlen(selection) > 1)
{
printf("Invalid selection.");
}
Alternatively, I think you could use getchar() to accept just a single character from the user, which means they wouldn't have to press enter.
As already mentioned, you should use getchar() if you only want one character. If you still want to use scanf() for whatever reason you may have, the correct format is "%c", not "%s".
I would also suggest that if you are looking for a single character, the if block looks a little "busy" (read, awkward) ... a switch would be a cleaner, more elegant way to do it (IMHO).
/* something like this ... */
switch ( selection ) {
case '1':
case 's':
case 'S':
printf ( "Hello\n" );
break;
case '2':
case 'e':
case 'E':
i = 0;
break;
}
Other couple of things ... if you don't care about the case of the character being read (that is, 's' and 'S' will do the same thing), you can convert selection to uppercase before your if-block or switch-block using toupper(). Also, and this is just a style suggestion, don't use i for your exit flag. General practice is to use things like i and j for counters or indexes - you could use something like quit_now or user_done which would convey more precisely what the variable means.

Resources