Switch Case to count amount of words and characters - c

the output window commandI am trying to use switch case in C to figure out the amount of characters, words, newlines in a user input. The code seems legit, no errors raised, however, the output does not work as expected. Please take a look and tell me what I did wrong. Thanks in advance! Here is the code:
#include <stdio.h>
int main()
{
char a, words = 1, characters = 0, newlines = 0;
printf("What do you have in mind? ");
a = getchar();
while ((a=getchar()) && a != EOF)
{
switch (a)
{
case '1':
if (a >= 'a' && a <= 'z' || a >= 'A' && a <= 'Z')
characters++;
printf("The amount of character is %c ", characters);
case '2':
if (a == ' ' || a == '\t')
words++;
printf("The amount of word is %c ", words);
case '3':
if (a == '\t')
newlines++;
printf("The amount of newlines is %c ", newlines);
default:
if (a == EOF)
break;
}
}
return 0;
}

you misunderstand what switch /case means. It does not means 'first case','second case' .. of some conditions, it means (in your specific situation), if the user just typed '1' then do this, it the users just typed '2' then do this,... well you are not typing 1 or 2 or 3.
Simply do this
while ((a=getchar()) && a != EOF)
{
if (a >= 'a' && a <= 'z' || a >= 'A' && a <= 'Z')
characters++;
printf("The amount of character is %c ", characters);
if (a == ' ' || a == '\t')
words++;
printf("The amount of word is %c ", words);
if (a == '\t')
newlines++;
printf("The amount of newlines is %c ", newlines);
}
Also you must change a to be an int

#include<stdio.h>
int
main ()
{
int ch_count = 0, line_count = 0, word_count = 0, choice;
char ch;
FILE *fp;
fp = fopen ("wordcount.txt", "r"); //make a seperate file "wordcount.txt" and Read the Test content from it.
if (fp == NULL) // Show error if previous step is not done i.e wordcount.txt file is not made.
{
perror ("FILE NOT FOUND.");
return (-1);
}
else // If file is opened properly then ask for NO. of counts.
{
printf ("Select the Following Option-------\n"
"1 - Number of Characters\n"
"2 - Number of Words\n"
"3 - Number of Lines\n");
scanf ("%d", &choice);
}
{
switch (choice) // switch to desired case as per choice of user.
{
case 1: // CASE 1 - To count the characters in the file.
{
while ((ch = fgetc (fp)) && ch != EOF)
if (ch >= 'a' && ch <= 'z' || ch >= 'A' && ch <= 'Z')
ch_count++;
}
printf ("Number of Characters : %d\n", ch_count);
break;
case 2: // CASE 2: To count total number of words
while ((ch = fgetc (fp)) && ch != EOF)
if ((ch == ' ') || (ch == '\t') || (ch == '\n') || (ch == '\0'))
{
word_count++;
}
printf ("Numbers of Words : %d\n", word_count);
break;
case 3: // CASE 3: To count total number of lines
while ((ch = fgetc (fp)) && ch != EOF)
if ((ch == '\n') || (ch == '\0'))
{
line_count++;
}
printf ("Numbers of lines : %d\n", line_count);
break;
} //switch closed
}
fclose (fp); //file closed
return 0;
}

Related

why does only the 1st file reading function executes over multiple programs of the same kind in C language?

This code contains 3 file handling related functions which read from a file named "mno". But only the 1st called function in the main() is working. If the 1st function of the list is commented then, only the 2nd function will work and the third won't. Same goes for the 3rd one
#include <stdio.h>
#include <ctype.h>
#include <unistd.h>
void countVowel(char fin[])
{
FILE *fl;
char ch;
int count = 0;
fl = fopen(fin, "r");
while (ch != EOF)
{
ch = tolower(fgetc(fl));
count += (ch == 'a' || ch == 'e' || ch == 'i' || ch == 'o' || ch == 'u') ? 1 : 0;
}
fclose(fl);
printf("Number of Vowels in the file \" %s \"-> \t %d \n", fin, count);
}
void countConsonant(char fin[])
{
FILE *fl;
char ch;
int count = 0;
fl = fopen(fin, "r");
while (ch != EOF)
{
ch = tolower(fgetc(fl));
count += (!(ch == 'a' || ch == 'e' || ch == 'i' || ch == 'o' || ch == 'u') && (ch >= 'a' && ch <= 'z')) ? 1 : 0;
}
fclose(fl);
printf("Number of Consonant in the file \" %s \"-> \t %d \n", fin, count);
}
void countAlphabet(char fin[])
{
FILE *fl;
char ch;
int count = 0;
fl = fopen(fin, "r");
while (ch != EOF)
{
ch = tolower(fgetc(fl));
count += (ch >= 'a' && ch <= 'z') ? 1 : 0;
}
fclose(fl);
printf("Number of Alphabets in the file \" %s \"-> \t %d \n", fin, count);
}
int main()
{
countVowel("mno"); // output -> 10
countConsonant("mno"); // output -> 0
countAlphabet("mno"); // output -> 0
return 0;
}
Here are the contents of "mno" file ->
qwertyuiopasdfghjklzxcvbnm, QWERTYUIOPASDFGHJKLZXCVBNM, 1234567890
As others have mentioned, your handling of EOF was incorrect:
ch was uninitialized on the first loop iteration
Doing tolower(fgetc(fl)) would obliterate the EOF value.
Using char ch; instead of int ch; would allow a [legitimate] 0xFF to be seen as an EOF.
But, it seems wasteful to have three separate functions to create the three different counts because the most time is spent in the I/O versus the determination of what type of character we're looking at. This is particularly true when the counts are so interelated.
We can keep track of multiple types of counts easily using a struct.
Here's a refactored version that calculates all three counts in a single pass through the file:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <ctype.h>
struct counts {
int vowels;
int consonants;
int alpha;
};
void
countAll(const char *fin,struct counts *count)
{
FILE *fl;
int ch;
int vowel;
count->vowels = 0;
count->consonants = 0;
count->alpha = 0;
fl = fopen(fin, "r");
if (fl == NULL) {
perror(fin);
exit(1);
}
while (1) {
ch = fgetc(fl);
// stop on EOF
if (ch == EOF)
break;
// we only care about alphabetic chars
if (! isalpha(ch))
continue;
// got one more ...
count->alpha += 1;
ch = tolower(ch);
// is current character a vowel?
vowel = (ch == 'a' || ch == 'e' || ch == 'i' || ch == 'o' || ch == 'u');
// since we know it's alphabetic, it _must_ be either a vowel or a
// consonant
if (vowel)
count->vowels += 1;
else
count->consonants += 1;
}
fclose(fl);
printf("In the file: \"%s\"\n",fin);
printf(" Number of Vowels: %d\n",count->vowels);
printf(" Number of Consonants: %d\n",count->consonants);
printf(" Number of Alphabetics: %d\n",count->alpha);
}
int
main(void)
{
struct counts count;
countAll("mno",&count);
return 0;
}
For your given input file, the program output is:
In the file: "mno"
Number of Vowels: 10
Number of Consonants: 42
Number of Alphabetics: 52
You are using ch uninitialized. at while (ch != EOF). Every function call after the first has ch equal to 0 at the start, because you forgot to initialize it and the memory was set to -1 before. You can fix it by replacing the loops like this:
int ch;
...
while ((ch = fgetc(fl)) != EOF)
{
ch = tolower(ch);
count += ...;
}
Here ch is getting initialized before you check it and later converted to lowercase.
EDIT:
Note that this only works if ch is an int, so it can handle the value of -1 (EOF) and the byte 255 is not truncated to -1.
EDIT:
At first I said ch was 0 all the time. It was -1. I am so sorry, I swapped it with the null terminator, which is usually the reason for such behavior.

How to replace all instances of (multiple) whitespace characters (blanks, tabs, newlines) by single blanks in C using array?

I tried using getchar() to solve the problem and it works, but now I am using fgets() to get the text line by line and the whole text is stored in an array. I want to replace all instances of multiple whitespace characters including blanks, tabs, and newline by a single blank.
This is what I did using getchar():
int c;
while ((c = getchar ()) != EOF
{
if (c == '\r') continue;
if (c == '\n') {
putchar (c);
while ((c = getchar ()) == '\n' || c == '\r') {}
if (c != EOF) ungetc (c, stdin); else break;
continue;
}
if (c == ' ' || c == '\t') {
putchar (' ');
while ((c = getchar ()) == ' ' || c == '\t') {}
if (c != EOF) ungetc(c, stdin); else break;
continue;
}
putchar (c);
}
return 0;
}
Now, I am trying to do this:
while (1) {
if (fgets(line,max_len, stdin) == NULL) break;
for (int i=0;i<strlen(line);i++){
text[n++]=line[i];
}
}
Where each the text is stored in an array from where I want to filter it.
dont repeat yourself: you need only one getc() and one putc()
while in the loop, you only need to remember whether the previous outputted character was a blank.
break and continue exist for a reason.
int count;
for(count=0; ; ) {
int ch;
ch = getc(stdin);
if( ch == EOF) break;
switch(ch) {
case ' ':
case '\t':
case '\n':
case '\r':
if(count++) continue;
ch = ' ';
break;
default:
count=0;
break;
}
putc(ch, stdout);
}
Similar logic for rewriting a character buffer:
char line[100];
while ( fgets(line,sizeof line, stdin) ) {
unsigned dst,src,count;
for (count=dst=src=0; line[dst]=line[src++];){
switch(line[dst]) {
case ' ':
case '\t':
case '\n':
case '\r':
if(count++) continue;
line[dst++] = ' ';
break;
default:
dst++;
count=0;
break;
}
}
fputs(line,stdout);
}
As you can see, you don't need the buffer, it will only complicate things.

How to restrict to a one letter input?

I realised that if the input is a word starting with 'y' or 'n', it will escape the loop. How can I restrict the loop such that it will continue looping unless the input is a single character?
do
{
printf("Do you want to try again? (Y/N): ");
fflush(stdin);
scanf("%c", &repeat);
repeat = toupper(repeat);
if (repeat != 'Y' && repeat != 'N')
printf("Invalid answer. Please enter 'Y' or 'N'.\n\n");
} while (repeat != 'N' && repeat != 'Y');
like this:
#include <stdio.h>
#include <ctype.h>
int main(void){
char repeat[3] = {0};//3 : one character + one character + NUL
do{
printf("Do you want to try again? (Y/N): ");fflush(stdout);
if(EOF==scanf("%2s", repeat)){ *repeat = 'N'; break; }
*repeat = toupper(*repeat);
if (repeat[1] || *repeat != 'Y' && *repeat != 'N'){//repeat[1] != '\0'..
printf("Invalid answer. Please enter 'Y' or 'N'.\n\n");
scanf("%*[^\n]");scanf("%*c");//clear upto newline
*repeat = 0;
}
} while (*repeat != 'N' && *repeat != 'Y');
puts("Bye!");//try agein or see ya, bye
return 0;
}
First fflush(stdin); does not make sense except in Microsoft's world.
Then, the scanf family function returns a value which is the number of input token successfully decoded and that return value should always be controlled. And %c should be used with caution because it can return a blank character (space or newline) remaining in buffer while %s only return printable characters. With those remarks you code could become:
repeat = '\0';
do
{
char dummy[2], inp[2];
printf("Do you want to try again? (Y/N): ");
// fflush(stdin);
if (1 == scanf("%1s%1s", inp,dummy) repeat = toupper(inp[0]);
if (repeat != 'Y' && repeat != 'N')
printf("Invalid answer. Please enter 'Y' or 'N'.\n\n");
} while (repeat != 'N' && repeat != 'Y');
Alternatively to using scanf() one can use fgets() to read a line and then do the parsing one self:
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
int main(void)
{
char repeat = '\0';
do
{
int input_valid = 0; /* Be pessimistic. */
char line[3] = {0};
puts("Do you want to try again? (Y/N):");
do /* On-time loop, to break out on parsing error. */
{
if (NULL == fgets(line, sizeof line, stdin))
{
break; /* Either fgets() failed or EOF was read. Start over ... */
}
if (line[1] != '\0' && line[1] != '\n')
{
break; /* There was more then one character read. Start over ... */
}
line[0] = toupper(line[0]);
if (line[0] != 'Y' && line[0] != 'N')
{
break; /* Something else but Y or N was read. Start over ... */
}
input_valid = 1;
} while (0);
if (input_valid == 0)
{
int c;
do /* Flush rest of input. if any. */
{
c = getc(stdin);
} while (EOF != c && '\n' != c);
fprintf(stderr, "Invalid answer. Please enter 'Y' or 'N'.\n\n");
}
else
{
repeat = line[0];
}
} while ('\0' == repeat);
printf("The user entered: '%c'\n", repeat); /* Will only print either Y or N. */
return EXIT_SUCCESS;
}

C - Swap chars using getchar and putchar

This is for homework . Must use only getchar and putchar
int main(void) {
int pch; //first
int ch; //second
while(1){
pch=getchar();
ch=getchar();
if(((pch>='A' && pch<='Z')) && ((ch>='A' && ch<='Z'))){
putchar(ch);
putchar(pch);
}
if((pch>='A' && pch<='Z') && ch=='\n') putchar(pch);
if(pch=='\n' || ch=='\n') break;
}
return EXIT_SUCCESS;
}
I need to swap chars using getchar and putchar . For exemple
PARIS
APIRS
And it works , but i need to hit ENTER two times when i even number of letters 4,6,8... . How do i eliminate this behavior ? Is there some way to kill \n for getchar
I typed PAR, hit one time enter and got APR. I believe this is what you want.
Is there some way to kill \n for getchar?
You need to do something like this:
char1 = getchar();
getchar(); // To kill `\n`
char2 = getchar();
getchar(); // To kill `\n`
Source.
Also as suggested by mch, you can do:
if(pch == '\n') break; after pch=getchar();
So you should change your program to this:
#include <stdio.h>
int main(void) {
int pch; //first
int ch; //second
while (1) {
pch = getchar();
if (pch == '\n') // when you hit enter once, break the loop
break;
ch = getchar();
if (((pch >= 'A' && pch <= 'Z')) && ((ch >= 'A' && ch <= 'Z'))) {
putchar(ch);
putchar(pch);
}
if ((pch >= 'A' && pch <= 'Z') && ch == '\n')
putchar(pch);
if (pch == '\n' || ch == '\n')
break;
}
return 0;
}

How to expect different data types in scanf()?

I'm developing a chess game in C just for practicing. At the beginning of the game, the user can type 4 things:
ROW<whitespace>COL (i.e. 2 2)
'h' for help
'q' to quit
How can I use a scanf to expect 2 integers or 1 char?
Seems like it would be most sensible to read a whole line, and then decide what it contains. This will not include using scanf, since it would consume the contents stdin stream.
Try something like this :
char input[128] = {0};
unsigned int row, col;
if(fgets(input, sizeof(input), stdin))
{
if(input[0] == 'h' && input[1] == '\n' && input[2] == '\0')
{
// help
}
else if(input[0] == 'q' && input[1] == '\n' && input[2] == '\0')
{
// quit
}
else if((sscanf(input, "%u %u\n", &row, &col) == 2))
{
// row and column
}
else
{
// error
}
}
It's better to avoid using scanf at all. It usually causes more trouble than what it solves.
One possible solution is to use fgets to get the whole line and then use strcmp to see if the user typed 'h' or 'q'. If not, use sscanf to get row and column.
This one is just using scanf
#include <stdio.h>
int main()
{
char c;
int row, col;
scanf("%c", &c);
if (c == 'h')
return 0;
if (c == 'q')
return 0;
if (isdigit(c)) {
row = c - '0';
scanf("%d", &col);
printf("row %d col %d", row, col);
}
return 0;
}
int row, col;
char cmd;
char *s = NULL;
int slen = 0;
if (getline(&s, &slen, stdin) != -1) {
if (sscanf(s, "%d %d", &row, &col) == 2) {
free(s);
// use row and col
}
else if (sscanf(s, "%c", &cmd) == 1) {
free(s);
// use cmd
}
else {
// error
}
}
P.S.: those who did not read and understand my answer carefully, please respect yourself, DO NOT VOTE-DOWN AT WILL!
Beside "get the whole line and then use sscanf", read char by char until '\n' was entered is also a better way. If the program encountered 'h' or 'q', it could do the relevant action immediately, meanwhile you cloud also provide a realtime analysis for the input stream.
example:
#define ROW_IDX 0
#define COL_IDX 1
int c;
int buffer[2] = {0,0};
int buff_pos;
while( (c = getchar())) {
if (c == '\n') {
//a line was finished
/*
row = buffer[ROW_IDX];
col = buffer[COL_IDX];
*/
buff_pos = 0;
memset(buffer , 0 , sizeof(buffer));//clear the buffer after do sth...
} else if (c == 'h') {
//help
} else if (c == 'q') {
//quit
} else {
//assume the input is valid number, u'd better verify whether input is between '0' and '9'
if (c == ' ') {
//meet whitespace, switch the buffer from 'row' to 'col'
++buff_pos;
} else {
buffer[buff_pos%2] *= 10;
buffer[buff_pos%2] += c - '0';
}
}
}

Resources