Vowels not counting correctly - c

I am trying to write a C program to count the number of vowels, keystrokes, and alpha characters. The keystroke counter is working, but the vowel counter is always off by 1 vowel. The alpha counter is not working.
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
int main(int argc, char *argv[])
{
int keystrokes = 0; //Number of keystrokes.
int letters = 0; //Number of total letters.
int vowels = 0; //Number of vowels.
int i = 0;
char sentence[0]; //Chararacter array specified to users input.
while((sentence[i] = getchar()) != '\n')
{
if(sentence[i] == 'a' || sentence[i] == 'e' || sentence[i] == 'i' || sentence[i] == 'o' ||sentence[i] =='u'|| sentence[i] == 'A' || sentence[i] == 'E' || sentence[i] == 'I' || sentence[i] == 'O' ||sentence[i] == 'U' )
{
++keystrokes;
++letters;
++vowels;
}
else
{
if (isalpha(sentence[i]) == 1) // if character is true
{
++keystrokes;
++letters;
}
else
{
++keystrokes;
i++;
}
}
}
printf("SAMPLE OUTPUT, for EACH sentence above:\n");
printf("Keystrokes %d \n", keystrokes);
printf("Alpha Characters %d \n", letters);
printf("Vowels %d \n", vowels);
return 0;
}

You have a lot of issues here. By saying char sentence[0] you actually say that there is zero bytes of memory to store the input. Accessing sentence[i] will be "out of bounds" and overwrite other parts of memory, leading to undefined behavior.
To start, change char sentence[0] to char sentence[100]. Then look carefully where you increment your counters, i.e. what the if/else flow looks like in your program. To give an example: Currently, when you have a vowel, the check for isalpha() is not reached, nor is the i++.

Your problem is that you have undefined behaviour caused by memory corruption.
char sentence[0];
That declares a 0 character array. Just get rid of the array and the i index. That is, change char sentence[0] to be something like char current_char and then replace all instances of sentence[i] with current_char.

I agree with Alan AU about replacing sentence with get_char. I also changed the (isalpha(sentence[i]) == 1) to (isalpha(sentence[i])).
I admit that I'm still new to programming, but your code did not increment the letters properly until I made that change.

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 check a string contain a certain value in C

#include <stdio.h>
#include <string.h>
#define CHAR_SIZE 35
//Function to remove white space
char *remove_white_spaces(char *str)
{
int i = 0, j = 0;
while (str[i])
{
if (str[i] != ' ')
str[j++] = str[i];
i++;
}
str[j] = '\0';
return str;
}
void main()
{
int i = 0;
char str[CHAR_SIZE];
printf("\nKey in input: ");
fgetchar();
fgets(str , CHAR_SIZE, stdin);
//Remove white space
remove_white_spaces(str);
printf("%s",str);
//for (i = 0; str[i] != '\0'; ++i);
//printf("Length of the string: %d", i);
if (str[i] == '0' || str[i] == '1' )
{
printf("CORRECT");
}
else
{
printf("Wrong Input");
}
}
I want to check whether the user has type in the correct input. For example, I have key in 0 01111110 10100000000000000000000. After removing the white space, the str input became 00111111010100000000000000000000. From this str, I want to check that the user has only key in 0 and 1. The output of the result I got was correct which is shown below1.
Output of result
However, when the user key in another value including 0 and 1. The output I suppose to get is the wrong input. But I obtained Correct as the result which is shown below2.
Output of result
Additional question, How do I implement an if statement that the str has to only have 32 characters to continue otherwise it has to break and the user key has to key in 32 characters only. Can I do it in a while loop instead of an if statement so that the user would not need to run the code again?
You could use strtok to extract your characters. Also there's a flaw in your logic. it should be if (str[i] == '0' || str[i] == '1' to check if the value is '0' OR '1'. Here's a sample implementation you could refer to:-
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define CHAR_SIZE 100
int main()
{
char str[CHAR_SIZE];
printf("\n Key in value: ");
getchar();
fgets(str, CHAR_SIZE, stdin);
char *tok;
tok = strtok(str, "\n");
int i = 0;
tok++; //skip the first character which is a space
while (*tok != 0x00)
{
if (*tok <= 0x31 && *tok >= 0x30)
tok++;
else
{
printf("Wrong number input ==> %c \n", *tok);
break;
}
}
}
initialize i:
putting the equivalent of C's
int i = 0;
in your prog lang before entering the while loop should do the job.
First of all, you are checking that str[i] should be equal to 0 and equal to 1 – and that doesn't make any sense, because an element in the array can be only one value, 0 or 1; so, you should test if (str[i] == '0' || str[i] == '1').
And, before that, you should initialize i: int i = 0.
Edit you must loop over elements of the string
int check = 0;
while (str[i] != '\0')
{
if (str[i] == '0' || str[i] == '1')
i++;
else {
check = 1;
break;
}
}
if (check == 0){
print("CORRECT");
}
else {
printf("WRONG INPUT");
}

Find vowels in a string

Given below is my code for finding vowels in a given string:
#include <stdio.h>
#include <string.h>
int main() {
char str[100];
int i, str_length;
//scanf("%[^\n]%*c", &str[100]);
fgets(str, sizeof(str), stdin);
str_length = strlen(str);
for (i = 0; i < str_length; i++) {
if (str[i] == 'a' || str[i] == 'e' ||
str[i] == 'i' || str[i] == 'o' ||
str[i] == 'u' || str[i] == 'A' ||
str[i] == 'E' || str[i] == 'I' ||
str[i] == 'O' || str[i] == 'U')
{
printf("Vowels in the string are: %c \n", str[i]);
}
}
return 0;
}
I just wanna know, why scanf("%[^\n]%*c",&str[100]) is not working in my code?
cause I tried executing my program multiple times using scanf but it didn't worked.
And after using fgets I got the desired output.
So, can anyone help me to understand, where I am wrong!!
In the scanf function call, this &str[100] takes a pointer to str, makes it point to the element with the index 100 (which is past the end of the array), dereferences it and then takes the address of that (non-existing) element. This, most likely, leads to an attempt to an invalid write, which is probably caught by the operating system which terminates your program. In any case, the string is not written to the correct location.
Instead, you want the argument to point to the memory location of the first element of str, i.e.:
scanf("%[^\n]%*c", str);
That said, using fgets is better as it accepts an argument for the size which prevents buffer overflows. A size can also be given to scanf, but since it is part of the format specifier it cannot be a variable; only a hardcoded constant:
scanf("%99[^\n]%*c", str);
Note that this is for 99 elements, as there needs to be room for the null-terminator (\0) as well. See here for more info on scanf. But again, using fgets is less error prone and to be preferred.
Some additional advice:
The typical signature of the main function, using no parameters, is int main(void).
The scanf version fails if the input is a single newline character. Both versions fail on no input. It is always a good idea the check the return values of input (and output) functions.
Inside of the for-loop, you could create a copy of the current character converted to lowercase using the tolower function, and then perform only the lowercase comparisons. I.e.:
for (i = 0; i < str_length; i++) {
char ch = tolower(str[i]);
if (ch == 'a' || ch == 'e' || ch == 'i' || ch == 'o' || ch == 'u')
printf("Vowels in the string are: %c \n", str[i]);
}
Another option is to replace the comparisons in the if-statement with a call to strchr, which makes the program a bit more generic and scalable (one string is more easily changed than multiple comparisons):
char ch = tolower(str[i]);
if (strchr("aeiou", ch) != NULL)
printf("Vowels in the string are: %c \n", str[i]);

Program to find vowels, If statements not assigning correct values [closed]

Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 3 years ago.
Improve this question
I have a simple program to find the vowels in a string. The for loop is supposed to iterate through the string and see if the char matches any of the vowels using and if else block but the output is just 100 As.
I tried making them all just ifs but that gave all Us.
#include <stdio.h>
int main()
{
const int SIZE = 100;
char str[SIZE] = {"the brown fox\0"};
char vowels[SIZE];
for (int i = 0; i <= SIZE; i++) {
if (str[i] == '97' || '65') {
vowels[i] = 'a';
}
else if (str[i] == '101' || '69' ) {
vowels[i] = 'e';
}
else if (str[i] == '105' || '73') {
vowels[i] = 'i';
}
else if (str[i] == '111' || '81') {
vowels[i] = 'o';
}
else if (str[i] == '117' || '85') {
vowels[i] = 'u';
}
printf("%c", vowels[i]);
}
return 0;
}
EDIT: Fixed the assignment if e.g. (str[i] == '97' || str[i] == '65') now it's printing strange symbols
EDIT 2: New code
#include <stdio.h>
int main()
{
const int SIZE = 100;
char str[SIZE] = {"the brown fox\0"};
char vowels[SIZE];
for (int i = 0; i <= SIZE; i++) {
if (str[i] == 'a' || str[i] == 'A') {
vowels[i] = 'a';
}
else if (str[i] == 'e' || str[i] =='E' ) {
vowels[i] = 'e';
}
else if (str[i] == 'i' || str[i] == 'I') {
vowels[i] = 'i';
}
else if (str[i] == 'O' || str[i] == 'o') {
vowels[i] = 'o';
}
else if (str[i] == 'u' || str[i] == 'U') {
vowels[i] = 'u';
}
printf("%c", vowels[i]);
}
return 0;
}
EDIT 3: Even after initialing vowels to '' at the start of the loop as suggested the strange symbols are gone but it's still not functioning properly.
You are comparing your char str[i] with '97'
6.4.4.4
An integer character constant has type int. The value of an integer character constant containing a single character that maps to a single-byte execution character is the numerical value of the representation of the mapped character interpreted as an integer. The value of an integer character constant containing more than one character (e.g., 'ab'), or containing a character or escape sequence that does not map to a single-byte execution character, is implementation-defined.
If you want to compare a char you can use the ascii value for example 97 or directly the char with 'c'.
For more maintenability and readability I prefer using the char directly.
There is other problems in your code:
First, in your for loop: for (int i = 0; i <= SIZE; i++) {
You are going too far in your array because of your <= as arrays id starts with 0, if you type str[100], in reality you are using the 101st char.
Another problem is your if statements: if (str[i] == '97' || '65') {
Here your if statement is equivalent to if (str[i] == '97' || '65' != 0) {
Consider retyping str[i] == : if (str[i] == '97' || str[i] == '65') {
Plus don't forget the first problem I mentionned about your '97'
You have a very large number of small problems summarized below:
#define SIZE 100 /* if you need a constant, #define one (or more) */
...
char vowels[SIZE] = ""; /* initialize all zero, {0) is valid also */
An integer constant is created by #define or by use of an enum. A const qualified int is not a constant integer. (that said VLAs are legal in C99, but optional in C11)
int idx = 0; /* separate index for filling vowels array */
Keep a separate index for filling the vowels array.
/* don't use magic-numbers in your code */
if (str[i] == 'a' || str[i] == 'A') {
Don't use magic-numbers, instead, use literal character constants were needed in your code to produce much more readable code.
Your program takes arguments, use them to pass the string to parse (or read from stdin), e.g.
int main (int argc, char **argv) {
const char *str = (argc > 1) ? argv[1] : "the brown fox";
...
The test ? if_true : if_false operator is called the ternary operator. It allows a simple in-line conditional to select one of two values based on the test condition (e.g. (argc > 1))
If you plan on using vowels as a string, don't forget to nul-terminate vowels after the loop, e.g.
vowels[idx] = 0; /* nul-terminate vowels */
Correcting all the errors and adding the arguments to main() you could do something similar to:
#include <stdio.h>
#define SIZE 100 /* if you need a constant, #define one (or more) */
int main (int argc, char **argv) {
const char *str = (argc > 1) ? argv[1] : "the brown fox";
char vowels[SIZE] = ""; /* initialize all zero, {0) is valid also */
size_t idx = 0; /* separate index for filling vowels array */
for (int i = 0; idx < SIZE - 1 && str[i]; i++) {
/* don't use magic-numbers in your code */
if (str[i] == 'a' || str[i] == 'A') {
vowels[idx++] = 'a'; /* assign 'a', increment index */
}
else if (str[i] == 'e' || str[i] == 'E' ) {
vowels[idx++] = 'e';
}
else if (str[i] == 'i' || str[i] == 'I') {
vowels[idx++] = 'i';
}
else if (str[i] == 'o' || str[i] == 'O') {
vowels[idx++] = 'o';
}
else if (str[i] == 'u' || str[i] == 'U') {
vowels[idx++] = 'u';
}
}
vowels[idx] = 0; /* nul-terminate vowels */
printf (" %zu vowels: ", idx); /* print number of vowels */
for (int i = 0; vowels[i]; i++) /* output each vowel, comma-separated */
printf (i > 0 ? ", %c" : "%c", vowels[i]);
putchar ('\n'); /* tidy up with newline */
return 0;
}
Example Use/Output
bin\vowels.exe "a quick brown fox jumps over the lazy dog"
11 vowels: a, u, i, o, o, u, o, e, e, a, o
Depending on your compiler str[i] == '117' (and the rest) may give you an error as signle quotes are only to be used when you want to implement the ascii equivalent of a single character like 'a' or so. Therefore str[i] == '117' is checking if str[i] is equal to the ascii equivalent of "117".
Other than that " || " is a logical "or" operator. When you write down str[i] == '111' || '81' you simply mean "find ascii codes of 111 and 81(which dont exist) , use them in "or" operation, check if the result equals str[i]".
last but not least i found a nice function online which might help making your code more compact
int isvowel(int ch)
{
int c = toupper(ch);
return (c == 'A' || c == 'E' || c == 'I' || c == 'O' || c == 'U');
}
to explain it shortly, if the char equivalent of given int ch is lowercase, the function changes it to uppercase and checks if it is an uppercase vowel, if the given integer already equals an uppercase vowel int c = toupper(ch); doesnt change anything.
Implementation can be done as:
for(int i=0; i<SIZE; i++) //scan all emelents of str[SIZE]
{
if(isvowel(str[i])) //print if vowel
printf ("%c", str[i]);
}

Why my program returns characters i didn't input? (Pure C)

My program: Something is wrong
#define _CRT_SECURE_NO_WARNINGS
#include <ctype.h>
#include <stdio.h>
//Функция для проверки соответствия символов.
int ifSignsCorrect(char theChar) {
if ((theChar >= 'A' && theChar <= 'Z') || (theChar >= 'a' && theChar <= 'z') || theChar == '.' || theChar == ' ' || theChar == '*') return 1;
return 0;
}
int main() {
char string[256];
int i = 0;
//Заполняем массив
for (i = 0; i < 256; i++) {
scanf("%c\n", &string[i]);
if (string[i] == '*') break;
printf("%с\n", string[i]);
if (ifSignsCorrect(string[i]) != 1) {
printf("You used wrong characer, formating disc C (Just joking)\n");
return;
}
}
}
Three things I want to mention:
First:
You are trying to access invalid pieces of memory with this code:
int i = 0;
while (string[i - 1] != '*') {
In the first iteration you will access string[-1]. You have to solve that first.
Second:
You are defining an array of pointers in this line:
char *string[256];
use an array of characters char string[256]; instead.
Third:
You could just print like this:
printf("You used wrong characer, formating disc C (Just joking)\n");
Unless you want to define variable that will indicate this error_message, that could be cleaner some times, specially is you are going to reuse it.
Hope it helps.
You used an array of pointers instead of array of characters here:
char *string[256];
You are also accessing the array out of bounds here:
while (string[i - 1] != '*') { // here i == -1
Also a if statement after the scanf() like this would be proper:
if( string[i] == '*' )
break ;
EDIT:
Why does the program only print the character ? ?
Because the character c in the line printf("%с\n", string[i]); is actually not an ascii c
Try copying it into a program that only supports ascii. I copied it into notepad++ and set the encoding to ascii and it turned to ? :) . Must be a multilanguage support error as i see you have cyrillic enabled.

Resources