我正在尝试创建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
答案 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);
其中a
和b
只是指向您传递的数组中相邻元素的指针,如果-1
排在a
之前,则返回b
,{{ 1}},如果它们相同,或者0
,如果1
在b
之前排序-就像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
上标记了结构,以创建不同的变量名,例如{{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
虽然您可以使用a
和qsort (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;
}
(或者您可以在代码中打开一个新的文件流,并在其中输出信息)
仔细检查一下,如果还有其他问题,请告诉我。