从文件中读取一串信息并按int结果排序

时间:2019-01-01 20:35:46

标签: c arrays file sorting

我正在尝试创建C编程的前5名。信息存储在普通文本文件中。

我想按%的结果对history.txt文件中的信息进行排序:整数1-3是用户进行的测试的类型。

26%       User1           1       01/01/2019
100%      User2           3       01/01/2019
73%       User3           1       01/01/2019
52%       User4           1       01/01/2019
75%       User5           2       01/01/2019
60%       User6           1       01/01/2019

我现在在我的代码中有错误,但是暂时只是转圈。是char testTy [50];它不是数组,但我真的不知道如何解决它,使其与%的结果保持一致。目前,我已经解决了结果排序问题。但是文本的其余部分只是一再的混乱。

//显示5级最佳成绩(此功能)

fp = fopen("history.txt", "r");
int ch=0;
int lines=0;
while(!feof(fp))
{
    ch = fgetc(fp);
    if(ch == '\n')
    {
        lines++;
    }
}
fclose(fp);

fp = fopen("history.txt", "r");

int i =0, temp, swapped;
int topResult[lines];
char testTy[50];

char singelLine[100];
while(!feof(fp))
{
    fgets(singelLine, 100, fp);
    sscanf(singelLine, "%d%[^'\n']s",&topResult[i], testTy);
    i++;
}

fclose(fp);
while(1)
{
    swapped = 0;

    for( i= 0; i <lines-1; i++)
    {
        if(topResult[i]<topResult[i+1])
        {
            int temp = topResult[i];
            topResult[i] = topResult[i+1];
            topResult[i+1] = temp;
            swapped = 1;
        }
    }
    if(swapped == 0)
    {
        break;
    }
}

printf("Result:   User:      Test type:      Date:\n");
for (i = 0; i < 5; i++)
{
    printf("\n%d%25s", topResult[i], testTy);
}
printf("\n\n");
return;

我想要的结果是这样的信息:

100%     user2  3 01/01/2019
75%      user5  2 01/01/2019
73%      user3  1 01/01/2019
60%      user6  1 01/01/2019
52%      user4  1 01/01/2019

我现在的输出是:

100%     user1  1 01/01/2019
75%      user1  1 01/01/2019
73%      user1  1 01/01/2019
60%      user1  1 01/01/2019
52%      user1  1 01/01/2019

2 个答案:

答案 0 :(得分:0)

我认为问题在于testTy不是数组。您将输入分为两个变量:

  • topResult:这是一个具有要排序的值的数组
  • testTy:其余字符串

打印结果时,变量testTy始终具有相同的输出。

答案 1 :(得分:0)

您的直接问题已在评论中指出,您被引导至Why is while ( !feof (file) ) always wrong?。始终以读取函数本身为条件来限制读取循环,或者连续循环,并在成功读取并满足所有约束条件后检查循环和break;循环中读取函数的返回。

fp = fopen("history.txt", "r");

不要硬编码文件名或在代码中使用魔术数字。对于文件名,可以将文件名传递为程序的参数(即argv的意思),也可以提示输入。 (最好将其作为参数传递)。如果您的代码中需要常量,请#define一个(或多个)或使用全局enum来完成相同的事情。

现在到了问题的症结所在。任何时候当您必须将不同类型的值作为单个记录或对象来处理时,您都应该考虑使用结构来将不同类型的值作为单个对象进行协调。在这里,您可以用成员struct声明一个int来存储百分比和测试类型值,以及char[](或char*并分配)来保存名称和日期信息。然后,您可以简单地声明一个结构数组,以保存从您的history.txt文件中读取的所有值,这些值可以很容易地与qsort在您选择的任何成员上进行排序。

首先,声明一个简单的结构,例如

struct users {     /* simple struct to hold values read from input */
    int pct,
        test;
    char name[MAXNM],
        date[MAXDT];
};

然后,您可以简单地使用struct users array[50];声明一个数组。但是,可以简化创建过程,并且不必通过创建struct users ...来重复键入typedef。在C中,您甚至可以删除结构标签users并在最后添加typedef标签,例如

typedef struct {    /* simple struct w/typedef to hold values read from input */
    int pct,
        test;
    char name[MAXNM],
        date[MAXDT];
} userhist_t;

现在,您可以使用userhist_t array[50];来简单地创建一个结构数组(是否使用typedef由您决定,这不是必需的,它只是保存输入内容)

如果您要使用C对值进行排序,请继续帮助自己,并学习如何为qsort编写 compare 函数。它是用C进行分拣的瑞士军刀(也非常有效,比您自己动手做的任何事情都要经过更好的测试)。编写比较函数没有什么困难。原型是:

int compare (const void *a, const void *b);

其中ab只是指向您传递的数组中相邻元素的指针,如果-1排在a之前,则返回b,{{ 1}},如果它们相同,或者0,如果1b之前排序-就像a一样。为此,您只需将strcmpa转换为数组的元素类型,然后比较这些值,返回适当的值。例如:

b

以上,指针/* qsort compare function sorting array of struct by percent (descending) */ int compare_pct (const void *a, const void *b) { const userhist_t *as = a, /* cast the pointers to correct type */ *bs = b; /* return descending sort (conditionals avoids potential overflow) * for ascending sort use (as > bs) - (as < bs) */ return (as->pct < bs->pct) - (as->pct > bs->pct); } a被转换为指向您的结构的指针(我刚刚在b上标记了结构,以创建不同的变量名,例如{{1} }和s,您可以随意命名。

虽然您只可以返回as,但是如果值超过可以作为bs返回的值,则存在溢出的风险(例如,两个较大的负值相减时将小于{ {1}},仅使用条件表达式的结果,使用条件语句将对bs->pct - as->pct的返回值归一化。

(仔细研究一下,如果int的结果为INT_MIN,而-1, 0, 1的结果为(as->pct < bs->pct)则产生1(因此(as->pct > bs->pct)排序在0之前(降序))

要对数组进行排序,只需调用:

1 - 0 = 1

现在开始读取/填充struct数组。因此,让我们声明常量,上面有一个struct,让我们声明一个struct数组,然后将文件中的值读入数组,例如

b

虽然您可以使用aqsort (array, nelements, sizeof element, compare); 来读取一行,然后分别解析值,但是/* global enum defining constants for use in code */ enum { MAXDT = 12, MAXNM = 16, MAXS = 64 }; ... userhist_t user[MAXS] = {{ .pct = 0 }}; /* array of struct */ size_t n = 0; ... /* read/fill up to MAXS struct from file */ while (n < MAXS && fscanf (fp, "%d%% %s %d %s", &user[n].pct, user[n].name, &user[n].test, user[n].date) == 4) n++; 在此将作为示例。关键是要验证以确保成功进行了4次转换并且没有发生 input matching 失败的返回。

全部放入,将文件名作为第一个参数传递给程序(或者,如果没有提供参数,则默认从fgets读取),处理声明,读取,使用sscanf进行排序和输出,您可以执行以下操作:

fscanf

示例输入文件

stdin

使用/输出示例

使用输入文件,将导致您描述的排序顺序:

qsort

如果要将结果保存到新文件,只需重定向输出,例如

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

/* global enum defining constants for use in code */
enum { MAXDT = 12, MAXNM = 16, MAXS = 64 };

typedef struct {    /* simple struct to hold values read from input */
    int pct,
        test;
    char name[MAXNM],
        date[MAXDT];
} userhist_t;

/* qsort compare function sorting array of struct by percent (descending) */
int compare_pct (const void *a, const void *b)
{
    const userhist_t    *as = a,    /* cast the pointers to correct type */
                        *bs = b;

    /* return descending sort (conditionals avoids potential overflow)
     * for ascending sort use (as > bs) - (as < bs)
     */
    return (as->pct < bs->pct) - (as->pct > bs->pct);
}

int main (int argc, char **argv) {

    userhist_t user[MAXS] = {{ .pct = 0 }};   /* array of struct */
    size_t n = 0;
    /* use filename provided as 1st argument (stdin by default) */
    FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;

    if (!fp) {  /* validate file open for reading */
        perror ("file open failed");
        return 1;
    }

    /* read/fill up to MAXS struct from file */
    while (n < MAXS && fscanf (fp, "%d%% %s %d %s", &user[n].pct,
            user[n].name, &user[n].test, user[n].date) == 4)
        n++;
    if (fp != stdin) fclose (fp);   /* close file if not stdin */

    /* sort by calling compare_pct to sort by percent (descending order) */
    qsort (user, n, sizeof *user, compare_pct);

    for (size_t i = 0; i < n; i++)  /* output sorted results */
        printf ("%3d%%      %-8s    %2d     %s\n", 
                user[i].pct, user[i].name, user[i].test, user[i].date);

    return 0;
}

(或者您可以在代码中打开一个新的文件流,并在其中输出信息)

仔细检查一下,如果还有其他问题,请告诉我。