我正在尝试创建排名前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);
其中
a
和b
只是指向您传递的数组中相邻元素的指针,如果-1
在a
之前排序,则返回b
;如果它们相同,则返回0
;如果1
,则返回b
cc>在a
之前排序-就像strcmp
一样。为此,您只需将a
和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
被强制转换为指向您的结构的指针(我只是在s
上标记了结构,以创建不同的变量名,例如as
和bs
,您可以将它们命名为任何名称你喜欢)。虽然您可以只返回
bs->pct - as->pct
,但是如果值超过了可以作为int
返回的值,则存在溢出的风险(例如,两个较大的负值相减时将小于INT_MIN
。)仅用于使用条件表达式的结果来标准化对-1, 0, 1
的返回。(仔细考虑一下,如果
(as->pct < bs->pct)
的结果为1
且(as->pct > bs->pct)
的结果为0
得出1 - 0 = 1
(因此,在递减的情况下,b
在a
之前排序))要对数组进行排序,只需调用:
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++;
虽然可以使用
fgets
和sscanf
读取一行,然后分别解析值,但是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/