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

标签 c arrays file sorting

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

我想按%的结果对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

最佳答案

注释中指出了您的直接问题,您被引导至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中,您甚至可以删除struct标签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的比较函数。它是用C进行分拣的瑞士军刀(它非常有效,比您自己滚动的任何工具都经过了更好的测试)。编写比较函数没有什么困难。原型是:

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


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

/* 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);
}


上面的指针ab被强制转换为指向您的结构的指针(我只是在s上标记了结构,以创建不同的变量名,例如asbs,您可以将它们命名为任何名称你喜欢)。

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

(仔细考虑一下,如果(as->pct < bs->pct)的结果为1(as->pct > bs->pct)的结果为0得出1 - 0 = 1(因此,在递减的情况下,ba之前排序))

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

qsort (array, nelements, sizeof element, compare);


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

/* 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++;


虽然可以使用fgetssscanf读取一行,然后分别解析值,但是fscanf在此处将二者用作示例。关键是验证返回值以确保4转换成功,并且没有发生输入或匹配失败。

放在一起,将文件名作为第一个参数传递给程序(或者,如果没有提供参数,则默认从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;
}


输入文件示例

$ cat dat/history.txt
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


使用/输出示例

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

$ ./bin/userhistsort dat/history.txt
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
 26%      User1        1     01/01/2019


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

$ ./bin/userhistsort dat/history.txt > sortedfile.txt


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

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

关于c - 从文件中读取一串信息并按int结果排序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53998752/

相关文章:

java - 如何在SWT shell中以只读模式打开word文档

函数 pthread_join 的代码 - Pthread 库

C - 无法将文件存储到字符串数组中(基于脱机换行符)

python - 字符串系列到数组

c++ - 数组递归;无法获得正确的返回值

c - 对 C 中的 char 数组进行排序

c - 在struct中需要一个 "variable"大小的二维数组

C 打印形状 : Unable to add back slash

c# - 有效复制多个文件

python - 在C中查看日志文件