0

I'm new here, and very new to programming, and for all the time I spent scouring the internet and this site, I can't seem to find an answer to this question of mine. I need to randomly pick a single element out of a list of characters and print it, and then repeat this a user-entered number of times. I'm trying to make a text generator for typing practice with individual keys, not words. (Yes, I know I am so very late to the "typing correctly" party, but my forays into coding made me see it was a more useful skill than I thought.)
So far, I have mostly found answers that use an iterator to print all the elements of a list in a row, which isn't what I want. I also keep coming across people saying to use a vector instead of a list, but my C++ book I started learning from doesn't go into a lot of things that are "too advanced", so I'm stuck there. Using a list seems like a good idea to me though, but it could just be my beginner-ness talking. An array would be too rigid for what I want to accomplish, because if the user could enter in the keys they want in a later version of this program, and not just code them in like I did for the first try, it would be more ideal. But anyway, my program looks like this now:

// Version 1
// Text Generator for Typing Practice with Individual Keys:
//  For inputting into typing practice programs/sites with "insert your text" fields.
//   Generates a random list of letters from a list of known keys,
//    that only displays up to a user-entered amount of characters,
//     separated into paragraphs.

#include <iostream>
#include <cstdlib>
#include <list>
#include <ctime>

using namespace std;

int main () {

//Declare variables used below
int x = 0;
int list_size = 0;
int p = 0;

// Add new letters to the list below as you learn them!
list <char> Keys_Known = {' ', ' ', ' ', 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', 'e', 'r', 'u', 'i'};

// Define function(s) used below
char get_Text(); {
        for (int i = 0; i <= x; ++i) { // For x amount of times

            p = srand(time(nullptr)) % list_size;
            // Randomly choose a character from the list by its index,
            //  limited to the total number of elements in the list,

            cout << Keys_Known[p];
            //   and finally output the letter value of the index.
        }
    }

// Get and set list_size here
list_size = Keys_Known.size();

cout << "Enter total number of characters wanted: " << endl;
cin >> x;
// Set x to the total number of characters wanted in your practice text.
//  Maybe about 100 is good? ((Try with 10 for testing!))

cout << get_Text() << "/n" << get_Text() << "/n";
// Print two blocks of random text separated into paragraphs.

return 0;
}

I keep getting errors on the types of int p and int list_size not working with %, which is how I usually limit a random number range. Eclipse also tells me that I can't say 'Keys_Known []' anything because it has no idea what [] is supposed to mean. I even tried putting a 0 in there but it still acts like I can't use indexes. Am I missing an '#include' header? The exact errors I get are:
"invalid operands of types 'void' and 'int' to binary 'operator%' line 29 C/C++ Problem"
and:
"no match for 'operator[]' (operand types are 'std::__cxx11::list' and 'int') line 33 C/C++ Problem"

Any help would be appreciated, thanks!

KG911
  • 13
  • 1
  • 4

2 Answers2

0
  1. std::list is not a random access container. Hence, you may not use Keys_Known[p] to access an element.

    You may use an array or a std::vector.

    An array would work just fine for your needs.

  2. There is lack of clarity in what you are trying to do -- at least the intention hasn't translated to code. It will be helpful to learn the fundamentals of the language from a good book.

Here's your code, updated and annotated. Hope it is helpful.

#include <iostream>
#include <cstdlib>
#include <list>
#include <ctime>

using namespace std;

int main () {

   //Declare variables used below
   int x = 0;
   int list_size = 0;
   int p = 0;

   // Add new letters to the list below as you learn them!
   char Keys_Known[] = {' ', ' ', ' ', 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', 'e', 'r', 'u', 'i'};

   // Seed the random number generator.
   srand(time(nullptr));

   // Get and set list_size here
   list_size = sizeof(Keys_Known)/sizeof(Keys_Known[0]);

   cout << "Enter total number of characters wanted: " << endl;
   cin >> x;

   // Define function(s) used below

   // Incorrect.
   // This will execute the code in the loop x+1 times.
   // for (int i = 0; i <= x; ++i) // For x amount of times

   // Correct. Choose one.
   // for (int i = 0; i = x; ++i) // For x amount of times
   for (int i = 1; i <= x; ++i) // For x amount of times
   {

      // Get a random number mod list_size..
      p = rand() % list_size;

      // Randomly choose a character from the list by its index,
      //  limited to the total number of elements in the list,

      cout << Keys_Known[p];
      // and finally output the letter value of the index.
   }

   cout << endl;

   return 0;
}
R Sahu
  • 204,454
  • 14
  • 159
  • 270
0

A couple of things are going on here:

As mentioned by Öö Tiib, the function srand(unsigned int) seeds the random number generator and returns void. You should seed the random number generator once with srand(unsigned int), then call rand() to generate a random integer.

Second, list<T> is not a random access container, so unlike other containers, no operator[] is defined. The documentation tells us that list<T> is implemented as a doubly-linked list designed to allow constant time inserts and deletes, but lacks direct access to an element at a given position:

The main drawback of lists and forward_lists compared to these other sequence containers is that they lack direct access to the elements by their position; For example, to access the sixth element in a list, one has to iterate from a known position (like the beginning or the end) to that position, which takes linear time in the distance between these.

You probably don't want to use a list<char> here anyway. Some more efficient options would be:

  1. vector<char>, which does have a random access operator[] defined, and can be used as a drop-in replacement in your code;
  2. string, which is a container of chars that also has operator[] defined;
  3. or just a plain old char[list_size], which is all you really need here to get the job done, and is what I would recommend: you don't need all the fancy iterators, search methods, or dynamic allocation that you get from using an std container.
PaSTE
  • 4,050
  • 18
  • 26
  • Note that option (3) relies on variable-length arrays, which are not part of the C++ language (although they may still work, if the compiler the questioner is using supports them as a compiler-specific extention -- the code will not be portable though) – Jeremy Friesner Aug 27 '18 at 03:37