I'm having a problem with pop_back() in c++

108 Views Asked by At

I'm trying to write a program in C++ that can swap the vocals on a sentence (by reversing it).

#include <iostream>
#include <string>
#include <vector>

int main() {
    // declare the variables
    std::string text;
    char vocals[] = {'a', 'i', 'u', 'e', 'o', 'A', 'I', 'U', 'E', 'O'};

    // get the input
    std::cout << "input the text: ";
    std::getline(std::cin, text);

    // declare the vector to store the vocals
    std::vector<char> v(text.length());

    // identify the vocals
    for (int i = 0; i < text.length(); i++) {
        for (int j = 0; j < 10; j++) {
            if (text[i] == vocals[j]) {
                v.push_back(text[i]);
            }
        }
    }

    // swap the vocals
    for (int i = 0; i < text.length(); i++) {
        for (int j = 0; j < 10; j++) {
            if (text[i] == vocals[j]) {
                text[i] = v.back();
                v.pop_back();
            }
        } 
    }

    // print the result
    std::cout << "the new text is: " << text << std::endl;

    return 0;
}

The problem is, when I input "vocal switch test run", it outputs "vucil swatch tst rn" instead.

I debugged the code by printing text[i] in the last for loop, all the vocals are present in the vectors.

2

There are 2 best solutions below

0
Chris On

As noted in comments, you're missing a break in each of your loops. Adding these breaks means that for each character in the string that is a vowel, we only add (or in the second loop) subtract one character at a time from the vector.

#include <iostream>
#include <string>
#include <vector>

int main() {
    // declare the variables
    std::string text;
    char vocals[] = {'a', 'i', 'u', 'e', 'o', 'A', 'I', 'U', 'E', 'O'};

    // get the input
    std::cout << "input the text: ";
    std::getline(std::cin, text);

    // declare the vector to store the vocals
    std::vector<char> v(text.length());

    // identify the vocals
    for (int i = 0; i < text.length(); i++) {
        for (int j = 0; j < 10; j++) {
            if (text[i] == vocals[j]) {
                v.push_back(text[i]);
                break;
            }
        }
    }

    // swap the vocals
    for (int i = 0; i < text.length(); i++) {
        for (int j = 0; j < 10; j++) {
            if (text[i] == vocals[j]) {
                text[i] = v.back();
                v.pop_back();
                break;
            }
        }
    }

    // print the result
    std::cout << "the new text is: " << text << std::endl;

    return 0;
}
$ ./a.out
input the text:  vocal switch test run
the new text is:  vucel switch tast ron

Taking greater advantage of the STL, I might write the following, using a is_vowel function that leverages std::set<char> and std::copy_if as well as a range-based for loop.

#include <set>
#include <vector>
#include <string>
#include <iostream>
#include <algorithm>

bool is_vowel(char ch) {
    static std::set<char> vowels {
        'a', 'e', 'i', 'o', 'u',
        'A', 'E', 'I', 'O', 'U'
    };

    return vowels.find(ch) != vowels.end();
}

int main() {
    std::string text;
    std::vector<char> v;

    std::getline(std::cin, text);
    std::copy_if(
        text.cbegin(), text.cend(),
        std::back_inserter(v),
        is_vowel
    );

    for (auto &ch : text) {
        if (is_vowel(ch)) {
            ch = v.back();
            v.pop_back();
        }
    }

    std::cout << text << std::endl;
}
0
zdf On

Here are some observations that might help you.

(1) You can look up vowels using a lookup-table. Here’s a quick solution:

// vowels lookup table - all false except for vowels
bool v[256]{};
v['a'] = v['e'] = v['i'] = v['o'] = v['u'] =
v['A'] = v['E'] = v['I'] = v['O'] = v['U'] = true;

(2) A string is reversed by using two indexes: one moving from left to right and one moving from right to left. The characters associated to those indexes are swapped. You can use the same principle, except you must skip the consonants.

// look for the next vowel from left to right
while (i < j && !v[s[i]]) ++i; 

// look for the next vowel from right to left
while (i < j && !v[s[j]]) --j; 

(3) Once you have considered both the left and right sides, you stop.

// if the left side and the right side were already considered, exit the loop
if (i >= j) 
  break;