user486543
user486543

Reputation: 113

Recursive function that counts vowels

I have an assignment that asks me to "Write a recursive function vowels(s,low,high) that returns the number of vowels in an input string s[]." We are also limited by "Do not use the C++ string type. Read the characters into an array one at a time using cin.get()." I think I solved the task at hand, but it doesnt compile so I am unsure. If anyone could assist me and show how to fix my error and any errors I've made towards my solution that would be great.

Here is my error message.

***main.cpp:24:37: error: invalid conversion from ‘char*’ to ‘char’ [-fpermissive]
     vowelCount = vowels(s, low, high);**

Here is my code:

#include <iostream>
#include <cstring>
using namespace std;

int vowels(char, int, int);

int main()
{
    char s[500];
    int high,
        vowelCount,
        low = 0;

    cout << "Enter a string of characters: ";
        cin.get(s, 500);

    high = strlen(s);
    vowelCount = vowels(s, low, high);

    cout << "The string contains " << vowelCount << " vowels." << endl;

    return 0;
}

int vowels(char s[], int low, int high)
{
    if (s[low] == 'a' || 'A' || 'e' || 'E' || 'i' || 'I' || 'o' || 'O' || 'u' || 'U') {
        return 1 + vowels(s, low + 1, high - 1);
    } else {
        return vowels(s, low + 1, high - 1);
    }
}

Upvotes: 0

Views: 1282

Answers (1)

A M
A M

Reputation: 15265

We are talking about a so called XY-Problem here.

The teacher wants to cover recursive functions. The vowel counting is just some noise. Unfortunately the given example is a bad one, because it could be implemented by far better with an iterative approach.

The recursion is just adding unnecessary time and space complexity. So, the performance is worse compared to a simple loop in all cases.

If the teacher wants that you learn about recursion, you may want to first look at this description or that more practical example.

After having read this, you will understand that a loop can be simply converted into a recursive function.

I am not sure, why there is a "low" and a "high" parameter. Maybe because of the usage of C-strings stored in a char array (what is nonsense in C++). I doubt that 2 self calls should be established and the function should walk from the begin and the end of the string to the middle. That would even further reduce the performance. So, let us assume the standard case.


Next to your problem with the comparison. What you have written is wrong. The correct comparison in C++ would be:

if ((s[low] == 'a') || (s[low] == 'A') || (s[low] == 'e') || 
   (s[low] == 'E') || (s[low] == 'i') || (s[low] == 'I') || 
   (s[low] == 'o') || (s[low] == 'O') || (s[low] == 'u') || 
   (s[low] == 'U'))

Of course, nobody would write such a long statement, because you can simply calculate, without any comparison, if an ASCII character is a vowel. You could simply write:

if (std::isalpha(s[low]) && ((0x208222 >> (s[low] & 0x1f)) & 1))

and thats it. If you are interested, I can explain the theory later, but not needed for this example.

Then, next, your recursive function is dangerously wrong, because it does not have an end condition. it will run forever or until the stack overflows.

So, you need to rework that, It could be done like this:

#include <iostream>
#include <cstring>
using namespace std;

int vowels(char[], int, int);

int main()
{
    char s[500];
    int high,
        vowelCount,
        low = 0;

    cout << "Enter a string of characters: ";
        cin.get(s, 500);

    high = strlen(s);
    vowelCount = vowels(s, low, high);

    cout << "The string contains " << vowelCount << " vowels." << endl;

    return 0;
}

int vowels(char s[], int low, int high)
{
    int sum = 0;
    if (low != high) {
        if ((s[low] == 'a') || (s[low] == 'A') || (s[low] == 'e') || 
            (s[low] == 'E') || (s[low] == 'i') || (s[low] == 'I') || 
            (s[low] == 'o') || (s[low] == 'O') || (s[low] == 'u') || 
            (s[low] == 'U')) 
        {
            ++sum; 
        }
        sum += vowels(s,low+1,high);
    }
    return sum;
}

If we go a little bit more into the direction of C++ and use meaningful variable names and comments, then we could come up with that:

#include <iostream>
#include <cstring>

// A recursive function to count the vowels in a rang of a text
int countVowelsRecursive(char textToEvaluate[], unsigned int startPositionForEvaluation, unsigned int endPositionOfText)
{
    // Here we will store the number of vowels. We will use tail recursion 
    // So, the overall calculation will be done at the end 
    unsigned int numberOfVowelsInThisRecursion = 0u;
    
    // Now we are evaluating this character from the text
    const char currentChar = textToEvaluate[startPositionForEvaluation];
    
    // Check, for the end of recursion condition
    if (startPositionForEvaluation != endPositionOfText) {

        // Check, if it is a vowel
        if ((currentChar == 'a') || (currentChar == 'A') || (currentChar == 'e') || 
            (currentChar == 'E') || (currentChar == 'i') || (currentChar == 'I') || 
            (currentChar == 'o') || (currentChar == 'O') || (currentChar == 'u') || 
            (currentChar == 'U')) 
        {
            // Vowel found. Increase counter by one 
            ++numberOfVowelsInThisRecursion; 
        }
        // Tail recursion. Self call, starting at next position of the string
        numberOfVowelsInThisRecursion += 
            countVowelsRecursive(textToEvaluate,startPositionForEvaluation + 1, endPositionOfText);
    }
    // This will be the final result
    return numberOfVowelsInThisRecursion;
}

// We will allow a maximal input text length like this
constexpr unsigned int MaxTextLength = 500u;

// Driver code / test function
int main()
{
    // Here we will store the text from the user 
    char text[MaxTextLength]{};
    
    // Give instructions and get the text
    std::cout << "Enter a string of characters: ";
    std::cin.get(text, MaxTextLength);

    // Set text parameters for the evaluation 
    unsigned int startOfText = 0u;
    unsigned int endOfText = static_cast<unsigned int>(strlen(text));
    
    // Calculate the vowels
    unsigned int vowelCount = countVowelsRecursive(text, startOfText, endOfText);

    // Show result to user 
    std::cout << "The string contains " << vowelCount << " vowels." << std::endl;

    return 0;
}

And if we would be allowed to use C++ then we would write:

#include <iostream>
#include <string>
#include <algorithm>

int main()
{
    // Give instructions and get the text
    std::cout << "\nEnter a text:\n";
    if (std::string text{}; std::getline(std::cin, text))

        // Show result to user 
        std::cout << "\n\nThe string contains " 
            << std::count_if(text.begin(), text.end(), [](const char c){ return std::isalpha(c) && ((0x208222 >> (c & 0x1f)) & 1);})
            << " vowels.\n";

    return 0;
}

Have fun . . .

Upvotes: 2

Related Questions