I've been writing a simple program to check if input letter is a vowel, and my code doesn't work.
The program should take characters as input one by one until % is entered, which will make it exit. It checks if input chars are vowels, and prints the result. Also it reports an error if input is not a letter.
The problem is, it breaks out of the loop on the second step.
Thank you for help, in advance.
PS Sorry, didn't write that there's no error message, it just breaks out of the loop.
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
int main(void)
{
char processed='q';
while(processed != '%')
{
printf("Enter letter to check if it's a vowel, %% to quit.\n");
char input = getchar();
processed = tolower(input);
printf("%c\n", processed);
if (processed == '%')
break;
if (processed < 'a' || processed > 'z')
{
fprintf(stderr, "Input should be a letter\n");
exit(1);
}
switch(processed)
{
case 'a':
case 'e':
case 'i':
case 'o':
case 'u':
case 'y':
printf ("Vowel\n");
break;
default:
printf ("Non-vowel\n");
}
}
exit(0);
}
Presumably you're entering a character and then hitting [ENTER]. So, in actuality you are entering two characters -- the letter you typed and a line feed (\n). The second time through the loop you get the line feed and find that it's not a letter, so you hit the error case. Perhaps you want to add something like:
if (processed == '\n') {
continue;
}
Someone else mentioned that you're hitting enter after each letter of input, and thus sending a newline ('\n') into your program. Since your program doesn't have a case to handle that, it isn't working right.
You could add code to handle the newline, but using scanf would be easier. Specifically, if you replaced
char indent = getchar();
with
char indent;
scanf("%c\n", &indent);
scanf() would handle the newline and just return back the letters you're interested in.
And you should check scanf()'s return value for errors, of course.
Related
I needed to make a program to count the number of words, sentences and letters by getting an input from the user. The program works perfectly until the input i give is multi-lined. If the input is longer than the text that can fit in the terminal window, the program starts to ignore all full stops/question marks/exclamation marks. I don't know why, and I'd like some help. This doesn't happen if the text can fit in one line of the terminal window. I also printed every character when it's read by the program, but that also ignores all full stops/question marks/ exclamation marks. None of those characters get printed. For clarification, a sentence is just the number of full stops/question marks/ exclamation marks, number of words is just the number of spaces in the text plus 1. Here is my code:
#include <stdio.h>
#include <ctype.h> //for the isalpha() function
#include <cs50.h> //for the get_string() function
int main(void)
{
int sentences = 0, letters = 0;
int words = 1;
char character;
string text = get_string("Enter Text: \n");
char x = 0;
while (text[x] != '\0')
{
character = text[x];
switch (character)
{
case ' ':
words++;
break;
case '.':
sentences++;
break;
case '?':
sentences++;
break;
case '!':
sentences++;
break;
default:
if (isalpha(character))
{
letters++;
}
}
x++;
}
printf("\n");
printf("WORDS: %d, LETTERS: %d, SENTENCES: %d\n", words, letters, sentences);
}
I'm fairly new to c, but I have around a year of experience in Python. Thank you for your time.
I’m going to make a few suggestions.
First, don’t use get_string1 (or scanf, or fgets). For a filter program like this, you don’t actually need to store the input in order to process it; use getchar (or fgetc) to read one character at a time and loop based on that:
int c; // getchar returns int, not char
...
puts( "Enter Text:" );
while ( ( c = getchar() ) != EOF )
{
// test c instead of text[x]
}
This approach will handle input of any length (such as if you redirect a file as your input), and it avoids the potential overflow issue Weather Vane identified in the comments. The downside is that you’ll have to manually signal EOF from the console for interactive input (using either Ctrl-z or Ctrl-d depending on your platform).
You can collapse some of your tests in your switch, such as
case '.' : // Each of these cases "falls through"
case '!' : // to the following case.
case '?' :
words++; // the end of a sentence is also the end of a word
sentences++;
break;
You’ll want to add cases to handle newlines and tabs:
case ' ' :
case '\n' :
case '\t' :
words++;
break;
except you don’t want to bump the words counter for repeating whitespace characters, or if the previous non-whitespace character was a punctuation character. So you’ll want an extra variable to track the class of the previously-read character:
enum {NONE, TEXT, PUNCT, WHITE} class = NONE;
...
while ( ( c = getchar() ) != EOF )
{
switch( c )
{
case ' ' :
case '\n' :
case '\t' :
if ( class == TEXT )
words++;
class = WHITE;
break;
case '.' :
case '!' :
case '?' :
if ( class == TEXT ) // Don’t bump the word counter
words++; // if the previous character was
// was whitespace or .! ?
if ( class != PUNCT ) // Don’t bump the sentence counter
sentences++; // for repeating punctuation
class = PUNCT;
break;
...
}
}
There will still be weird corner cases where this won’t give a completely accurate count, but should be good enough for most input.
You should be able to figure out the rest from there.
The CS50 string handling and I/O routines like get_string are pretty slick, but they grossly misrepresent how C actually does things. The string typedef is especially egregious because what it aliases is not a string. Just be aware these tools will not be available outside the CS50 curriculum, so don’t become too reliant on them.
I write a piece of code to help myself understand how things work when stdin and stdout involved.
Here is my code:
#include<stdio.h>
#include<stdlib.h>
void prompt(){
int i=0;
printf("please select:\n"); //string1
printf("1.input\n2.print\n3.Exit\n"); //string2
scanf("%d",&i);
switch(i){
case 1:
printf("Data input!\n");
break;
case 2:
printf("data printed!\n");
break;
case 3:
exit(0);
case 10:
printf("Newline detected!"); //string3
default:
printf("Please input a valid number!(1-3)"); //string4
}
}
int main()
{
while(1)
prompt();
return 0;
}
What I expect this code to do is:
prompt me for input;
then I enter a number 4,which is out of the cases;
so the default case will be matched and the string 'Please input a valid...'(string 4) will be printed.
as there is still a newline character left in the stdin buffer, in the next loop,
the variable 'i' will automatically get a newline character, which is 10 in ACSII
So after printing out 'please select..1.input\n2.print....',, a string 'Newline detected!'(string 3) will be immediately printed out.
And then the code goes into the third loop, and prompt me for input....
But that never happen. I cannot see any 'Newline detected!" in the output even if I enter a number 4, which is out of the cases.
Anyone can elaborate how this snippet work exactly?
By the way: I originally assume that when there is something printed in the stdout, the stdin buffer will be flushed automatically. But some fact proved me wrong. Is my assumption true or false?
Also, when I enter a character(for example, a g) rather than a number, I got string 1, string 2, sring 4 printed in the screen infinitly. Why is that?
#######################################################################3
Edit: After viewing the answer, I make another snippet, to help understand.
#include<stdio.h>
#include<stdlib.h>
void output();
int main()
{
int i;
printf("Enter a number here:\n");
scanf("%d",&i);
output();
return 0;
}
void output(){
char a;
if (scanf("%c",&a)!=1){
printf("scanf error!!");
exit(1);
}
switch(a){
case 'a':
printf("an char a is entered");
break;
case 'b':
printf("an char b is entered");
break;
default:
printf("%c",a);
printf("other thing is entered");
}
}
whatever you enter the first time the program prompt you, you will never get your second prompt. For example, when the program prompt you for the first time, if you enter a number 4, then you will get a newline and a string "other thing is entered" printed on you screen. Why is that?
as there is still a newline character left in the stdin buffer, in the next loop, the variable 'i' will automatically get a newline character, which is 10 in ACSII
So after printing out 'please select..1.input\n2.print....',, a string 'Newline detected!'(string 3) will be immediately printed out.
That is not correct. When you use
scanf("%d",&i);
all white spaces are ignored, which includes the newline.
And then the code goes into the third loop, and prompt me for input....
Now you know it stays in the second loop, waiting for a number to be entered.
I originally assume that when there is something printed in the stdout, the stdin buffer will be flushed automatically. But some fact proved me wrong. Is my assumption true or false?
That assumption is false. stdout is flushed when you wait for input from stdin.
Also, when I enter a character(for example, a g) rather than a number, I got string 1, string 2, sring 4 printed in the screen infinitly. Why is that?
That's because the program is not able to read the character when it executes the line:
scanf("%d",&i);
The character stays in the input stream. You don't have any code to remove that character from the input stream. That makes the program stay in an infinite loop.
as there is still a newline character left in the stdin buffer, in the
next loop, the variable 'i' will automatically get a newline
character, which is 10 in ACSII
Wrong. %d will get a integer until a newline or a space is encountered and the newline character in the buffer will not be consumed by the next scanf()
So always check the return value of scanf()
if(scanf("%d",&i) != 1)
{
printf("scanf failed\n");
return 1;
}
As a side note:
case 10:
printf("Newline detected!");
There is a a break missing in this case.
Addressing the second program in the question, here's a mildly revised version. It prints more information, and uses strict prototypes.
#include <stdio.h>
#include <stdlib.h>
void output(void);
int main(void)
{
int i;
printf("Enter a number here:\n");
if (scanf("%d", &i) == 1)
printf("Read %d OK\n", i);
output();
return 0;
}
void output(void)
{
char a;
if (scanf("%c", &a) != 1)
{
printf("scanf error!!");
exit(1);
}
printf("Character %d (%c) entered\n", a, a);
switch (a)
{
case 'a':
printf("an char a is entered\n");
break;
case 'b':
printf("an char b is entered\n");
break;
default:
printf("%c", a);
printf("other thing is entered\n");
break;
}
}
Example runs:
$ ./stdin
Enter a number here:
23499911
Read 23499911 OK
Character 10 (
) entered
other thing is entered
$ ./stdin
Enter a number here:
2A
Read 2 OK
Character 65 (A) entered
Aother thing is entered
$ ./stdin
Enter a number here:
19b
Read 19 OK
Character 98 (b) entered
an char b is entered
$ ./stdin
Enter a number here:
999a
Read 999 OK
Character 97 (a) entered
an char a is entered
$
Note that in the first run, the stray character is the newline after the second 1 digit, character code 10. This is what you should get.
Do make sure your output print operations end with a newline (so that it appears in a timely manner). If you don't, your output may be held up indefinitely.
Do you mean that the scanf() function will not strip the newline character in the stdin buffer?
The scanf("%d", &i) certainly doesn't. The scanf("%c", &a) does. When scanf() completes a conversion, it puts the character that is not part of the conversion back into the input stream ready for the next input operation. So, it doesn't matter whether there's a space, a letter or a newline after the number, that character is left ready for the next input operation to read it. Most scanf() operations skip leading white space. There are three exceptions: %c, %n and %[…] (scansets). They do not skip leading white space.
I'm trying to write a simple menu in C.
This is my proposed code:
while (end == 0) {
printf("Main menu\n");
printf("=========\n");
printf("1) Option 1.\n");
printf("2) Option 2.\n");
printf("3) Option 3.\n");
printf("4) Option 4.\n");
printf("0) Exit");
printf("\n");
printf("Choose an option: ");
fgets(&menu_option,1,stdin);
switch (menu_option) {
case '0': end = 1; break;
case '1': option1(); break;
case '2': option2(); break;
case '3': option3(); break;
case '4': option4();
}
}
However, when executing this code, the loop never ends.
What's wrong?
Thank you.
EDIT: when I say "the loop never ends", I want to say that I can't write any option because the menu appears again and again.
From fgets
The fgets() function shall read bytes from stream into the array pointed to by s, until n-1 bytes are read, or a is read and transferred to s, or an end-of-file condition is encountered. The string is then terminated with a null byte.
Since you give a length of 1, n-1 will be 0 and so your input is never stored in menu_option. Change it to a char array
char menu_option[10];
// ...
fgets(menu_option, sizeof(menu_option), stdin);
switch (menu_option[0]) {
case '0': end = 1; break;
case '1': option1(); break;
case '2': option2(); break;
case '3': option3(); break;
case '4': option4();
}
Update:
It is necessary to use char arrays, because you need enough space to store the input. The minimum size for a buffer is two characters, e.g. char buf[2], because fgets stores your input plus a terminating NUL character.
The loop iterates twice or even more times, because when you input e.g. 1 return or 1 3 2 return, it will first return 1, then 3, 2 and finally return. If you want to read the whole line and use the first digit only, your buffer must be larger than just 2, like e.g. 10 or even 256.
fgets reads a string instead of character. The statement
fgets(&menu_option,1,stdin);
Will store a string to menu_option but to store a string you need a size at least 2 bytes.
char menu_option[2];
...
fgets(menu_option,2,stdin);
int c;
while((c = getchar()) != '\n' && c != EOF); // This will be needed to flush your input buffer
switch (menu_option[0]) {
...
...
}
From: http://www.cplusplus.com/reference/cstdio/fgets/
fgets
char * fgets ( char * str, int num, FILE * stream );
Get string from stream.
Reads characters from stream and stores them as a C
string into str until (num-1) characters have been read or either a
newline or the end-of-file is reached, whichever happens first.
A newline character makes fgets stop reading, but it is considered a
valid character by the function and included in the string copied to
str.
A terminating null character is automatically appended after the
characters copied to str.
Since you have specified 1 for the number, 0 bytes are read, and the only thing that happens is that a terminating null character is appended. The result is an infinite loop in which nothing is read.
Since in the comments you expressed dislike for using strings, here's alternative implementation with minimal changes to the question code:
while (end == 0) {
printf("...menu print snipped...\n");
int ch = getchar();
switch (ch) {
case EOF: // end of file or error, fall through to exit option
case '0': end = 1; break;
case '1': option1(); break;
case '2': option2(); break;
case '3': option3(); break;
case '4': option4();
// default: // add error message?
}
// ignore any extra chars in the same line
while ((ch = getchar() != '\n') {
// test for end of file and set end to true
if (ch == EOF) {
end = 1;
break;
}
}
}
Note the extra loop, which will read and discard rest of the input line. Without it, user can enter several options on one line, which is probably not desirable. Also note, if the option functions read more user input, consider how you handle long lines then. For example move the extra loop to be before switch (and add another variable to read discarded chars). Actually you should probably put the extra loop to it's own function discard_until_newline.
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.
I have a program where user input is required, a user types in a number 1-8 to determine how to sort some data, but if the user just hits enter a different function is performed. I get the general idea of how to do this and I thought what I had would work just fine but I'm having some issues when it comes to when the user just hits the enter key. Currently my code looks as follows:
//User input needed for sorting.
fputs("Enter an option (1-8 or Return): ", stdout);
fflush(stdout);
fgets(input, sizeof input, stdin);
printf("%s entered\n", input); //DEBUGGING PURPOSES
//If no option was entered:
if(input == "\n")
{
printf("Performing alternate function.");
}
//An option was entered.
else
{
//Convert input string to an integer value to compare in switch statment.
sscanf(input, "%d", &option);
//Determine how data will be sorted based on option entered.
switch(option)
{
case 1:
printf("Option 1.\n");
break;
case 2:
printf("Option 2.\n");
break;
case 3:
printf("Option 3.\n");
break;
case 4:
printf("Option 4.\n");
break;
case 5:
printf("Option 5.\n");
break;
case 6:
printf("Option 6.\n");
break;
case 7:
printf("Option 7.\n");
break;
case 8:
printf("Option 8.\n");
break;
default:
printf("Error! Invalid option selected!\n");
break;
}
}
Now I've changed the if statement to try input == "", input == " ", and input == "\n" but none of these seems to work. Any advice would be greatly appreciated. Currently from what I can see, the initial if statement fails and the code jumps to the else portion and then prints the default case.
Just to be clear the variables I declared for this code are as follows:
char input[2]; //Used to read user input.
int option = 0; //Convert user input to an integer (Used in switch statement).
The problem is in how you're doing the string comparison (if (input == "\n")). C doesn't have a "native" string type, so to compare strings, you need to use strcmp() instead of ==. Alternatively, you could just compare to the first character of the input: if (input[0] == '\n') .... Since you're then comparing char's instead of strings, the comparison doesn't require a function.
Try:
#include <string.h>
at the top and
if(strcmp(input, "\n") == 0)
in place if your if ( input == ... )
Basically, you have to use string comparison functions in C, you can't use comparison operators.
Try:
input[0] == '\n'
(or *input == '\n')
You need to use single quotes rather than double quotes
if(input == "\n")
compares the input address to the address of the string "\n",
What you want to do is to compare the first character of the input buffer
to the character literal \n like this
if(input[0] == '\n')
Note the use of single quotes around '\n'
You need to capture return code from sscanf, it will tell you how many of the field are "assigned", which in "Enter" key case, return code of 0
edit:
you should use strcmp when comparing string, not the operator "==".
The issue is with strings, you are comparing pointers, i.e. memory addresses. Since the input and "\n" aren't the same exact memory, it always fails (I assume input is a char *). Since you're looking for a single character, you can instead dereference input and compare to a char using single quotes instead of double.
(*input == '\n')
Should work as you intend.