从评论开始,您的包含数组的结构数组一开始是正确的。如前所述,唯一缺少的部分是添加一个成员来获取/存储每个 studentID 的分数(成绩)。添加这将允许逻辑工作并简化处理程序输出。实际上,它会简化为类似于以下的逻辑(包括按 ID 对结果进行排序):
...
/* constants for max students and marks */
enum { NSTD = 64, NMARK = 100 };
typedef struct {
int sid; /* student ID */
int nmarks; /* number grades */
int marks[NMARK]; /* grades array */
} student;
int main (int argc, char **argv) {
int i, j, sidx = 0;
student s[NSTD] = {{ .sid = 0 }};
...
for (; sidx < NSTD;) { /* for each id up to max NSTD */
int grade = 0;
printf (" enter student ID: "); /* enter/validate ID */
while (scanf (" %d", &s[sidx].sid) != 1) { ... }
printf (" Enter grades for student %d: ", s[sidx].sid);
while (scanf (" %d", &grade) == 1) { /* for each grade */
...
s[sidx].marks[s[sidx].nmarks++] = grade;
}
sidx++; /* increment student index */
}
...
输入所有数据并知道每个 studentID 有多少成绩后,对数据的迭代就变成了对每个 studentID 和标记的简单嵌套循环,例如:
for (i = 0; i < sidx; i++) {
printf ("\n Student ID : %3d grades :", s[i].sid);
for (j = 0; j < s[i].nmarks; j++)
printf (" %2d", s[i].marks[j]);
}
要对数据进行排序(或者当您认为排序 C 中的任何内容时)使用qsort。 qsort 的唯一挑战是编写一个小函数来告诉 qsort 如何对您传递的任何内容进行排序。 (您将传递一个指向student 的指针,因此只需根据student->sid 进行排序)。由于比较函数的输入将是 const void *(一个常量 void 指针),因此您只需将其转换为 student * 并引用 ID 成员:
int cmpsid (const void *a, const void *b)
{
student *s1 = (student *)a; /* technically you should add 'const' */
student *s2 = (student *)b; /* omitted for simmplicity */
/* comparing (a > b) - (a < b) prevents potential overflow */
return (s1->sid > s2->sid) - (s1->sid < s2->sid);
}
您可以通过在比较中简单地应用转换来避免中间变量 s1 和 s2:
int cmpsid (const void *a, const void *b)
{
/* (a > b) - (a < b) prevents potential overflow */
return (((student *)a)->sid > ((student *)b)->sid) -
(((student *)a)->sid < ((student *)b)->sid);
}
(以你更清楚的为准)
您调用qsort 对结构s 的数组进行排序很简单:
qsort (s, sidx, sizeof *s, cmpsid); /* sort by student ID */
将其放在一起并添加有意义的其他验证,您可以执行以下操作。从文本文件中读取数据的代码(如果没有给出文件名,则默认提示输入):
#include <stdio.h>
#include <stdlib.h> /* for qsort */
/* constants for max students and marks */
enum { NSTD = 64, NMARK = 100 };
typedef struct {
int sid; /* student ID */
int nmarks; /* number grades */
int marks[NMARK]; /* grades array */
} student;
int cmpsid (const void *a, const void *b); /* qsort comparison */
int main (int argc, char **argv) {
int i, j, sidx = 0;
student s[NSTD] = {{ .sid = 0 }};
FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;
if (!fp) { /* validate file open for reading */
fprintf (stderr, "error: file open failed '%s'.\n", argv[1]);
return 1;
}
printf ("\n enter student ID followed by grade (0-100)\n"
" 101 for next student, 102 when finished.\n\n");
for (; sidx < NSTD;) { /* for each id up to max NSTD */
int grade = 0, tries = 0;
printf (" enter student ID: "); /* enter/validate ID */
while (scanf (" %d", &s[sidx].sid) != 1) {
fprintf (stderr, " error: invalid student ID.\n");
if (++tries == 3) {
fprintf (stderr, " (max attempts reached, exiting.)\n");
goto done;
}
printf (" enter student ID: ");
}
printf (" Enter grades for student %d: ", s[sidx].sid);
while (scanf (" %d", &grade) == 1) { /* for each grade */
if (grade < 0 || 102 < grade) { /* invalid entry */
fprintf (stderr, " warning: invalid entry '%d'.\n", grade);
continue;
}
if (grade == 101) break; /* next student */
if (grade == 102) { /* exit input */
if (s[sidx].nmarks) sidx++;
goto done;
}
s[sidx].marks[s[sidx].nmarks++] = grade;
if (s[sidx].nmarks == NMARK) {
fprintf (stderr, " warning: max grades for ID %d.\n",
s[sidx].sid);
break;
}
}
sidx++; /* increment student index */
}
done:;
if (fp != stdin) fclose (fp); /* close file if not stdin */
qsort (s, sidx, sizeof *s, cmpsid); /* sort by student ID */
for (i = 0; i < sidx; i++) { /* output sorted data */
printf ("\n Student ID : %3d grades :", s[i].sid);
for (j = 0; j < s[i].nmarks; j++)
printf (" %2d", s[i].marks[j]);
}
putchar ('\n');
return 0;
}
/* integer comparison (use for all numeric types) */
int cmpsid (const void *a, const void *b)
{
/* (a > b) - (a < b) prevents potential overflow */
return (((student *)a)->sid > ((student *)b)->sid) -
(((student *)a)->sid < ((student *)b)->sid);
}
int cmpsid2 (const void *a, const void *b);
int cmpsid2 (const void *a, const void *b)
{
student *s1 = (student *)a; /* technically you should add 'const' */
student *s2 = (student *)b; /* omitted for simmplicity */
/* comparing (a > b) - (a < b) prevents potential overflow */
return (s1->sid > s2->sid) - (s1->sid < s2->sid);
}
示例输入
输入 10 名学生,每人 10 分:
$ cat dat/idmarks.txt
667 82 79 78 78 97 84 85 77 95 86 101
166 97 97 88 97 74 81 98 82 93 76 101
497 77 95 80 98 71 80 91 77 75 98 101
31 82 78 79 95 92 86 87 95 91 83 101
515 76 76 93 87 71 72 77 92 72 93 101
145 81 79 95 91 99 93 95 99 83 77 101
517 92 98 96 75 83 89 95 93 75 95 101
836 97 84 98 98 91 98 88 71 90 75 101
381 82 98 76 81 90 72 93 93 76 86 101
11 92 86 96 88 78 91 92 76 87 82 102
使用/输出示例
$ ./bin/studentmarks <dat/idmarks.txt
enter student ID followed by grade (0-100)
101 for next student, 102 when finished.
<snip prompts>
Student ID : 11 grades : 92 86 96 88 78 91 92 76 87 82
Student ID : 31 grades : 82 78 79 95 92 86 87 95 91 83
Student ID : 145 grades : 81 79 95 91 99 93 95 99 83 77
Student ID : 166 grades : 97 97 88 97 74 81 98 82 93 76
Student ID : 381 grades : 82 98 76 81 90 72 93 93 76 86
Student ID : 497 grades : 77 95 80 98 71 80 91 77 75 98
Student ID : 515 grades : 76 76 93 87 71 72 77 92 72 93
Student ID : 517 grades : 92 98 96 75 83 89 95 93 75 95
Student ID : 667 grades : 82 79 78 78 97 84 85 77 95 86
Student ID : 836 grades : 97 84 98 98 91 98 88 71 90 75
查看代码以及其他答案,如果您有任何问题,请告诉我。选择你的结构内容,让它适合你,它应该让生活更轻松。