iterate char by char through vector of strings

Viewed 57

I want to iterate char by char in a vector of strings. In my code I created a nested loop to iterate over the string, but somehow I get an out of range vector.

void splitVowFromCons(std::vector<std::string>& userData, std::vector<std::string>& allCons, std::vector<std::string>& allVows){
    for ( int q = 0; q < userData.size(); q++){
        std::string userDataCheck = userData.at(q);
        for ( int r = 0; r < userDataCheck.size(); r++){
            if ((userDataCheck.at(r) == 'a') || (userDataCheck.at(r) == 'A') || (userDataCheck.at(r) == 'e') || (userDataCheck.at(r) == 'E') || (userDataCheck.at(r) == 'i') || (userDataCheck.at(r) == 'I') || (userDataCheck.at(r) == 'o') || (userDataCheck.at(r) == 'O') || (userDataCheck.at(r) == 'u') || (userDataCheck.at(r) == 'U')){
                allVows.push_back(userData.at(r));
            }
            else if ((userDataCheck.at(r) >= 'A' && userDataCheck.at(r) <= 'Z') || (userDataCheck.at(r) >= 'a' && userDataCheck.at(r) <= 'z')){
                allCons.push_back(userData.at(r));
            }
            else {
                continue;;
            }
        }
    }
}
2 Answers

The error here is in these lines:

allVows.push_back(userData.at(r));
allCons.push_back(userData.at(r));

the r variable is your index into the current string, but here you're using it to index into the vector, which looks like a typo to me. You can make this less error prone using range-for loops:

for (const std::string& str : userData) {
    for (char c : str) {
        if (c == 'a' || c == 'A' || ...) {
            allVows.push_back(c);
        }
        else if (...) {
            ....
        }
    }
}

which I hope you'll agree also has the benefit of being more readable due to less noise. You can further simplify your checks with a few standard library functions:

for (const std::string& str : userData) {
    for (char c : str) {
        if (!std::isalpha(c)) continue; // skip non-alphabetical
        char cap = std::toupper(c); // capitalise the char
        if (cap == 'A' || cap == 'E' || cap == 'I' || cap == 'O' || cap == 'U') {
            allVows.push_back(c);
        }
        else {
            allCons.push_back(c);
        }
    }
}

Since this question is about debugging actually, I think it is a nice illustration of how the usage of std::algorithms of C++ can decrease the effort needed to see what is wrong with a non working code.

Here is how it can be restructured:

bool isVowel(char letter)
{
    return letter == 'A' || letter == 'a' ||
    letter == 'E' || letter == 'e'||
    letter == 'O' || letter == 'o'||
    letter == 'Y' || letter == 'y'||
    letter == 'U' || letter == 'u';
}

bool isConsonant(char letter)
{
    return std::isalpha(letter) && !isVowel(letter);
}

void categorizeLetters(const std::vector<std::string> &words, std::vector<char> &vowels, std::vector<char> &consonants)
{
    for( const std::string &word : words){
        std::copy_if(word.begin(), word.end(), std::back_inserter(vowels), isVowel);
        std::copy_if(word.begin(), word.end(), std::back_inserter(consonants), isConsonant);
    }
}

With a solution like this, you avoid the error-prone access-with-index that lead to your problem. Also, code is readable and comprehensive

Related