Return Styles: Pseud0ch, Terminal, Valhalla, NES, Geocities, Blue Moon. Entire thread

C - read a random line from a file.

Name: Anonymous 2006-03-06 10:31

dear world4chan, I wrote this to return a random line read from a file, but I hate it. what would you do?

#define MAX_LINE_SIZE 1024

void readQuote(int sock_desc)
{
        //data
        FILE* quoteSource;      //source file pointer
        int numLines;           //max number of lines
        int rndLine;            //random line
        int i;
        char buff[MAX_LINE_SIZE] = {0};

        //initialize the random number generator
        srand(time(NULL));

        //open file; check for errors
        quoteSource = fopen("quotes.txt", "r");
        if (quoteSource == NULL)
        {
                printf("!! Error accessing file.\n");
                return;
        }

        //get the file size, if zero, exit
        numLines = 0;
        while (!feof(quoteSource))
                if (fgetc(quoteSource) == '\n') numLines++;
        rewind(quoteSource);

        if (numLines == 0)
        {
                printf("!! Quote file empty\n");
                fclose(quoteSource);
                return;
        }

        //select a line and read until that line is found
        rndLine = (rand() % numLines) + 1;
        printf("line %d of %d: ", rndLine, numLines);

        for (i = 0; i < rndLine; i++)
                fgets(buff, MAX_LINE_SIZE, quoteSource);

        printf("%s\n", buff);


        fclose(quoteSource);
}

Name: Anonymous 2006-03-06 16:38

I would pick a random character from the file and work backwards and forwards from it until I find a full line. This means that the probability of picking a particular line is weighted towards the length of the line, but it is a lot quicker than reading them all in.

#define MAX_LINE_SIZE 1024

void readQuote()
{
    FILE* quoteSource;      //source file pointer
    long fileSize = 0;
    long currentPos = 0;
    int readLength;
    int secondReadLength;
    // this is a circular buffer, so +2 for the null terminators,
    // one in middle and one at end
    char buff[MAX_LINE_SIZE+2];
    char *endOfLinePtr;
    char *startOfLinePtr;
    int i;

    // initialize the random number generator
    srand(time(NULL));

    //open file; check for errors
    quoteSource = fopen("quotes.txt", "r");
    if (quoteSource == NULL)
    {
        printf("!! Error accessing file.\n");
        return;
    }

    //get the file size, if zero, exit
    fseek(quoteSource, 0, SEEK_END);
    fileSize = ftell(quoteSource);

    if (fileSize <= 0)
    {
        printf("!! Quote file empty\n");
        fclose(quoteSource);
        return;
    }

    // select random position in the file
    // if RAND_MAX < filesize then make sure enough rand()s are called to compensate
    for (i=0;i<=fileSize/RAND_MAX;i++)
        currentPos += rand();
    currentPos %= fileSize;
    fseek(quoteSource, currentPos, SEEK_SET);

    // get and print line that character resides in
    readLength = fread(buff, 1, MAX_LINE_SIZE, quoteSource);
    endOfLinePtr = strchr(buff, '\n');
    if (endOfLinePtr == NULL)
    {
        // if '\n' wasn't found we either have an entire MAX_LINE_SIZE size
        // line or we just read less than that up to the end of the file.
        if (readLength < MAX_LINE_SIZE)
        {
            endOfLinePtr = buff + readLength;
        }
    }
    if (endOfLinePtr != NULL)
    {
        // fill remainder of buffer up with previous part of line
        endOfLinePtr[0] = '\0';
        endOfLinePtr++;
        secondReadLength = MAX_LINE_SIZE-(endOfLinePtr-buff);
        fseek(quoteSource, currentPos-secondReadLength, SEEK_SET);
        fread(endOfLinePtr, 1, secondReadLength, quoteSource);
        // then search for last newline for start of line
        startOfLinePtr = strrchr(endOfLinePtr, '\n');
        if (startOfLinePtr == NULL)
        {
            // if not found, must be entire line in buffer
            startOfLinePtr = endOfLinePtr;
        }
        else
        {
            startOfLinePtr++; // skip newline
        }
        // print latter part of buffer
        printf("%s", startOfLinePtr);
    }
    // print from start of buffer
    printf("%s\n", buff);

    fclose(quoteSource);
}

Newer Posts
Don't change these.
Name: Email:
Entire Thread Thread List