3

私は順序付けられた一連の数字を取得しようとしています (私が投稿しているコードは私が使用するアプローチではありませんが、コードで行われた出力をバイナリ ファイルに書き込む必要があります)。
「ordenar」の最後の反復を除いて、すべて正常に動作します。注文後に数字を再度出力すると、最後の行を除いてすべてが注文され、ordenar が正しく行われていることを確認しました。fwrite()最後の反復では値 10 を返しますが、最後の出力が書き込まれていないように見えます。

コードは次のとおりです。

#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;
}
4

1 に答える 1

3

手始めに、あなたのコードが何をすべきか正確にわからないので、segfault を引き起こすものを削除してください。と in の両方で
閉じます。いずれかを削除すると、プログラムが機能します。fileimprime_numeros()main()



最後の行をソートしないという問題に対する私の解決策は次のとおりです。もう一度繰り返してください

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

そしてそれは動作します。私は現在、解決策の「なぜ」の部分を調べています。
編集 1
しばらく時間がかかりましたが、次のとおり
です。 main() にはFILE* file=fopen(..)、正しく開くかどうかを確認しない唯一の場所があります。プログラムを初めて実行するたびに、そのファイルが見つからずfile、main() が NULL に設定されます。

次に、それは陽気に進みgenera_numeros()、独自のファイルを開く(そしてnumbers.dat btwを作成する...)関数を呼び出しますが、外側genera_numeros() fileはまだNULLであるため、ローカルスコープで呼び出します。そのため、ファイルを作成し、それを埋めて、以前

に作成したファイルに進みます(まだローカル スコープにあり、使用後にこのファイルを閉じます)。 その後、部分が進み、物事が面白くなり始めます。imprima_numeros()numbers.dat

ordenar
ordenar(file, i)NULL ファイルを取得すると...セグメンテーション違反でクラッシュします。
興味深い部分、そして私をだましたのは、プログラムを2回目に実行したときにこれが発生しないnumbers.datことでした。これは、前回の実行から残るためです)。

EDIT 2. FINAL はい、私は他の誰かのコードのバグを見つけるために 2 時間の無給の深夜を過ごしました。私はその男かもしれません...とにかく...
問題は、同じファイルを複数回開くことです。
つまり、存在しないファイルを開くことで以前のバグを修正するか、プログラムを 2 回目に実行して main() でファイルを開き、このファイルをimprime_numerosと で数回開いて閉じますgenera_numeros。それが本来のimplementation-defined振る舞いです。
問題は、ループ内での最後の呼び出しの後、ordenar()ループを再度開いて、imprime_numeros最後にソートされた行がディスク上のファイルにまだ表示されていないことです。これは、ファイル ストリームを閉じた後に行われます。したがって、ソートされた最終行を書き込む直前のファイルの状態が表示されます。

今、なぜ私のMAX+1解決策が機能したのは、最後の行を永続的に書き込むことを強制したため、によって開かれたファイルに表示されましたimprime_numeros()
それはほとんどすべてです。
MAX+1 を追加すると、サイズが 440 バイトのファイルが得られ (4 バイトの int があります)、400
になるはずです。問題の修正方法についても言及するのを忘れていましたが、私の説明でそれを適切に追跡できます。 . 読み取る前に fclose(file) を
ヒントします。 この時点までのこの回答を読んでいるすべての人は、文法、スタイルのために編集してくれてありがとう. 遅くて、これは私に多額の費用がかかりました。


于 2013-10-16T21:34:26.067 に答える