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 从您阅读的行中获取字符串?为什么要读取整个文件两次?

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

您应该对 sscanf 的返回值进行错误检查,但总体思路在代码中。然后你不需要那个 for 循环,也不需要倒带文件来读取它两次。

于 2013-07-21T09:36:40.807 回答
1

为了快速修复,您必须将数组声明V[i]int ...,V[i]..., 更改为V[2000]; 这是因为在分配数组时,您必须知道它有多少项目,例如V[2000]它将有 2000 个项目,索引从 0 到 1999。

在 C99 中,您可以使用变量来获得不同的数组大小运行时......但您必须有一个定义的值,i 在行中并不清楚。

然后,您不知道文件中有多少行,最简单的方法是固定数组大小并进行 som 控制以确保您不会溢出数组。

像这样更改您的代码:

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 回答
1

在计算文件中的行数后,fi已更改。

你需要fi像这样重置:

fseek(f1, 0, SEEK_SET);

并再次从头读取文件。

然后你可能会在“data.out”中得到正确的输出。

于 2013-07-21T09:38:16.520 回答
0

我认为您的 V[i] 数组应该在使用之前进行初始化

于 2013-07-25T11:51:56.987 回答