0

I have followed this tutorial to implement a program that generates up to 100,000 random numbers and inserts them in a file to be sorted, but I have noticed that the loop with getw is outputting way less numbers than expected. In my machine, this code only prints 49 numbers:

#include <stdio.h>
#include <stdlib.h>

int gen_random_file(int n_values) {
    int index;
    int num, num_count = 0;
    FILE *r_file;
    r_file = fopen("random_numbers", "w");

    if (r_file != NULL) {
        printf("File created successfully!\n");
    }
    else {
        printf("Failed to create the file.\n");
        return -1;
    }

    for (index = 0; index < n_values; index++) {
        putw(rand(), r_file);
    }

    fclose(r_file);

    r_file = fopen("random_numbers", "r");

    // display numbers
    printf("\nNumbers:\n");
    while ( (num = getw(r_file)) != EOF ) {
        printf("%d\n", num);
        num_count++;
    }
    printf("\nEnd of file.\nNum Count = %d\n", num_count);

    fclose(r_file);

    return 0;
}

int main()
{
    gen_random_file(10000);

    return 0;
}
  • 1
    Note to readers: `putw` and `getw` are *likely* the Windows-specific [`_putw`](https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/putw?view=msvc-170) and [`_getw`](https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/getw?view=msvc-170) functions. – Some programmer dude Aug 28 '22 at 15:57
  • 2
    Open the file in `"rb"` binary mode. Note that [`_getw`](https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/getw?view=msvc-170) states *However, because the EOF value is also a legitimate integer value, use `feof` or `ferror` to verify an end-of-file or error condition.* The text-mode conversions may have misaligned the expected data causing `-1` to appear which wasn't actually written. – Weather Vane Aug 28 '22 at 15:58
  • 1
    To the OP: Note that `EOF` is equal to `-1`. And that's a valid `int` value, making it impossible to distinguish between the actual valid value `-1` and `EOF`. This is a major flaw with the functions you use. If you want to write and read raw binary data, use [`fwrite`](https://en.cppreference.com/w/c/io/fwrite) and [`fread`](https://en.cppreference.com/w/c/io/fread) instead. And as mentioned, remember to open the file in ***b**inary* mode. – Some programmer dude Aug 28 '22 at 15:59
  • 2
    @Someprogrammerdude Visual C's `rand()` generates vlaues in the range `0` .. `32767` but a misalignment resulting from reading in text mode might create `-1` as an artifact. – Weather Vane Aug 28 '22 at 16:01
  • @Someprogrammerdude: `putw` and `getw` are SYSVr4 "standard" functions, so predate windows, and are present on most UNIX systems, even though they are not part of POSIX – Chris Dodd Aug 28 '22 at 19:00

3 Answers3

2

You terminate the loop too early. rand() is likely to produce -1 once in a while.

Quoting man getw (section Bugs):

Since EOF is a valid integer value, feof(3) and ferror(3) must be used to check for failure after calling getw().

You need something like

    while(1) {
        if ((w = getw()) == EOF) {
            if (feof(stdin) || ferror(stdin)) {
                break;
            }
        printf(....);
        ....
    }
    // Deal with error if necessary
user58697
  • 7,808
  • 1
  • 14
  • 28
0

This one of those rare cases where you actually want feof. You need a loop like

while ((num = getw(r_file)), !feof(r_rile)) {

to read a number and then test for EOF.

On some systems (such as Windows), you'll also need "wb" and "rb" for your fopen modes to get a binary file.

Chris Dodd
  • 119,907
  • 13
  • 134
  • 226
0

I ended up using fwrite and fread as well as "wb" and "wr" as parameters for fopen and that solved the problem.

#include <stdio.h>
#include <stdlib.h>

int gen_random_file(int n_values) {
    int index;
    int rand_num, num_count = 0;
    int buffer[100000];
    FILE *rand_file;

    rand_file = fopen("random_numbers", "wb");

    if (rand_file != NULL) {
        printf("File created successfully!\n");
    }
    else {
        printf("Failed to create the file.\n");
        return -1;
    }

    for (index = 0; index < n_values; index++) {
        rand_num = rand();
        fwrite(&rand_num, sizeof(rand_num), 1, rand_file);
    }

    fclose(rand_file);

    rand_file = fopen("random_numbers", "rb");

    // display numbers
    printf("\nNumbers:\n");
    fseek(rand_file, 0, SEEK_SET);
    fread(buffer, sizeof(rand_num), n_values, rand_file);
    for (index = 0; index < n_values; index++) {
        rand_num = buffer[index];
        printf("%d\n", rand_num);
        num_count++;
    }
    printf("\nEnd of file.\nNum Count = %d\n", num_count);

    fclose(rand_file);

    return 0;
}

int main()
{
    gen_random_file(10000);

    return 0;
}