Problem generating random number

Hey everyone, I have a question that it seems like I shouldn't have. I am recreating a hangman game that I made in my c++ class last semester, just for practice, for comparison, and fun. I'm trying to generate a random number to help choose which word from my words list to use and I've done it a billion times before just like this. So, here's my code:

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
39
40
41
#include <iostream>
#include <cstdlib> //standard library.
#include <ctime> //for random.
#include <fstream> //for reading and writing to a file.
#include <string>

using namespace std;

int main()
{
  int num_words;
  string word[num_words];
  ifstream infile;
  ofstream outfile;
  
  // read in words for the word list
  infile.open("words.txt");
  infile >> num_words;
  for(int i = 0; i < num_words; i++)
  {
    infile >> word[i];
  }
  
  infile.close();
  
  // Generate a random number to get a word from the word list.
  long  seed = time(NULL); // gets current time
  srand(seed);
  int random_num = rand(); // Computer's random selection

  cout << random_num % 5<< endl;


  // Debug
  for(int i = 0; i < num_words; i++)
  {
    cout << word[i] << endl;
  }  
  
}


I have the text file "words.txt" info below.

5
dog
cat
horse
pig
bird

If I run the program as it is, I get a segmentation fault core dumped error, however, if I take all the stuff that reads in the words from the words.txt file, like so:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <iostream> //every program has this.
#include <cstdlib> //standard library.
#include <ctime> //for random.
#include <fstream> //for reading and writing to a file.
#include <string>

using namespace std;

int main()
{
  long  seed = time(NULL); // gets current time
  srand(seed);
  int random_num = rand(); // Computer's random selection

  cout << random_num << endl;
  
}


it works correctly and generates a random number. I have no idea what's going on and would greatly appreciate any help.

(Also, just a side note, I'm using Linux Mint. I believe I wrote the last version of this on Windows. I can't really remember.)
1
2
>  int num_words;  
    string word[num_words]; // ??? 


This is not standard C++, it belongs to a non-standard dialect that the GCC crowd calls gnucxx.

Even if it were syntactically correct (it would be in C++14), it results in undefined behaviour - num_words has not been initialized before it is used.

Tip: compile with -std=c++11 -pedantic-errors -Wall -Wextra
Why not just call your string array string word[5], since you know there are 5 words. Or otherwise, if you want its size to be somewhat dynamic, then read in the number of lines in the file and assign that value to num_words, before the declaration string word[num_words].

Also, #include <iostream> //every program has this. This is not true. ;)
It is legal to use a variable into size of array
1
2
int a = 5;
int b[a];

Is legal in all compilers and also in all versions of C/C++..... the important thing is that the int variable must be initialized before being used as value for array dimension.

mhaggard: I would suggest to use std::vector<std::string> instead of an array of std::string

in that case I would replace code in 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
26
27
28
int main() {
  std::vector <std::string> word;
  ifstream infile;
  
  // read in words for the word list
  infile.open("words.txt"); //now "words.txt" does not require to start with "5" (number of words)
  while (!infile) {  //continue until end of file
    std::string tstr;
    infile >> tstr;
    word.append(tstr);
  }
  
  // Generate a random number to get a word from the word list.
  long  seed = time(NULL); // gets current time
  srand(seed);
  int random_num = rand(); // Computer's random selection

  cout << random_num % 5<< endl;


  // Debug
  for(int i = 0; i < word.size(); i++)
  {
    cout << word[i] << endl;
  } 

  return 0;
}


if you really want to mantain array approach (and bind dimension of the first value).
In this case you must, instead, specify in first line of word.txt the size of the array (in this case "5")

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
int main() {
   int num_words=0; //it is a good thing to initialize the value even if it is not the desired one
  ifstream infile;  
  //NOTE: we already don't know size of array becouse we don't know num_words
  //  so we cannot declare here string world[num_worls] becouse the array would be invalid
  infile.open("words.txt");
  infile >> num_words;
  //now num_words is truely initialized. It will be "5" as the first line of wolrds.txt
  //so AT THIS POINT we can declare the array "word"
  std::string word[num_words]; //now we can declare it... and not before this moment
  for(int i = 0; i < num_words; i++)
  {
    infile >> word[i];
  }
  
  infile.close();
  
  // Generate a random number to get a word from the word list.
  long  seed = time(NULL); // gets current time
  srand(seed);
  int random_num = rand(); // Computer's random selection

  cout << random_num % 5<< endl;


  // Debug
  for(int i = 0; i < num_words; i++)
  {
    cout << word[i] << endl;
  }  
  
> Is legal in all compilers and also in all versions of C/C++.....

For C++, see: http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2013/n3639.html

As far as C goes, VLA was not there in C89, was made mandatory in C99, and is now optional with C11.

An array (or a vector) is not required for this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <string>
#include <iostream>
#include <random>
#include <ctime>

// invariant: first line of stm contains the number of words in it
std::string random_word( std::istream& stm )
{
    std::string word ;

    int n ;
    if( stm >> n && n > 0 )
    {
        static std::mt19937 rng( std::time(nullptr) ) ;
        const int r = std::uniform_int_distribution<int>( 1, n )(rng) ;
        for( int i = 0 ; i < r ; ++i ) stm >> word ;
    }

    return word ;
}
That's how i would write a Hangman game, just to give you ideas.

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
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <ctime>
#include <cctype>

using namespace std;

int main()
{
    // set-up
    const int MAX_WRONG = 8;  // maximum number of incorrect guesses allowed

    vector<string> words;  // collection of possible words to guess
    words.push_back("GUESS");
    words.push_back("HANGMAN");
    words.push_back("DIFFICULT");

    srand(static_cast<unsigned int>(time(0)));
    random_shuffle(words.begin(), words.end());
    const string THE_WORD = words[0];            // word to guess
    int wrong = 0;                               // number of incorrect guesses
    string soFar(THE_WORD.size(), '-');          // word guessed so far
    string used = "";                            // letters already guessed

    cout << "Welcome to Hangman.  Good luck!\n";

    // main loop
    while ((wrong < MAX_WRONG) && (soFar != THE_WORD))
    {
        cout << "\n\nYou have " << (MAX_WRONG - wrong);
		cout << " incorrect guesses left.\n";
        cout << "\nYou've used the following letters:\n" << used << endl;
        cout << "\nSo far, the word is:\n" << soFar << endl;

        char guess;
        cout << "\n\nEnter your guess: ";
        cin >> guess;
        guess = toupper(guess); //make uppercase since secret word in uppercase
        while (used.find(guess) != string::npos)
        {
            cout << "\nYou've already guessed " << guess << endl;
            cout << "Enter your guess: ";
            cin >> guess;
            guess = toupper(guess);
        }

        used += guess;

        if (THE_WORD.find(guess) != string::npos)
        {
            cout << "That's right! " << guess << " is in the word.\n";

            // update soFar to include newly guessed letter
            for (unsigned int i = 0; i < THE_WORD.length(); ++i)
			{
                if (THE_WORD[i] == guess)
				{
                    soFar[i] = guess;
				}
			}
        }
        else
        {
            cout << "Sorry, " << guess << " isn't in the word.\n";
            ++wrong;
        }
    }

    // shut down
    if (wrong == MAX_WRONG)
        cout << "\nYou've been hanged!";
    else
        cout << "\nYou guessed it!";
    
    cout << "\nThe word was " << THE_WORD << endl;

    return 0;
}
@Mats: Also, #include <iostream> //every program has this. This is not true. ;)

^^ Ha yea I know. I just copied my "#includes" and that was there from the first time I wrote the program when I started the class. Thanks for pointing that out though.

Here is my new code:

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
39
40
41
42
43
44
45
46
47
48
49
#include <iostream>
#include <cstdlib>
#include <ctime>
#include <fstream>
#include <string>
#include <vector>

using namespace std;

int main()
{
    ifstream infile;
  
    vector<string> word; // Use a vector instead of an array.

    // read in words for the word list
    infile.open("words.txt");
    
    while(!infile)
    {
	string tstr;
	infile >> tstr;
	word.push_back(tstr);
    }
	
    

    for(int i = 0; i < num_words; i++)
    {
    infile >> word[i];
    }

    infile.close();

    // Generate a random number to get a word from the word list.
    long  seed = time(NULL); // gets current time
    srand(seed);
    int random_num = rand(); // Computer's random selection

    cout << random_num % 5<< endl;


    // Debug
    for(int i = 0; i < word.size(); i++)
    {
    cout << word[i] << endl;
    }  

}


@Nobun: I really like the vector approach, but when I compile I get this error:

class std::vector<std::basic_string<char> >’ has no member named ‘append’

so, I changed append to push_back (Sorry if that's dumb I'm not too familiar with vectors. it's kind of a learn as I go thing with them) and now it compiles fine, but the program stalls when running.

Thank all of you so much for your help so far. Sorry for all the dumb questions.
Last edited on
Sorry I make an error... this is becouse I am more used to use Qt than std::vector.

So I used "append()" instead of "push_back" sorry

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
int main() {
  std::vector <std::string> word;
  ifstream infile;
  
  // read in words for the word list
  infile.open("words.txt"); //now "words.txt" does not require to start with "5" (number of words)
  while (!infile) {  //continue until end of file
    std::string tstr;
    infile >> tstr;
    word.push_back(tstr);
  }
  
  // Generate a random number to get a word from the word list.
  long  seed = time(NULL); // gets current time
  srand(seed);
  int random_num = rand(); // Computer's random selection

  cout << random_num % 5<< endl;


  // Debug
  for(int i = 0; i < word.size(); i++)
  {
    cout << word[i] << endl;
  } 

  return 0;
Topic archived. No new replies allowed.