0

I'm currently learning C++ and have written a bit of code that selects and plays a random film quote.

The starting point of the code is an array of strings that looks like this:

string filmQuotes[] = { "film1.wav", "film2.wav", "film3.wav" etc etc "film40.wav" };

As all the strings have the pattern film+n.wav I thought there must be a better way of declaring them?

Something like:

int i;
for( i = 1; i < 41; i++ ){
    filmQuotes[] = "film"+i+".wav";
}

I know the above is a bit of mixture of languages but hopefully you'll understand what I'm looking to do.

Thanks

1
  • 2
    You can use iteration to fill a std::vector. Also please read about std::to_string. Commented Oct 1, 2019 at 13:35

3 Answers 3

3

Best way would be to use std::vector instead of C-style array:

std::vector<std::string> filmQuotes;
filmQuotes.reserve(40); //only needed to avoid a couple reallocations, can be ommitted
for( i = 1; i < 41; i++ ){
    std::string name = "film" + std::to_string(i) + ".wav";
    filmQuotes.push_back(name);
}

Could be done a little bit fancier with std::generate_n from <algorithm> (lambda captures are available from C++14 and up):

std::vector<std::string> filmQuotes;
std::generate_n(std::back_inserter(filmQuotes), 
                40, 
                [fileNumber=1]() mutable { return "film" + std::to_string(fileNumber++) + ".wav"; });

Or without lambda captures:

std::vector<std::string> filmQuotes;
std::generate_n(std::back_inserter(filmQuotes), 40, [](){ 
     static int fileNumber = 1;
     return "film" + std::to_string(fileNumber++) + ".wav"; 
});
Sign up to request clarification or add additional context in comments.

3 Comments

@GuillaumeRacicot What is wrong with static? It's scoped to the lambda which can't be accessed after the expression so there is no reuse concerns. It also saves from having a weird looking capture and having to specify the lambda as mutable.
@NathanOliver There are both versions now :)
@Yksisarvinen a big thank you for your comprehensive answer. I've marked it as the answer to the question as it seems to cover different ways to achieve the same thing. I've just got to dissect it now and try and understand it better! Thanks again for taking the time and trouble to answer my question so well. Cheers :-)
3

Easiest way to do it is as follows:

#include <vector>
#include <string>

int main()
{
    std::vector<std::string> filmQuotes;
    for (int i = 0; i < 41; i++)
        filmQuotes.push_back("film" + std::to_string(i) + ".wav");
}

Comments

2

There is no need for recursion here, a loop will serve you well. Using a std::vector if the size is only known at run time, or a std::array if the size is known at compile time you can loop through the indices and convert it to a string using std::to_string This gives you a std::string object that you can add your string literals too. That would give you code like

std::size_t size = some_value;
std::vector filmQuotes;
filmQuotes.reserve(size);
for (std::size_t i = 0; i < size; ++i)
    filmQuotes.emplace_back("film" + std::to_string(i) + ".wav");

or

constexpr std::size_t size = some_constant_value;
std::array<std::string, size> filmQuotes;
for (std::size_t i = 0; i < size; ++i)
    filmQuotes[i] = "film" + std::to_string(i) + ".wav");

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.