Unable to read all characters(using getchar) inside for loop - c

Code:
//Program to find no of vowels
#include<stdio.h>
int main()
{
int count;char letter;int vowel=0;
for(count=0;count<10;count++)
{
letter=getchar();
switch(letter)
{
case 'a':
case 'e':
case 'i':
case 'o':
case 'u':vowel++;
}printf("Count:%d",count);
}
printf("NO of vowels is %d\n",vowel);
return 0;
}
Output:
a
a
s
d
f
NO of vowels is 2
The program reads only 5 characters and then displays the expected output. I tried printing the value of 'count' and by the end of loop, it incremented to 10. But,I am not able to read the number of characters(10) equivalent to my for loop condition. Please help.

I'm surprised you didn't notice from the printf("Count: %d\n"); line that the count increments by two for each letter of input. The getChar function gets all of the characters from the input text, including spaces and newlines. The simplest way to make your program behave as you expect is to increase the maximum count to 20:
for(count = 0; count < 20; count++)
{
letter = getchar();
// ...
Alternatives include using scanf and checking for reaching the end of text input, but your implementation is much safer.

Space ' ' is also a character. getchar reads a character at a time and hence reads ' ' too. Remove spaces from the input.

#include <stdio.h>
#include <ctype.h>
int main(){
int count=0, vowel=0;
char letter;
while(count < 10){
letter=getchar();
if(isgraph(letter)){
switch(tolower(letter)) {
case 'a':
case 'e':
case 'i':
case 'o':
case 'u':vowel++;
}
++count;//Counting only the case of the display characters that are not blank
}
}
printf("NO of vowels is %d\n",vowel);
return 0;
}

Related

Nested switch() - case issue in C. Why are <ctype.h> functions not working the way I would like them to?

I have been trying to understand why this is not working properly for the past five hours.
The question explicitly asks for the use of switch() and no if-else (or of the likes) to count the number of words, lines, and characters in typed up text. And exit the program with Ctrl+D or Ctrl+Z.
Here, I deconstructed the counting by figuring different cases of whether the current typed input is whitespace or not, and from thereon, judging by the previous letter, whether it is justified to count it as an extra word, character, and/or line. ( input = punctuation, previous input= character --> add 1 to word count and 1 to character count ; if input = newline and previous input !=whitespace --> add one to line counter + one to word counter, etc.)
My code is the following:
int main() {
int letter = 0, prev_letter = 0, num_char = 0, num_words = 0, num_lines = 0;
printf("User, please provide any text you wish using letters, spaces, tabs, "
"and enter. \n When done, enter Ctrl+D or Ctrl+Z on your keyboard.");
while ((letter = getchar()) != 4 &&
letter != 26) // In ASCII, Ctrl+D is 4, and Ctrl+Z is 26
{
switch (isspace(letter)) {
case 0: // False = is not a whitespace
{
switch (
isalpha(prev_letter)) // checking to see if alphanumeric input or not
{
case 1:
switch (ispunct(letter)) {
case 1:
num_words++;
num_char++; // Punctuation considered as characters in this particular
// sub-exercise.
break;
}
break;
case 0:
num_char++;
break; // All other cases are just another character added in this case
// 0 (Not whitespace)
}
} break;
case 1: {
switch (letter) {
case 9: // 9 =Horizontal tab
{
switch (isspace(prev_letter)) {
case 0:
num_words++; // Assuming if not whitespace, then punctuation or
// character.
break;
default:
break;
}
} break;
case 32: // 32 = Space
{
switch (isspace(prev_letter)) {
case 0:
num_words++; // Assuming if not whitespace, then punctuation or
// character.
break;
default:
break;
}
} break;
case 13: // 13 = Carriage return
{
switch (isspace(prev_letter)) {
case 0:
num_words++;
num_lines++;
break;
default:
num_lines++;
}
} break;
case 10: // 13 = Line Feed
{
switch (isspace(prev_letter)) {
case 0:
num_words++;
num_lines++;
break;
default:
num_lines++;
}
} break;
default:
printf("Test2");
}
} break;
default:
break;
}
prev_letter = letter;
}
printf("Number of characters is: %d. \n", num_char);
printf("Number of words is: %d. \n", num_words);
printf("Number of lines is: %d. \n", num_lines);
return 0;
}```
It seems like isalpha(), ispunct(), isalnum() are not feeding properly my cases.
I have tried breaking it down to individual cases but when inputting text with tabs, spaces, and alphanumeric inputs, it fails to count words, characters, and lines properly.
What am I not seeing properly? Any pointers greatly appreciated.
That seems an odd assignment. Maybe you're misunderstanding it, but assuming you aren't, let me see if I can figure it out.
switch compares one variable to several values, so that would mean the first part is to determine a single value from several test functions.
A common use of switch is to check enum values, so you can start by defining an enum with the values you need. You're using isalpha(), ispunct(), and isspace() in your code, so I'll define those enum values.
enum chartype {
IS_ALPHA,
IS_PUNCT,
IS_SPACE,
IS_UNKNOWN
};
You can select an enum value without using if with the ? : operators.
enum chartype letter_chartype =
isalpha(letter) ? IS_ALPHA
: ispunct(letter) ? IS_PUNCT
: isspace(letter) ? IS_SPACE
: IS_UNKNOWN;
That lets you use a switch for each character type.
switch(letter_chartype) {
case IS_ALPHA:
...
break;
case IS_PUNCT:
...
break;
case IS_SPACE:
...
break;
default:
...
break;
}
That doesn't do your assignment for you, but I hope that helps give you some direction. I'm assuming you covered the ? : operators. If not, you might have to do something longer, trickier, or stupider (stupid often looks clever, be careful about that).
isalpha and similar return zero if the parameter is not letter or not zero if it is.
Use if statement not switch to test the condition. Using switch for logical data is not logical or practical.
use functions and write your own implementations of those functions using switch ... case
Example (using GCC extension case ranges - to be portable you need to have separate case for every letter or digit [like in myispace])
int myisalpha(unsigned char x)
{
switch(x)
{
case 'a' ... 'z':
case 'A' ... 'Z':
return 1;
}
return 0;
}
int myisdigit(unsigned char x)
{
switch(x)
{
case '0' ... '9':
return 1;
}
return 0;
}
int myisspace(unsigned char x)
{
switch(x)
{
case ' ':
case '\n':
case '\r':
case '\t':
case '\v':
case '\f':
return 1;
}
return 0;
}

Scanf preventing a C pragram from looping

I'm trying to write a program that takes Roman numerals as input and then converts them to decimal values. The user has to first declare how many Roman numerals they are going to input (either one or two).
I am using a for loop that repeats as many times as the number of Roman numerals. It either shouldn't loop if the there is only one numeral or if there are two it should loop twice because we need to take one letter as input at a time.
The issue I was having is that the scanf statement that is inside the for loop, keeps preventing the programme from looping. As soon as I removed the scanf and statically assigned the value then it worked perfectly fine. Then while trying to fix the issue I tried to print out the value scanf is returning by assigning it to a new variable, like char snf = scanf("%s", &numeral); and for some reason it started working exactly I wanted it to work. I have absolutely no idea why it is working now and why it was preventing the loop from looping before. Can anyone explain to me what's going on?
// A program to convert Roman Numerals to Decimals system.
#include <stdio.h>
int convert_numerals(char numeral){
switch(numeral){
case 'I':
return 1;
case 'V':
return 5;
case 'X':
return 10;
case 'L':
return 50;
case 'C':
return 100;
case 'D':
return 500;
case 'M':
return 1000;
default :
printf("\nError! You did not enter a valid numeral\n");
return 0;}}
int main(){
int Decimal_Val = 0; //Initializing the variable with 0 to avoid issues at check.
int Numeral_Count;
printf("How many characters does your Roman numerals have? 1 or 2\n");
scanf("%d",&Numeral_Count);
for (int i = 1; i < 1+Numeral_Count; ++i)
{
char numeral = 'O';
int converted_val;
printf("\n\nEnter numeral %d : ",i);
scanf("%s", &numeral); // The problematic line.
converted_val = convert_numerals(numeral);
if (Decimal_Val != 0)
{
if (Decimal_Val < converted_val)
{
Decimal_Val = converted_val - Decimal_Val;
}else{
Decimal_Val += converted_val;
}
}else{
Decimal_Val = converted_val;
}
}
printf("\nThe Roman numerals you entered are equal to %d in Decimals\n", Decimal_Val);
return 0;
}
Scanf can be a problematic function, especially with characters. Instead, try using fgets to read a line, then use the first character. If we break this out into a separate function. (Breaking problems down is crucial to solving complex problems in any programming language.)
char get_roman_numeral(const char *prompt, const char * error_msg) {
while (1) {
printf("%s: ", prompt);
char input[20] = {};
fgets(input, 19, stdin);
input[strcspn(input, "\n")] = '\0';
if (strlen(input) > 0) {
switch (input[0]) {
case 'i': case 'I':
case 'v': case 'V':
case 'x': case 'X':
case 'l': case 'L':
case 'c': case 'C':
case 'd': case 'D':
case 'm': case 'M':
return input[0];
default:
printf("%s\n", error_msg);
}
}
else {
printf("%s\n", error_msg);
}
}
}
Picking this apart, we loop indefinitely. Each time we print the prompt we provide, then read a line from stdin into the char buffer input which can hold 20 characters (one of them has to be the null terminating character).
input[strcspn(input, "\n")] = '\0';
This is going to find the first newline character in the input string and set it to '\0'. This effectively removes the newline character than fgets will include in the input string.
If the input string is then longer than 0 characters, we'll evaluate the first character. If it's a roman numeral, we return it. The function is done!
If it's either not a roman numeral, or the string is zero characters in length, we'll print the error message, and the loop starts over.
Hopefully looking at getting your input this way, without the problematic scanf will help you solve the bigger problem.
just decide to stop working for no apparent reason.
Below fails as "%s" attmeps to form a string and numeral is only big enoguh for the stirng "".
//char numeral = 'O';
//scanf("%s", &numeral); // The problematic line.
char numeral[100];
if (scanf("%99s", &numeral) == 1) {
// Success, continue and use `numeral`
converted_val = convert_numerals(numeral); will need to change too as that only handles 1 char.

For-loop logic in order to print an inputed character using scanf n number of times

I've been trying to understand the logic behind this for loop but I've been unable to. The problem asks to input an integer n (number of test cases) followed by n number of characters with each characters denoting the day of the week. So I need to output the day n number of times.
#include <stdio.h>
int main()
{
int n, i;
char ch;
scanf("%d",&n);
for (i = 0; i < 2 * n; i += 1)
{
scanf("%c", &ch);
switch (ch)
{
case 'M':
printf("Monday\n");
break;
case 'T':
printf("Tuesday\n");
break;
case 'W':
printf("Wednesday\n");
break;
case 'H':
printf("Thursday\n");
break;
case 'F':
printf("Friday\n");
break;
case 'S':
printf("Saturday\n");
break;
case 'N':
printf("Sunday\n");
break;
}
}
return 0;
}
I don't understand the logic for i<2*n. So for example when I input n=2 followed by characters M M, and i is initialized to 0, the condition for 0 < 4 is checked which is true so the first character M is input, and Monday is printed once, now i is incremented to 1 and is checked against 1 < 4 which is true and is printed once again. Now it has already been printed twice, but according to the i < 2 * n logic shouldn't Monday get printed 4 times until 4 < 4 terminates the for loop?
But this logic somehow works correctly.
My logic for i <= n, for some reason does not work and only inputs and prints the character the one time. Where am I going wrong here?
scanf("%c", &ch); scans the character you input but the \n newline character, caused by the enter, remains on the buffer, (the same is true for the previous scanf in your code), this causes the for loop to run 2 times for every input: first, it scans the character itself and then the \n. This is the reason why your for loop needs to run 4 times instead of the 2 it should.
You will need to discard those \n characters. You can use %*c to discard them, then you can replace n*2 with n in the for loop, the advantage is that the loop runs only half of the times you have now.
This works, not only for block input separated by space, but also for one at a time inputs.
Link to live sample
//...
scanf("%d%*c", &n); //<-- dicard newline character
for (i = 0; i < n ; i += 1) {
scanf("%c%*c", &ch); //<-- discard newline character
//...

Setting number of looping

I have problem. I need functions in tool.c file to loop only number of times that are required. Like it stops after looping thru whole input. My teacher said I should pass second argument, but class finished and I don't know how it should look.
main.c
#include <stdio.h>
#include <stdlib.h>
#include "tools.h"
int main(int argc, char *argv[]) {
int count[256] = { 0 };
int c;
while ( (c=getchar())!=EOF ){
count[c]++;
}
switch (argc > 1 && argv[1][1]) {
case 'm': case 'M':
mostOften(count);
break;
case 'l': case 'L':
leastOften(count);
break;
default:
mostOften(count);
break;
}
return 0;
}
tools.c
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include "tools.h"
void mostOften(int *s) {
int j, a = 0;
int max=0, cha;
for(j=32; j<126; j++){
if(s[j]>max) {
max=s[j];
cha=j;
}
a++;
}
printf("char %c: %d times\n", cha, max);
}
void leastOften(int *s) {
int j, a = 0;
int min=INT_MAX, cha;
for(j=32; j<126; j++){
if(s[j] && s[j]<=min) {
min=s[j];
cha=j;
}
a++;
}
printf("char %c: %d times\n", cha, min);
}
For example if I input
paragraph
I want it to loop only 9 times, basically I need to set some if statment to stop looping
From looking at how you have the problem setup, it looks like you are confusing iterating over the character that are part of the input, and the array that holds the frequency of the characters read.
For starters, to make your code readable, don't use magic numbers in your code, e.g. 32 and 126. Instead use the characters you are attempting to represent, e.g. (space) and ~ (tilde). For example, instead of using:
for(j=32; j<126; j++){
you could use:
for(j = ' '; j < '~'; j++){
That too has it's pitfalls. Why? You don't want to loop over characters, you actually want to loop over the elements in your count array that hold the frequency each character occurs in input. In other words, you need an array holding at minimum 95 integers which will hold the frequency each character occurs in your input. Since you know how may characters that will be, don't obscure it behind 32 to 126, just declare a constant for your array size (maybe called ARSZ) in tools.h, e.g.
#define ARSZ 95
Then after reading your input and filling the count array, it is just a matter of iterating over the count array once to get either the mostoften or leastoften number. Further, since you have a constant for the number of elements in count you do NOT need to pass the size of count to mostoften and leastoften -- you already know how many elements are present, 95. (see below for notes on iterating only over the characters present in input)
(if the array size is Not constant (and you are not passing an array with a sentinel like a nul-terminated string) or the number of elements you need to iterate over is not known at compile time, then you DO need to pass the size of the array to the functions.
(and another quick aside, C generally uses all lower-case for variable names, reserving all upper-case for constants and macros. You will not ordinarily see MixedCase or camelCase variable names in C, leave that for C++)
Next, while you should use getopt for processing command line arguments, you can use a quick hack of checking the second character of the arguments at issue, but you need to validate you have at least one argument to check and that the argument isn't an empty-string. Basically, you want to check:
if (argc > 1 && *argv[1]) /* check argc & not empty-string */
switch (argv[1][1]) {
case 'm':
mostoften (count);
break;
case 'M':
mostoften (count);
break;
case 'l':
leastoften (count);
break;
case 'L':
leastoften (count);
break;
default:
fprintf (stderr, "warning: unrecognized option, using 'mostoften'.\n");
mostoften (count);
}
else {
fprintf (stderr, "warning: no option given using 'mostoften'.\n");
mostoften (count);
}
note: you can't put two constant conditions together for any single case of your switch (some compilers provide non-standard extensions). Also note, you do not need a break in the default case, there is no fall-through possible.
Putting it altogether, you could write your tools.h similar to:
#include <stdio.h>
#include <limits.h>
#define ARSZ 95
int mostoften (int *a);
int leastoften (int *a);
Your tools.c as:
#include "tools.h"
int mostoften (int *a) {
int i, max = INT_MIN, cha = '0';
for (i = 0; i < ARSZ; i++)
if (a[i] > max) {
max = a[i];
cha = i + ' ';
}
printf ("char '%c' : %d times\n", cha, max);
return max;
}
int leastoften (int *a) {
int i, min = INT_MAX, cha = '0';
for (i = 0; i < ARSZ; i++)
if (a[i] < min) {
min = a[i];
cha = i + ' ';
}
printf ("char '%c' : %d times\n", cha, min);
return min;
}
You do know that if the max or min is the same for 2 different characters, you will select the first, and in the case of leastoften you will always select the first character with 0 frequency. To correct this problem, you will need to keep a second array (or 2D array, or struct) that tracks which characters were present in the input and only consider the frequency for those characters.
Finally, your main.c could be written something like:
#include "tools.h"
int main (int argc, char **argv) {
int c = 0, count[ARSZ] = {0};
while ((c = getchar ()) != EOF)
if (' ' <= c && c <= '~')
count[c - ' ']++;
if (argc > 1 && *argv[1]) /* check argc & not empty-string */
switch (argv[1][1]) {
case 'm':
mostoften (count);
break;
case 'M':
mostoften (count);
break;
case 'l':
leastoften (count);
break;
case 'L':
leastoften (count);
break;
default:
fprintf (stderr, "warning: unrecognized option, using "
"'mostoften'.\n");
mostoften (count);
}
else {
fprintf (stderr, "warning: no option given using 'mostoften'.\n");
mostoften (count);
}
return 0;
}
There are many different ways to accomplish this task, but given your initial code, this keeps with what appeared to be your intent. Look it over and let me know if you have any questions. If you want the easiest way to track the characters present in your input without using a struct, then simply declaring count as count[ARSZ][2] and using the additional element to indicate which characters were present would do. (you can pass the array to your functions as int a[][2] or int (*a)[2]) Good luck.

Exit out of a loop after hitting enter in c

How should i exit out of a loop just by hitting the enter key:
I tried the following code but it is not working!
int main()
{
int n,i,j,no,arr[10];
char c;
scanf("%d",&n);
for(i=0;i<n;i++)
{
j=0;
while(c!='\n')
{
scanf("%d",&arr[j]);
c=getchar();
j++;
}
scanf("%d",&no);
}
return 0;
}
I have to take input as follows:
3//No of inputs
3 4 5//input 1
6
4 3//input 2
5
8//input 3
9
Your best bet is to use fgets for line based input and detect if the only thing in the line was the newline character.
If not, you can then sscanf the line you've entered to get an integer, rather than directly scanfing standard input.
A robust line input function can be found in this answer, then you just need to modify your scanf to use sscanf.
If you don't want to use that full featured input function, you can use a simpler method such as:
#include <stdio.h>
#include <string.h>
int main(void) {
char inputStr[1024];
int intVal;
// Loop forever.
for (;;) {
// Get a string from the user, break on error.
printf ("Enter your string: ");
if (fgets (inputStr, sizeof (inputStr), stdin) == NULL)
break;
// Break if nothing entered.
if (strcmp (inputStr, "\n") == 0)
break;
// Get and print integer.
if (sscanf (inputStr, "%d", &intVal) != 1)
printf ("scanf failure\n");
else
printf ("You entered %d\n", intVal);
}
return 0;
}
There is a difference between new line feed (\n or 10 decimal Ascii) and carriage return (\r or 13 decimal Ascii).
In your code you should try:
switch(c)
{
case 10:
scanf("%d",&no);
/*c=something if you need to enter the loop again after reading no*/
break;
case 13:
scanf("%d",&no);
/*c=something if you need to enter the loop again after reading no*/
break;
default:
scanf("%d",&arr[j]);
c=getchar();
j++;
break;
}
You also should note that your variable c was not initialized in the first test, if you don't expected any input beginning with '\n' or '\r', it would be good to attribute some value to it before the first test.
change
j=0;
to
j=0;c=' ';//initialize c, clear '\n'
When the program comes out of while loop, c contains '\n' so next time the program cannot go inside the while loop. You should assign some value to c other than '\n' along with j=0 inside for loop.

Resources