gpt4 book ai didi

c - 在我的结构进入txt文件之前使用qsort和strcmp

转载 作者:行者123 更新时间:2023-11-30 16:29:44 25 4
gpt4 key购买 nike

我的代码从一个文本文件中提取数据,然后合计分数并将其输入到一个单独的文本文件中,因此我希望程序在将frpintf转换为文本文件之前按总得分来组织团队和得分。到目前为止,该程序可以提取并运行数据并将其总计,并且fprintf很好,我应该使用qsort进行排序并打印到文本文件中,以及将其放置在代码中的什么位置。这是它正在阅读的文本。

印第安人54 45 5

双胞胎45 53 7

老虎43 59 8

白_索克斯35 64 9

皇家队30 69 3

我也知道在MLB大声笑中没有任何关系,只是抛出一个附加变量。

谢谢。

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
int main(void)

{
struct records {
char filename;
char team[50];
int wins;
int tie;
int loss;
int points;
};
struct records roster;
FILE *ifp = NULL;
FILE *afd = NULL;
const int argv;
char filename2[64] = {0};
char filename[64] = {0};
int points;
int points2;
int total;


printf("\nPlease enter the the .txt file you would like to open: ");
scanf("%63s", filename);
printf("Opened file name %s",filename);
ifp = fopen(filename,"r");


if (ifp == NULL)
{
printf("Could not open");
printf("\nPlease enter the the .txt file you would like to open:");
scanf("%63s", filename);
printf("Opened file name %s",filename);
ifp = fopen(filename,"r");
}

printf("\nReading the file %s \n", filename);
while(fscanf(ifp, "%s %d %d%d" , roster.team, &roster.wins, &roster.loss,
&roster.tie) != EOF)
printf("%s Wins:%d Losses:%d ties:%d\n", roster.team, roster.wins,
roster.loss, roster.tie);
printf("\nWins are worth 2 points ties are worth 1 point and losses are
worth \nzero in overall league standings.");
printf("\nHere are the overall ALCentral Standings!\n");

ifp = fopen(filename, "r");
fopen(filename, "r"); while(fscanf(ifp, "%s %d %d %d", roster.team,
&roster.wins, &roster.loss, &roster.tie) != EOF)
printf("%s Wins:%d Losses:%d ties:%d Total league points:%d\n",
roster.team, roster.wins, roster.loss, roster.tie, (roster.wins * 2 +
roster.tie * 1), total);


printf("closing %s", filename);
fclose(ifp);

printf("\nPlease enter the the .txt file you would like to write to: ");
scanf("%63s", filename2);
printf("Opened file name %s", filename2);
afd = fopen(filename2, "a+");

if (afd == NULL)
{
printf("Could not open"); printf("\nPlease enter the the .txt file you
would like to open: ");
scanf("%63s", filename2);
printf("Opened file name %s", filename2);
afd = fopen(filename2,"a+");
}

ifp = fopen(filename,"r");
fopen(filename, "r");
points = roster.wins * 2;
points2 = roster.tie * 1;
total = points + points2;
while(fscanf(ifp, "%s %d %d %d", roster.team, &roster.wins, &roster.loss,
&roster.tie) != EOF)



fprintf(afd, "%s Wins:%d Losses:%d ties:%d total league points:%d\n",
roster.team, roster.wins, roster.loss, roster.tie, (roster.wins *2 +
roster.tie *1 ), total, filename2);
printf("\nYour stats have been recorded to the selected
file!\nClosing all open files! \nThanks for using the STAT-Master!
Have a great day!


fclose(afd);
fclose(ifp);



return 0;
}

最佳答案

您的逻辑很混乱。如果我了解您要尝试的内容,则希望从数据文件中读取每个团队winslosstie记录,然后计算points,然后将其用于将团队按降序排列(或也许升序),然后将“总体ALCentral排名”输出到stdout或文件,或两者都输出。

在开始之前,让我们讨论一下struct records中对main()的定义。虽然合法,但通常您希望结构声明位于文件范围内,以便您为帮助处理代码中的数据而编写的任何函数都可以使用结构类型。在这里,您必须将声明移到main()之外,因为qsort比较函数将需要知道struct records是什么类型。比较函数不能在main()中声明和定义,因为C不允许嵌套函数声明。因此,将您的结构移到main()之外,例如

#define MAXR   16   /* if you need a constant, #define one (or more) */
#define MAXC 64
#define MAXB 1024

typedef struct records {
char team[MAXC];
int wins,
loss,
tie,
points;
} record_t;


(注意:使用 typedef可以使事情更方便)

首先,您多次尝试读取文件名很尴尬,并且从不保证您确实打开了文件。它只是作了几次尝试,然后有效地放弃了验证,只是盲目地假定存在要读写的有效文件流,并按向前。这是调用未定义行为的方法。

每当您在C中执行任何操作时,尤其是在处理用户输入或文件操作时,都必须验证每个步骤。在尝试读取文件之前,必须知道文件是否已打开以供读取。 (无论尝试打开它多少次)在开始使用代码中的值之前,您都必须验证所阅读的内容。在尝试下一次读取之前,您必须验证输入流的状态,并处理剩余的任何字符。

考虑到这一点,您可以提示输入文件名并尝试打开连续循环中提供的文件名,直到您确认文件实际上是打开的为止,例如

/** helper function to empty stdin between inputs */
void empty_stdin()
{
int c = getchar();

while (c != '\n' && c != EOF)
c = getchar();
}
...
FILE *fp = NULL; /* file pointer */

do { /* loop until valid filename given and file open */
printf("\nenter input filename: ");
if (scanf (" %63[^\n]", filename) != 1) {
fprintf (stderr, "error: user canceled input.\n");
return 1;
}
empty_stdin(); /* remove '\n' and any add'l chars in input buffer */
fp = fopen (filename, "r"); /* open filename */
if (fp == NULL) /* validate file open for reading */
perror ("fopen-input");
} while (fp == NULL);
printf("Opened file name %s\n\n",filename);


(注意: scanf不是使用 fgets进行用户输入,而是提供了一种更好的用户输入方法,并且与 scanf相比陷阱少得多,下面的示例使用 roster

接下来,您对如何收集内存中的数据以对其进行排序的了解并不明显。当要对一组团队信息进行排序时,必须将所有团队信息读入内存,然后才能将该信息传递给 qsort进行排序。

您有一个 struct来保存每个团队的所有信息,您只需要从输入文件中读取每一行(记录)到一个数组或结构中,然后可以轻松地将其传递给 qsort进行排序。

要使用 qsort,首先必须定义一个 compare函数,该函数用于 qsort对数据进行排序。 compare函数具有特定的声明:

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


其中每个 const void *参数将是指向记录数组中元素之一的指针。 (在C中,空指针,例如 void*是可以从任何其他指针类型分配或分配给其他类型的通用指针,而无需进行强制转换-这就是为什么 compare函数的声明使用该类型的参数作为参数的原因)编写 compare函数的工作只是简单地为指针提供类型(通过选择还是通过显式强制转换,您可以选择),然后在希望排序的值之间进行比较。例如,您对每个结构的 points成员的比较可能只是:

/** qsort compare function (descending order of points) */
int compare (const void *a, const void *b)
{
const record_t *ta = a;
const record_t *tb = b;

return (ta->points < tb->points) - (ta->points > tb->points);
}


(其中 (a < b) - (a > b)取决于不等式的简单计算结果为 -1, 0, 1,例如,如果 a = 4b = 3,则您具有 (0) - (1)等于 -1,表示 ab之前排序)

剩下的工作就是将每个团队的数据读入数组并计算 points,然后将数组传递给 qsort

要将数据读入数组,将每一行读入缓冲区,将缓冲区中的数据解析为单独的值,验证是否正确解析了每个单独的值,计算每个团队的得分值,增加数组索引并然后阅读下一行。您可以使用 fgets进行以下操作来读取每一行数据:

    record_t roster[MAXR] = {{ .team = "" }};   /* array to hold teams */
...
/* read up to MAXR team records from file */
while (ndx < MAXR && fgets (buf, MAXB, fp)) {
/* parse data from buffer filled, saving return */
int rtn = sscanf (buf, " %49s %d %d %d" , roster[ndx].team,
&roster[ndx].wins, &roster[ndx].loss,
&roster[ndx].tie);
if (rtn < 4) /* if less than 4 conversions, get next line */
continue;

/* compute points (2 * wins + ties) */
roster[ndx].points = roster[ndx].wins * 2 + roster[ndx].tie;
ndx++; /* increment index */
}
fclose (fp); /* close file */


(请注意:您可以添加 strlen()buf的检查,以确定是否有其他字符保留在未读行中-留给您)。

将所有数据存储在结构 roster的数组中后,剩下的就是将 roster传递给 qsort,然后输出排序后的数据。

以下内容对数据进行排序并将结果输出到 stdout。将输出写入文件留给您,但是提示,您既不需要 ifpafp,也不需要 filenamefilename2points2,您只需要处理一次一个文件/文件名。排序和输出很简单:

    /* sort roster based on points (descending order) */
qsort (roster, ndx, sizeof *roster, compare);

/* outpout results */
printf ("Here are the overall ALCentral Standings!\n\n"
"Team Wins Loss Tie Points\n\n");
for (int i = 0; i < ndx; i++)
printf ("%-12s %4d %4d %4d %4d\n", roster[i].team,
roster[i].wins, roster[i].loss, roster[i].tie,
roster[i].points);


综上所述,您可以执行以下操作:

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

#define MAXR 16 /* if you need a constant, #define one (or more) */
#define MAXC 64
#define MAXB 1024

typedef struct records {
char team[MAXC];
int wins,
loss,
tie,
points;
} record_t;

/** helper function to empty stdin between inputs */
void empty_stdin()
{
int c = getchar();

while (c != '\n' && c != EOF)
c = getchar();
}

/** qsort compare function (descending order of points) */
int compare (const void *a, const void *b)
{
const record_t *ta = a;
const record_t *tb = b;

return (ta->points < tb->points) - (ta->points > tb->points);
}

int main (void) {

int ndx = 0; /* index for roster array */
char buf[MAXB] = "", /* buffer for fgetrs */
filename[MAXC] = ""; /* filename to read */
record_t roster[MAXR] = {{ .team = "" }}; /* array to hold teams */
FILE *fp = NULL; /* file pointer */

do { /* loop until valid filename given and file open */
printf("\nenter input filename: ");
if (scanf (" %63[^\n]", filename) != 1) {
fprintf (stderr, "error: user canceled input.\n");
return 1;
}
empty_stdin(); /* remove '\n' and any add'l chars in input buffer */
fp = fopen (filename, "r"); /* open filename */
if (fp == NULL) /* validate file open for reading */
perror ("fopen-input");
} while (fp == NULL);
printf("Opened file name %s\n\n",filename);

/* read up to MAXR team records from file */
while (ndx < MAXR && fgets (buf, MAXB, fp)) {
/* parse data from buffer filled, saving return */
int rtn = sscanf (buf, " %49s %d %d %d" , roster[ndx].team,
&roster[ndx].wins, &roster[ndx].loss,
&roster[ndx].tie);
if (rtn < 4) /* if less than 4 conversions, get next line */
continue;

/* compute points (2 * wins + ties) */
roster[ndx].points = roster[ndx].wins * 2 + roster[ndx].tie;
ndx++; /* increment index */
}
fclose (fp); /* close file */

/* sort roster based on points (descending order) */
qsort (roster, ndx, sizeof *roster, compare);

/* outpout results */
printf ("Here are the overall ALCentral Standings!\n\n"
"Team Wins Loss Tie Points\n\n");
for (int i = 0; i < ndx; i++)
printf ("%-12s %4d %4d %4d %4d\n", roster[i].team,
roster[i].wins, roster[i].loss, roster[i].tie,
roster[i].points);

return 0;
}


输入文件示例

该文件按给定方式提供,在记录之间使用空白行。

$ cat dat/teams.txt
Indians 54 45 5

Twins 45 53 7

Tigers 43 59 8

White_Sox 35 64 9

Royals 30 69 3


使用/输出示例

$ ./bin/qsortstrcmp

enter input filename: dat/teams.txt
Opened file name dat/teams.txt

Here are the overall ALCentral Standings!

Team Wins Loss Tie Points

Indians 54 45 5 113
Twins 45 53 7 97
Tigers 43 59 8 94
White_Sox 35 64 9 79
Royals 30 69 3 63


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

关于c - 在我的结构进入txt文件之前使用qsort和strcmp,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51598867/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com