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



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

我想按%的结果对历史记录.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

我现在的代码有误,但暂时只是在兜圈子。 这是字符测试Ty[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("nn");
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

您的直接问题已在评论中指出,您被定向到为什么 while ( !feof (文件) ) 总是错误的?始终将读取循环条件放在读取函数本身上,或者连续循环并检查循环中读取函数的返回,并在成功读取发生且满足所有约束时break;循环。

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

不要对文件名进行硬编码或在代码中使用魔术数字。对于文件名,要么将文件名作为参数传递给程序(这就是argv的用途),要么提示输入。(最好将其作为参数传递)。如果需要代码中的常量,请#define一个(或多个)或使用全局enum来完成相同的操作。

现在谈谈问题的症结。每当必须将不同类型的值作为单个记录或对象处理时,都应该考虑使用结构将不同类型的值作为单个对象进行协调。在这里,您可以声明一个包含int个成员的struct来存储百分比和测试类型值,并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];但是,您可以通过创建typedef来使您的生活更轻松,并避免一遍又一遍地键入struct users ...。在 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编写比较函数。它是用于在C中分类的瑞士军刀(它也非常有效,并且比您自己滚动的任何东西都经过了更好的测试)。编写比较函数并不难。原型是:

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

其中ab只是指向你传递的数组中相邻元素的指针,你返回-1如果ab之前排序,0它们是否相同,或者如果ba之前排序1- 就像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(因此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++;

虽然您可以使用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     %sn", 
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

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

仔细查看,如果您有其他问题,请告诉我。

我认为问题是testTy不是一个数组。您将输入拆分为 2 个变量:

  • topResult:这是一个包含要排序的值的数组
  • testTy:字符串的其余部分

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

相关内容

  • 没有找到相关文章

最新更新