I'm writing a program in C which counts the numbers of the vowels in a series of strings decided by the user, even the number of elements of the strings is decided by the user. The problem is that the function gives always the same numbers of vowels which is the one of the first string.
Here's the code:
#include <stdio.h>
#include <string.h>
int vowels(char str[]);
int main(){
int n, i, x;
printf("How many strings do you want to insert?");
scanf("%d", &n);
printf("How many characters per string?");
scanf("%d", &x);
char str[x];
if(x < 10){
for(i = 0; i < n; i++){
printf("Insert a string:");
scanf("%s", str);
if(strlen(str) == x){
vowels(str);
}
else{
printf("Error\n");
}
}
}
else{
printf("Error: the number of characters must be < 10");
}
return 0;
}
int vowels(char str[]){
int i, j;
while(str[i] != '\0'){
if(str[i] == 'a' || str[i] == 'A' || str[i] == 'e' ||
str[i] == 'E' || str[i] == 'i' || str[i] == 'I' ||
str[i] == 'o' || str[i] == 'O' || str[i] == 'u' ||
str[i] == 'U'){
j++; }
i++;
}
printf("Number of vowels in the string:%d\n", j);
return 0;
}
Your code contains two mistakes:
i and j indexes of vowels() function are not initialized, so they contain garbage and will lead to an unpredictable behavior of your loops. That's because local variables, unlike global variables, are not initialized by default to 0.
Use instead
int i=0, j=0;
The buffer char str[x]; will not be able to contain a string with x characters. In fact, the space required by string terminator character '\0'.
So it should be
char str[x+1];
With these changes your code will work.
But...
... but it is not enough. In fact, when you get the input string, you don't perform any check to the number of characters retreived:
scanf("%s", str);
By inserting a very long string you will go out of bounds far beyond the str string, causing undefined behavior and, likely, a program crash.
How to fix it? Since your input string can have a maximum length of 9, just define a fixed length array:
char str[11];
Why size 11? First of all your array must contain the maximum of 9 characters and the terminator. So 10. But it has also to contain an extra character, so that inputs longer that 9 characters can be detected.
After that, just receive input string with
scanf("%10s", str);
In this way all legit input string can be stored (from size 1 to size 9). All strings long 10 or more characters will be truncated to a ten chars long string, and your length check will fail as expected.
Please note that in case of long string all characters exceeding the first 10 will remain unread in the stdin buffer. So in case of error you need a mechanism to consume those chars, otherwise you will find them at the next scanf. I've written this trick:
while( fgets( str, 10, stdin ) != NULL )
{
if( strlen(str) < 10 )
break;
}
The resulting code, with all the changes I described, is the following one:
#include <stdio.h>
#include <string.h>
int vowels(char str[]);
int main(){
int n, i, x;
printf("How many strings do you want to insert?");
scanf("%d", &n);
printf("How many characters per string?");
scanf("%d", &x);
if(x < 10){
char str[11];
for(i = 0; i < n; i++){
printf("Insert a string:");
scanf("%10s", str);
if(strlen(str) == x){
vowels(str);
}
else{
printf("Error\n");
while( fgets( str, 10, stdin ) != NULL )
if( strlen(str) < 10 )
break;
}
}
}
else{
printf("Error: the number of characters must be < 10");
}
return 0;
}
int vowels(char str[]){
int i=0, j=0;
while(str[i] != '\0')
{
if(str[i] == 'a' || str[i] == 'A' || str[i] == 'e' ||
str[i] == 'E' || str[i] == 'i' || str[i] == 'I' ||
str[i] == 'o' || str[i] == 'O' || str[i] == 'u' ||
str[i] == 'U')
{
j++;
}
i++;
}
printf("Number of vowels in the string:%d\n", j);
return 0;
}
I'm pasting your code and adding comments inline. Note: I am not fixing anything, just pointing things out for you to fix.
#include <stdio.h>
#include <string.h>
int vowels(char str[]);
int main(){
int n, i, x;
printf("How many strings do you want to insert?");
scanf("%d", &n); // Consider a more descriptive variable name than 'n'
printf("How many characters per string?");
scanf("%d", &x); // Consider a more descriptive name here too.
char str[x]; // Note, a string needs 1 extra character for the NUL character.
if(x < 10){ // 10 is a very magic number. Consider making a constant.
for(i = 0; i < n; i++){
printf("Insert a string:");
scanf("%s", str);
if(strlen(str) == x){
vowels(str);
}
else{
printf("Error\n"); // Consider breaking or returning here if error...
}
}
}
else{
printf("Error: the number of characters must be < 10");
}
return 0;
}
int vowels(char str[]){ // Do you need a return value? What does it represent?
int i, j;
while(str[i] != '\0'){ // i and j are not initialized (to 0). Turning on compiler warnings would catch this.
// a for() loop may make more sense
if(str[i] == 'a' || str[i] == 'A' || str[i] == 'e' ||
str[i] == 'E' || str[i] == 'i' || str[i] == 'I' ||
str[i] == 'o' || str[i] == 'O' || str[i] == 'u' ||
str[i] == 'U'){
j++; }
i++;
}
printf("Number of vowels in the string:%d\n", j);
return 0; // Again, maybe this function returns void if we don't need a return.
}
The problems in the vowels function are caused by uninitialized variables. Neither i nor j is given an initial value. A good compiler will generate a warning about this. If you're compiling with gcc or clang, be sure to compile with -Wall -Wextra. Then read the warnings, and fix all of the warnings.
The variable i can be declared and initialized with a for loop, as shown below. The variable j should be given a more descriptive name, like count, and initialized before the loop. You might also want to return the count from the vowels function, and let main do the printing. That way, you can reuse the vowels function in a different program that needs to count vowels, but doesn't want the count printed.
int vowels(char str[]){
int count = 0;
for (int i=0; str[i] != '\0'; i++){
if(str[i] == 'a' || str[i] == 'A' || str[i] == 'e' ||
str[i] == 'E' || str[i] == 'i' || str[i] == 'I' ||
str[i] == 'o' || str[i] == 'O' || str[i] == 'u' ||
str[i] == 'U'){
count++;
}
}
return count;
}
The other problem in the program is that the str array is too small. A C string uses a zero byte (known as the NUL terminator) to mark the end of the string. So, for example, if the strlen of a string is 5, then the array holding the string must be at least 6 bytes, 5 for the string, plus one for the NUL.
In your program, you limit the string length to a number less than 10, so you could just declare the str array with a fixed size, e.g. char str[16], and it will always be big enough. OTOH, the scanf doesn't limit the number of characters written into the string, unless you tell it to. The code below shows how to limit the number of characters that scanf writes into the string.
int main(){
int n, x;
printf("How many strings do you want to insert?");
scanf("%d", &n);
printf("How many characters per string?");
scanf("%d", &x);
char str[16];
if(x < 10){
for(int i = 0; i < n; i++){
printf("Insert a string:");
if (scanf("%15s", str) != 1) {
printf("That wasn't a valid input\n");
break;
}
else if(strlen(str) == x){
int count = vowels(str);
printf("Number of vowels in the string:%d\n", count);
}
else{
printf("Error\n");
break;
}
}
}
else{
printf("Error: the number of characters must be < 10");
}
return 0;
}
Related
I am doing my C assignment for colleage. The task is requiring the function uses getchar() to read input from user and save it to a char[] type variable. Here is my code:
void readLine(char str[], int length){
int i = 0;
if(length < 1) return;
while(1){
str[i] = getchar();
if(str[i] == '\n'){
str[i] == '\0';
return;
}
if(i < length - 1) i++;
}
}
printf("String? ");
char inputString[LENGTH];
readLine(inputString, LENGTH);
the terminal will get frozen while the value of getchar() is assigned to str[i]. If I assigned it to an int type variable, no complains comes from terminal.
According to the doc of getchar(), it is returning int type and it is possible to assign to a char[]. So I am confused what I did wrong.
your problem is so simple:
instead of the line str[i] == '\0'; it's str[i] = '\0'; , not the difference between = and == , the first one is used in assignment , the second one is used to test whether the variable equals to this value or not.
you have a warning in this line str[i] = getchar(); as getchar() returns int not char and my compiler gave me this warning :
Clang-Tidy: Narrowing conversion from 'int' to signed type 'char' is implementation-defined
so you should cast the returned value from getchar() by writing str[i] = (char)getchar();
also , you should modify the condition if(str[i] == '\n') into if(str[i] == '\n' || i == length - 1) , imagine that the user entered number of chars exceeded the LENGTH , then you should store only the first chars that could fit.
with these only 3 small modifications , this is the edited code :
#include<stdio.h>
#include <stdlib.h>
#define LENGTH 10
void readLine(char str[], int length)
{
int i = 0;
if(length < 1) return;
while(1)
{
str[i] = (char)getchar();
if(str[i] == '\n' || i == length - 1)
{
str[i] = '\0';
return;
}
if(i < length - 1) i++;
}
}
int main(){
printf("String? ");
char inputString[LENGTH];
readLine(inputString, LENGTH);
printf("%s", inputString);
}
and this is the output :
String?test
test
I am trying to write a program to find all the vowels in a given string, however I don't know how to get my program to increase my count variable (numVowels)
I've looked for "getting size of array for iteration" etc.. Haven't been able to find anything specific to C.
int num_vowels(char string[]){
//int j;
int i;
int numVowels = 0;
//iterate through string searching for vowels
for(i = 0; i < sizeof(string); i++){
//if any vowels found
if (string[i] == 'a' ||string[i] == 'e' ||string[i] == 'i' ||string[i]
== 'o' ||string[i] == 'u'){
//increase count
numVowels++;
}
}
//print count
printf("Number of vowels: %d", numVowels);
return 0;
}
Input works fine, it's just i can't get it to print the numvowels, or even find out if it's going through the array.
Edit: I know, it's a long if statement, i'm going to fix that later
When you write "num_vowels(char string[])" you are not passing the string but the address of(pointer to) the first element of the character array "string".
Hence, when you do "sizeof(string)" the result would be the size of the character pointer, which could be either 4 or 8 depending upon the architecture.
As suggested in the comments, you could use "strlen" but please ensure including the "string.h" header.....The solution would be.....
#include <stdio.h>
#include <string.h>
int num_vowels(char string[]){
int i;
int numVowels = 0;
//iterate through string searching for vowels
for(i = 0; i < strlen(string); i++){ //use strlen(string)
//if any vowels found
if (string[i] == 'a' ||string[i] == 'e' ||string[i] == 'i' ||string[i]
== 'o' ||string[i] == 'u'){
//increase count
numVowels++;
}
}
//print count
printf("Number of vowels: %d", numVowels);
return 0;
}
Or you need not use "strlen" and dereference the pointer directly....
Like so......
int num_vowels(char string[]){
int i;
int numVowels = 0;
//iterate through string searching for vowels
for(; i = *string; string++){ //deference and increment pointer
//if any vowels found
if (i == 'a' || i == 'e' || i == 'i' || i
== 'o' || i == 'u'){
//increase count
numVowels++;
}
}
//print count
printf("Number of vowels: %d", numVowels);
return 0;
}
Little help to reduce your conditional if
#include <stdio.h>
#include <string.h>
int num_vowels(const char *string){
int numVowels = 0;
const char *wordToSearch = "aeiou";
//loop on string
for(int i = 0; i < strlen(string); i++) {
//loop on wordToSearch
for (int j = 0; j < strlen(wordToSearch); j++) {
if (string[i] == wordToSearch[j]) {
numVowels++;
}
}
}
printf("Number of vowels: %d", numVowels);
return 0;
}
Enter the array of 20 strings. Make program that prints out strings which have more consonants than vowels and in which letter 'r' is repeated at least 3 times.
I belive that the problem is in my if loops, but somehow i fail to understand why it does not work properly. It prints every string I enter.
This is the code i wrote:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void) {
char string[20][50];
int i, j;
int vowels=0;
int consonants=0;
int repeated_r=0;
printf("Enter the array of 20 strings:\n");
for(i=0;i<20;i++){
gets(string[i]);
}
for(i=0;i<20;i++){
for(j=0;j<50;j++){
if(string[i][j] == 'r'){
repeated_r++;
}
else if(string[i][j] == 'a' || string[i][j] == 'e' || string[i][j] == 'i' || string[i][j] == 'o' || string[i][j] == 'u'){
vowels++;
}
else{
consonants++;
}
}
if(consonants>vowels && repeated_r>=3){
fflush(stdin);
puts(string[i]);
}
}
return 0;
}
You need to reset the counters after processing each string.
And don't use gets use fgets instead.
for(i=0;i<20;i++){
for(j=0;j<50;j++){
if(string[i][j] == 'r'){
repeated_r++;
}
else if(string[i][j] == 'a' || string[i][j] == 'e' || string[i][j] == 'i' || string[i][j] == 'o' || string[i][j] == 'u'){
vowels++;
}
else{
consonants++;
}
}
if(consonants>vowels && repeated_r>3){
fflush(stdin);
puts(string[i]);
}
//Reset the counters
consonants =0;
vowels =0;
repeated_r =0;
}
}
Also note that in your current code r is not considered as consonant.
You are not resetting the initial values of the variables in the outer loop
int vowels=0;
int consonants=0;
int repeated_r=0;
Also the condition in the inner loop
for(j=0;j<50;j++){
^^^^
is not correct because in this case there is an access to memory beyond stored strings in the array.
The letter 'r' is not counted as a consonant.
Take into account that the function gets is not a standard C function that is it is not supported by the C Standard any more.
And this call
fflush(stdin);
has undefined behavior.
I can suggest the following solution as shown in the demonstrative program below.
#include <stdio.h>
#include <string.h>
int main( void )
{
enum { M = 3, N = 50 };
char s[M][N];
for ( size_t i = 0; i < M; i++ )
{
fgets( s[i], N, stdin );
s[i][strcspn( s[i], "\n" )] = '\0';
}
const char *vowels = "aeiou";
const char r = 'r';
for ( size_t i = 0; i < M; i++ )
{
size_t repeated_r = 0;
size_t vowels_count = 0;
size_t n = strlen( s[i] );
for ( size_t j = 0; j < n; j++ )
{
repeated_r += s[i][j] == r;
vowels_count += strchr( vowels, s[i][j] ) != NULL;
}
if ( repeated_r >= 3 && vowels_count < n - vowels_count )
{
puts( s[i] );
}
}
return 0;
}
If to enter the following strings
Hello World
errors
photosynthesis_bro
then the program output might look like
errors
there is one more problem in your code, ypu're using gets. It'll also include white spaces so say if your string is "_ _ rrrbaeeeeiou _ ". It will print this string but actually this string should not have been printed.
Note that "" means a blank space.
According to your code, "_" will be counted in consonants and even though there are 4 consonants in your string(3 r and 1 b) and 8 vowels, it will print this string as output since the blank spaces will be counted as consonants.
Also in your code r is not counted as consonant
I have a problem with my homework. I need to count quantity of upper case and quantity of vowels in string. Unfortunately, it always returns number 0 which looks as it doesn't change in function. Everything works until this one.
Here is my code:
#include <stdio.h>
#include <conio.h>
#include <string.h>
char *StringChange(char *text, int *upper, int *chars);
int main(void) {
char text[40];
int upper, chars;
puts("Type a string");
gets(text);
StringChange(text, &upper, &chars);
puts("Change words to start with upper case and change white spece to *");
puts(text);
printf("Quantity of upper case in string: %d\n", upper);
printf("Quantity of vowels: %d", chars);
getch();
return 0;
}
char *StringChange(char *text, int *upper, int *chars) {
int i, length;
length = strlen(text);
for (i = 1; i <= length; i++) {
if (text[i - 1] == '*' && (text[i] >= 'a' && text[i] <= 'z')) {
text[i] = text[i] - 32;
}
if (text[i] == ' ') {
text[i] = '*';
}
if (text[i] >= 'A' && text[i] <= 'Z') {
*upper = *upper + 1;
/* *upper++; that also doesn't work */
}
if (text[i] == 'a' || text[i] == 'e' || text[i] == 'i' || text[i] == 'o' || text[i] == 'u' || text[i] == 'y') {
*chars = *chars + 1;
/* *chars++; that also doesn't work */
}
}
if (text[0] >= 'a' && text[0] <= 'z') {
text[0] = text[0] - 32;
}
return (text);
}
I tried your code and I do get non-zero results -- depending on the input, of course, so maybe you are only testing on strings that produce zero.
However, the results are not always correct. There are two problems I found in the code:
1) As pointed out in a comment, you should initialize upper and chars to 0.
2) You are starting the loop at index 1, not index 0. I think you did this so you could look at text[i-1] inside the loop, but it is causing you to exclude the first character from your totals. You should start the loop index and 0 and figure out a different way to handle it within the loop. (Hint - note that the first if within the loop and the one following the loop have similar conditions and the same body.)
There are multiple issues in your code:
you should never use gets().
the variables upper and chars are not initialized
the function StringChange make a special case of text[0] but does not update the counts for this initial byte.
you hard code the conversion of lowercase to uppercase for ASCII.
you should stop at the end of the string
all white space is not replaced, on whitespace followed by a lowercase letter.
uppercase vowels should be counted too.
Here is a modified version:
#include <stdio.h>
char *StringChange(char *text, int *upper, int *chars);
int main(void) {
char text[200];
int upper, vowels;
puts("Type a string");
if (fgets(text, sizeof text, stdin)) {
StringChange(text, &upper, &chars);
puts("Change words to start with upper case and change white space to *");
puts(text);
printf("Quantity of upper case in string: %d\n", upper);
printf("Quantity of vowels: %d\n", vowels);
}
getchar();
return 0;
}
char *StringChange(char *text, int *upper, int *vowels) {
int i, at_start = 1;
*upper = *vowels = 0;
for (i = 0; text[i] != '\0'; i++) {
char c = text[i];
if (at_start && c >= 'a' && c <= 'z') {
c += 'A' - 'a';
text[i] = c;
}
if (c == ' ') {
c = '*';
text[i] = c;
at_start = 1;
} else {
at_start = 0;
}
if (c >= 'A' && c <= 'Z') {
(*upper)++; // *upper++ would just increment the pointer, leading to undefined behavior
}
if (strchr("aeiouyAEIOUY", c) {
(*vowels)++;
}
}
return text;
}
so I want to make a code where you can find the number of upper and lowercase letters in a string (no spaces)
So I want something like this:
input:
HEllO
Output:
2 3
So what I have of code is this:
#include<stdio.h>
int main() {
int upper = 0, lower = 0;
char ch[80];
int i;
printf("\nEnter The String : ");
gets(ch);
i = 0;
while (ch[i] != '') {
if (ch[i] >= 'A' && ch[i] <= 'Z')
upper++;
if (ch[i] >= 'a' && ch[i] <= 'z')
lower++;
i++;
}
printf("%d %d", upper, lower);
return (0);
}
There is a problem with the code, but I cannot find the mistake. Can someone please fix it? Thanks.
Corrected code-
#include <stdio.h>
int main(void)
{
int upper = 0, lower = 0;
char ch[80];
int i = 0;
printf("\nEnter The String : ");
fgets(ch, sizeof(ch), stdin);
while (ch[i] != '\0')
{
if (ch[i] >= 'A' && ch[i] <= 'Z')
upper++;
if (ch[i] >= 'a' && ch[i] <= 'z')
lower++;
i++;
}
printf("\nuppercase letter(s): %d \nlowercase letter(s): %d", upper, lower);
return 0;
}
Note: I have used fgets() instead of gets() as the latter suffers from a buffer overflow issue.
In C a string always terminates with '\0'. The empty string '' and the escape null character are not identical.
while (ch[i] != '') should be while (ch[i] != '\0')
Your program should work then.
The problem is the expression ''. A character constant must have something between the single quotes. In this case, you want to test for end of string, so you would use the null character constant: '\0'.
#include <stdio.h>
int main(void) {
int upper = 0, lower = 0;
char ch[80];
int i;
printf("\nEnter The String : ");
fgets(ch, sizeof(ch), stdin);
i = 0;
while (ch[i] != '\0') {
if (ch[i] >= 'A' && ch[i] <= 'Z')
upper++;
if (ch[i] >= 'a' && ch[i] <= 'z')
lower++;
i++;
}
printf("%d %d\n", upper, lower);
return 0;
}
Note that I also replaced gets with fgets. You should never use gets(). It doesn't get passed the length of your buffer, so if the input is more than 79 characters long, it will overflow the ch array, causing undefined behavior. fgets takes a size argument and stops reading once it's read size - 1. It also includes the newline in the resulting string if one is present in the input, which gets does not.
A better approach that works properly for all input lengths is to read the string in one character at a time, and not bother storing it, since all you care about is the count of upper and lower.
#include <stdio.h>
int main(void) {
unsigned upper = 0, lower = 0;
printf("\nEnter The String : ");
int c;
while (EOF != (c = getchar())) {
if ('\n' == c) break;
if (c >= 'A' && c <= 'Z')
upper++;
if (c >= 'a' && c <= 'z')
lower++;
}
printf("%u %u\n", upper, lower);
return 0;
}