简体   繁体   中英

Trouble getting string to print random line from text file

I picked up this bit of code a while back as a way to select a random line from a text file and output the result. Unfortunately, it only seems to output the first letter of the line that it selects and I can't figure out why its doing so or how to fix it. Any help would be appreciated.

#include "stdafx.h"
#include <stdio.h>
#include <iostream>
#include <fstream>
#include <string>
#include <time.h>
using namespace std;

#define MAX_STRING_SIZE 1000

string firstName()
{
    string firstName;
    char str[MAX_STRING_SIZE], pick[MAX_STRING_SIZE];
    FILE *fp;
    int readCount = 0;

    fp = fopen("firstnames.txt", "r");
    if (fp)
    {
        if (fgets(pick, MAX_STRING_SIZE, fp) != NULL)
        {
            readCount = 1;
            while (fgets (str, MAX_STRING_SIZE, fp) != NULL)
            {
                if ((rand() % ++readCount) == 0)
                {
                    strcpy(pick, str);
                }
            }
        }
    }
    fclose(fp);
    firstName = *pick;
    return firstName;
}

int main() 
{
    srand(time(NULL));

    int n = 1;
    while (n < 10)
    {
        string fn = firstName();
        cout << fn << endl;
        ++n;
    }

    system("pause");
}
 firstName = *pick;

I am guessing this is the problem.

pick here is essentially a pointer to the first element of the array, char* , so of course *pick is of type char .. or the first character of the array.

Another way to see it is that *pick == *(pick +0) == pick[0]

There are several ways to fix it. Simplest is to just do the below.

return pick;

The constructor will automatically make the conversion for you.

Since you didn't specify the format of your file, I'll cover both cases: fixed record length and variable record length; assuming each text line is a record.

Reading Random Names, Fixed Length Records

This one is straight forward.

  1. Determine the index (random) of the record you want.
  2. Calculate the file position = record length * index.
  3. Set file to the position.
  4. Read text from file, using std::getline .

Reading Random Names, Variable Length Records

This assumes that the length of the text lines vary. Since they vary, you can't use math to determine the file position.

To randomly pick a line from a file you will either have to put each line into a container, or put the file offset of the beginning of the line into a container.

After you have your container establish, determine the random name number and use that as an index into the container. If you stored the file offsets, position the file to the offset and read the line. Otherwise, pull the text from the container.

Which container should be used? It depends. Storing the text is faster but takes up memory (you are essentially storing the file into memory). Storing the file positions takes up less room but you will end up reading each line twice (once to find the position, second to fetch the data).

Augmentations to these algorithms is to memory-map the file, which is an exercise for the reader.

Edit 1: Example

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

using std::string;
using std::vector;
using std::fstream;

// Create a container for the file positions.
std::vector< std::streampos > file_positions;

// Create a container for the text lines
std::vector< std::string > text_lines;

// Load both containers.
// The number of lines is the size of either vector.
void
Load_Containers(std::ifstream& inp)
{
  std::string    text_line;
  std::streampos file_pos;
  file_pos = inp.tellg();
  while (!std::getline(inp, text_line)
  {
    file_positions.push_back(file_pos);
    file_pos = inp.tellg();
    text_lines.push_back(text_line);
  }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM