0

私のローカル マシンには、次の内容の「data.in」という名前のファイルがあります。

1
5
6
6
8
10
33
24
20
3

そしてソースコード:

#include <stdio.h>

int main (void)
{
    int n,i,a,V[i],ch,aux;
    FILE *f1, *f2;

    f1 = fopen("data.in", "r");
    f2 = fopen("data.out", "w"); //create data.out

    char line[1024];
    n = 0;
    while( fgets(line,sizeof(line),f1) != NULL)
       n++; // n = number of lines from the file

    for (i=0; i<n; i++)
        fscanf(f1,"%d", &V[i]); //reading the array from data.in

    do {
        ch=0;
        for (i=0; i<n-1; i++)
            if (V[i]>V[i+1])
            {
                aux=V[i]; V[i]=V[i+1]; V[i+1]=aux; ch=1;
            }
    } while (ch); //Bubble sort

    for (i=0; i<n; i++)
        fprintf(f2, "%d\n", V[i]); // print the array into data.out

    fclose(f1);
    fclose(f2);

}

コンパイルはうまくいきますが、実行するたびに data.out には以下のみが含まれます。

0
0
0
0
0
0
0
0
0
0

配列だけを印刷しようとしましたが、まだゼロの束です。data.in を変更してすべての数字を同じ行に表示しようとしましたが、出力はまだゼロの集まりにすぎませんでした。私は何かが欠けているに違いない...

私はここで立ち往生しているので、助けていただければ幸いです。

4

5 に答える 5

2

動的メモリ割り当てを使用する場合、固定サイズの配列を定義して、割り当てたよりも多くのスペースが必要になるリスクを冒す必要も、ファイルを再読み込みする必要もありません。(一方で、数十、あるいは数千もの数字のファイルの場合、これはおそらくやり過ぎです。)

qsort()バブル ソートを使用する代わりに、標準ライブラリのソート関数 を使用することもできます。確かに、扱っているデータのサイズについては、バブル ソートとバブル ソートの違いはqsort()簡単に測定できない可能性がありますが、数十の数から数千の数に移動すると、O(N 2 ) とO(N log N) アルゴリズムが明らかになります。(以下がそのまま書かれている理由の説明については、C で構造体の配列をソートする方法を参照してください。)intcmp()

また、入力操作 (およびメモリ割り当て) をエラー チェックする必要があります。コードに示されている関数のような単純な関数を使用するerr_exit()と、エラー報告が簡潔になるため、負担が軽減され、エラー チェックを省略する言い訳が減ります。私は自分のプログラムの大部分で のより機能的なバリアントを使用していerr_exit()ますが、それは独自のヘッダーを持つ独自のソース ファイル内のコードです。多くのプログラム (以下の書き換えを含む) は、出力操作の成功をチェックしません。彼らはおそらくそうすべきです。

これにより、次のようなコードが生成されます。

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

static int intcmp(const void *p1, const void *p2);
static void err_exit(const char *fmt, ...);

int main(void)
{
    static const char n1[] = "data.in";
    static const char n2[] = "data.out";
    FILE *f1 = fopen(n1, "r");
    FILE *f2 = fopen(n2, "w");
    int *V = 0;
    char line[1024];
    int n = 0;
    int max_n = 0;

    if (f1 == 0)
        err_exit("Failed to open file %s for reading\n", n1);
    if (f2 == 0)
        err_exit("Failed to open file %s for writing\n", n2);

    while (fgets(line, sizeof(line), f1) != NULL)
    {
        int v;
        if (sscanf(line, "%d", &v) != 1)
            break;
        if (n == max_n)
        {
            int new_n = (max_n + 2) * 2;
            int *new_V = realloc(V, new_n * sizeof(*V));
            if (new_V == 0)
                err_exit("Failed to realloc array of size %d\n", new_n);
            V = new_V;
            max_n = new_n;
        }
        V[n++] = v;
    }

    qsort(V, n, sizeof(V[0]), intcmp);

    for (int i = 0; i < n; i++)
        fprintf(f2, "%d\n", V[i]);

    free(V);
    fclose(f1);
    fclose(f2);
    return(0);
}

static int intcmp(const void *p1, const void *p2)
{
    int i1 = *(int *)p1;
    int i2 = *(int *)p2;
    if (i1 < i2)
        return -1;
    else if (i1 > i2)
        return +1;
    else
        return 0;
}

static void err_exit(const char *fmt, ...)
{
    va_list args;
    va_start(args, fmt);
    vfprintf(stderr, fmt, args);
    va_end(args);
    exit(1);
}
于 2013-07-21T10:18:03.147 に答える
1

V の宣言 (i の値は何ですか? ヒント: ゼロの場合もあれば、-2147483648 の場合もあります) の宣言とは別に、fgets を使用して、ファイルの最後までの行数を取得しました。rewind(f1);その後、ファイルを再度読み取ることができるようにする必要があります。そうしないと、fscanf で何も読み取れないことになります。

fgets を使用し、まだ fgets のループにいる間に、sscanf を使用して、読んだ行から文字列を取得することをお勧めしますか? ファイル全体を 2 回読み取るのはなぜですか?

while (fgets(line, sizeof line, f1) != NULL) {
    sscanf(line, "%d", &V[n]);
    n++;
}

sscanf の戻り値でエラー チェックを行う必要がありますが、一般的な考え方はコードにあります。次に、その for ループは必要ありません。また、ファイルを巻き戻して 2 回読み取る必要もありません。

于 2013-07-21T09:36:40.807 に答える
1

V[i]簡単に修正するには、配列宣言をint ...,V[i]..., からV[2000];に変更する必要があります。V[2000]これは、配列を割り当てるときに、たとえば、 0 から 1999 までのインデックスを持つ 2000 個の項目が含まれるなど、配列に含まれる項目の数を知る必要があるためです。

C99では、変数を使用して異なる配列サイズのランタイムを取得できます...ただし、定義された値が必要です。iは行で明確にわかりません。

次に、ファイルに何行あるかわかりません。最も簡単な方法は、配列のサイズを修正し、配列をオーバーフローしないように制御することです。

コードを次のように変更します。

const int my_max_numbers = 10; // test it with more than 10 items and change for your likings
int n,i,a,ch,aux;
int V[my_max_numbers];
...

正しいサイズの配列を宣言する場合は、元のコードを別の方法で変更できます。ファイルの先頭で配列 V を宣言しないでください。ただし、行を読み取って行数を数えた後は、C99 標準を使用する必要があります。

while( fgets(line,sizeof(line),f1) != NULL)
    n++; // n = number of lines from the file

int V[n];
// here you have to rewind the file to the beginning
fseek(f1,0L,SEEK_SET);

for (i=0; i<n; i++)
    fscanf(f1,"%d", &V[i]); //reading the array from data.in

fseek のマンページ

于 2013-07-21T09:37:13.917 に答える
0

V[i] 配列は、使用する前に初期化する必要があると思います

于 2013-07-25T11:51:56.987 に答える