Search code examples
cfile-iofwrite

fwrite not working on last iteration


I'm just trying to get a set of numbers ordered (while the code I'm posting is not the approach I'm going to use, I do need to write to a binary file the output as done in the code).
Everything works fine, except for the last iteration of "ordenar": when I print back again the numbers after ordering, everything is ordered except for the last line, I have verified that ordenar is done correctly, and the fwrite() in that very last iteration is returning a value of 10, but it seems as if it does not write that last output.

Code is:

#define _CRT_SECURE_NO_DEPRECATE
#define SIZE 10
#define MAX  10

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

int numbers[SIZE];


int genera_numeros() {
    unsigned long i, j;
    FILE *file;

    file = fopen("number.dat", "wb");
    if (!file) {
        perror("fopen");
        return 1;    
    }

    srand(time(0));
    for (i = 0; i < MAX; i++) {
        for (j = 0; j < SIZE; j++) {
            numbers[j] = rand()%1000;
            printf("%i ", numbers[j]);
        }
        fwrite(numbers, sizeof(int), SIZE, file);
        printf("\n");
    }
    fclose(file);
    return 0;
} 


int imprime_numeros() {
    unsigned long i, j;
    int numbers[SIZE];
    FILE *file;

    file = fopen("number.dat", "rb");
    if (!file) {
        perror("fopen");
        return 1;
    }

    for (i = 0; i < MAX; i++) {
        fread(numbers, sizeof(int), SIZE, file);
        for (j = 0; j < SIZE; j++) {
            printf("%i ",numbers[j]);
        }
        printf("\n");
    }
    fclose(file);
    return 0;
}

int compare (const void * a, const void * b)
{
  return ( *(int*)a - *(int*)b );
}


int ordenar(FILE* file, long int num_bloque)
{
    int byte=0, written=0;
    fseek(file, num_bloque * sizeof(int) * SIZE, SEEK_SET);
    fread(numbers, sizeof(int), SIZE, file);
    qsort (numbers, SIZE, sizeof(int), compare);
    fseek(file, num_bloque * sizeof(int) * SIZE, SEEK_SET);
    byte=ftell(file);
    written=fwrite(numbers, sizeof(int), SIZE, file);
    return 0;
} 


int main(int argc, char* argv[]) {
    FILE *file;
        file = fopen("number.dat", "rb+");
    long int i;

    genera_numeros();
    printf("\n\n Los numeros son:\n\n");
    imprime_numeros();
    printf("\n\n Ordenando...");

    for (i=0; i<MAX; i++)
    {   
        ordenar(file, i);
    }

    printf("\n\n Los numeros son:\n\n");
    imprime_numeros();
    printf("\n");

    fclose(file);
    system("PAUSE");
    return 0;
}

Solution

  • For starters, because I can't tell what exactly your code is supposed to do, remove what gives you segfault.
    You close you file both with imprime_numeros() and the in main(). Remove one or aother and your program works.



    Here's my solution to your problem with not sorting last row. Just make one more iteration with

    for(i=0;i<MAX+1;i++){
    

    and it works. I'm currently looking into "why" part of solution.
    EDIT 1
    It took me a while, but here it goes:
    in your main() you have FILE* file=fopen(..) and that's the only place you don't check if it opens correctly. Every first time your program runs- it doesn't find that file and file in main() in set to NULL.

    Then it merrily proceeds and calls functions genera_numeros() that opens its own file(and creates numbers.dat btw...) but on the local scope, since outside genera_numeros() file is still NULL.

    And so it creates a file, fills it and proceeds to imprima_numeros() that opens previously created numbers.dat(still on local scope and you close this file after use).

    Then goes the ordenar part and things start to get interesting.
    ordenar(file, i) takes your NULL file and...crashes with segmentation fault.
    (interesting part, and what tricked me, was this will NOT occure second time you run the program, because numbers.dat will remain from previous run).

    EDIT 2. FINAL Yes, I just spent 2 non-paid-late-nigt hours in finding bug in someone else's code. I might be that guy...Anyway...
    Problem is with multiple opening of the same file.
    Bu that I mean, when you fix previous bug with opening non-existent file, or just run program 2nd time you open a file in main() then open and close this file few times with imprime_numeros and genera_numeros. That's supposed to be implementation-defined behavior.
    Problem is that after your last call to ordenar() in your loop you re-open it with imprime_numeros and written last sorted line is not yet visible in your file on disk. This will be done after you close the file stream. So you see state of the file just before writing sorted last line to it.

    Now why my MAX+1 solution worked is that it forced to write last line permamently so it was visible in your file opened by imprime_numeros().
    That's almost all.
    Notice that by adding MAX+1 you get file of 440 bytes in size( i have 4 byte int) and it's supposed to be 400.
    I also forgot to mention how to fix the problem, but you can propably track that down by my description.
    Hint
    fclose(file) before reading from it.

    All who are reading this answer to this point, I will be thankful for editing it for grammar, style. It's late and this one cost me a lot.