Hello milkitaa,
I think I have it working right. At least to a way I think it should be. I am not saying it is the best way, but it works.
To start with:
1 2 3 4 5 6 7 8 9
|
#include <iostream>
#include <string>
#include <fstream>
#include <ctime> // <--- For "time".
#include <cstdlib> // <--- For "srand" and "rand".
//#include <cstring>
using namespace std;
| |
I added "cstdlib". Do not count on your compiler and header files to cover this for you. I know that VS will include "cstdlib" when I include "iostream", but not all compiler will do this.
For what its worth these include files are in 2 sections. The first is what I have found to be used in most all programs. Although the header files I include is a bit larger. The second group are the includes needed by this program.
In either group the order is not important, but in the first group I have found that alphabetical order helps to remind you what is missing.
Line 9 is a topic all to its-self. You may find this useful reading
http://www.cplusplus.com/forum/beginner/258335/ It is the most recent post that I have seen.
Something that you may not be aware of:
Everything between the {}s is private by default. So when you wrote:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
|
class Words
{
private: // <--- Already private at this point. But OK to leave.
int minlen, maxlen; //input in main
int count;
string * choices;
int fileStatus;
const std::string inFileName{ "file.txt" };
int count_candidates()
{
std::string word;
ifstream fin;
fin.open(inFileName);
//ifstream inFile(inFileName); // <--- An alternative to what is above.
if (!fin)
{
std::cout << "\n File \"" << inFileName << "\" did not open! in function \"count_candidates\".\n";
return 1;
}
while (fin >> word)
{
if (word.length() > minlen && word.length() < maxlen)
{
count++; // <--- Part of class.
//std::cout << word << '\n'; // <--- Used for testing. Comment or remove when finished.
}
}
fin.close();
return 0; // <--- Function ended with no problems.
}
| |
The comment on line 3 should explain it.
Lines 4, 5 and 6 are the variables required by step 1. I found the
string word
to not have any use here or need.
The next 2 variables I added. The "fileStatus" because of where the 2 private functions are called from and the string to make it easier to us. Now you have only 1 place to change the file name if it is ever needed.
The variable "word" is defined in the function that needs it and when the function ends so does the variable. This way it is not hanging around being unused.
Line 17 tends to speak for its-self. In time this is what you are likely to use more often.
When you open a file for input is is a must to check that it is open and ready to use. Line 19 is the simplest way to do this. There are other ways, but it is more work than you need.
Point 2 is covered with this private function, but I have a problem with it returning "count" when the function already has access to the private variable "count" and your original code used this variable. Si I used the return value a bit differently. More on that when I get to the function call.
Line 35 is not needed as the file stream will close when the function looses scope, but it is OK if you want to leave it.
The "load_words" function is much the same with a couple of changes.
1 2 3 4 5
|
void load_words()
{
size_t index{};
string word;
choices = new std::string[count];
| |
The first 2 variables are used only in the function. There is no need to define them anywhere else.
The 3rd line cover this part of point 3
create a dynamic string array of size count. |
In the if statement I changed to this:
choices[index++] = word;
. Not a good idea to use "count" here because you would have to set it to (0) zero. Better to keep the value that is in "count" and use a different variable to be safe. By using the post ++ you add 1 to the variable after it has been used. No need for extra code for this.
The other difference here is that I did not check if the file was opened. If it did not work in the "count_candidates" function you will not get this far and since this is to be a "void" return value there is no way to return anything.
Your original "pick_word" function you are doing more than you need to. The 2 function calls need to be in the overloaded ctor and you can simply write:
return choices[rand() % count];
. This does the same as what you started out with. To keep what you have started with I would write:
int result = rand() % count;
. This does the same as the 2 line that you have.
I added this:
int GetFileStatue() { return fileStatus; }
to deal with the file not opening correctly.
Foe the overloaded ctor:
1 2 3 4 5 6 7 8 9 10 11 12
|
Words(int min, int max)
{
minlen = min;
maxlen = max;
count = 0;
fileStatus = 0;
fileStatus = count_candidates();
if (!fileStatus)
load_words();
}
| |
This is where I used the return value of the "count_candidates" function differently. Since "fileStatus" is a class variable you just use it. Nothing special is needed. The if statement determines if the "load_words" function should be called. If not you return to "main".
"main" I set up this way:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
|
int main()
{
//srand(time(NULL));
srand(static_cast<size_t>(time(nullptr)));
int min{ 3 }, max{ 10 };
//cout << "Enter min: ";
//cin >> min;
//cout << "Enter max: ";
//cin >> max;
Words words(min, max);
if (words.GetFileStatue())
return 1;
std::cout << "\n The random word is: " << words.pick_word() << '\n';
//words.DisplayList(); // <--- Used for testing. Comment or remove when finished.
return 0;
}
| |
Starting with "size_t", and "size_type", these are aliases for an "unsigned int". As it was mentioned in the requirements the ".length()" and ".size()" functions return a "size_t" value. Also the ".length()" and ".size()" functions return the same number, i.e., the number of elements in the variable.
The way I have written "srand" tends to be the most portable way to do this and if you watch this video you will find the same information.
https://channel9.msdn.com/Events/GoingNative/2013/rand-Considered-Harmful
Also the video will explain the problems of using "rand" and if you know wnt to expect it helps.
Giving "min" and "max" a value and commenting out the input just makes it easier to check the rest of the program without having it enter something each time the program runs. When ready you can remove what is between the {}s for "min" and "max" just leaving the empty {}s. Not really necessary in this program, but a good idea to always initialize your variables. From C++11 on the empty {}s make it easier.
After getting a value for "min" and "max" what you did not do was to create an object of the class, see step 5.
Line 17 is where I use the return value of the "count_candidates" function and the variable "fileStatus" to determine if the program should continue. If not this is the best place to leave the program so that everything is destroyed before the program ends.
If the program does not end this is when you call the "pick_word" function to get a random word. And as you can see you can do this easily in the "cout" statement.
Last part. When it comes to using {}s be consistent. Changing styles in the code makes it harder to read. Have a look at:
https://en.wikipedia.org/wiki/Indentation_style#Brace_placement_in_compound_statements Of all the choices I prefer the "Allman" style the best. Along with the proper indenting it is the easiest to read and that should be your first goal to make the code easy to read. This is more for your benefit first then others.
I realize that I was not in the class leading up to this program, so my interpretation may be different than what is expected and that you may not be able to use what I have done.
If you have a problem let me know.
Andy