C 结构和指针卡住了
我在C作业计划中面临一些问题:C 结构和指针卡住了,c,file,pointers,struct,C,File,Pointers,Struct,我在C作业计划中面临一些问题: 在选项#4,成绩只按降序排列,而在#5,成绩不会改变,只交换学生的姓名和分数 在选项#8,从文件输入的字符串和浮点将不会显示,我希望选项8是灵活的(通过选项#7输入文件时显示从文件或仅显示从#1菜单选项输入)。以下是该文件的示例: 80.64 John 90.40 Jane 78.00 Jake 守则: #include <stdio.h> #include <stdlib.h> #include <string.h>
80.64 John
90.40 Jane
78.00 Jake
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct Studata{
float min, max;
int many;
char *max1, *min1, gx, gn;
}studata;
struct Student{
char name[100], grade;
float score[100];
};
float average(struct Student student[100]){
float sum;
for(int i=0; i<student.many; i++){
sum += studata[i].score;
}
return sum/(float)student.many;
}
void MM(struct Student student[100]){
int i;
studata.min = 0;
studata.max = 100;
for (i=0; i<studata.many; i++){
if(*student[i].score > studata.min){
studata.min = student[i].score;
studata.min1 = student[i].name;
studata.gn = student[i].grade;
}
}
for (i=0; i<studata.many; i++){
if(student[i].score < studata.min){
studata.max = student[i].score;
studata.max1 = student[i].name;
studata.gx = student[i].grade;
}
}
}
void swapname(char *a, char *b){
char z[100];
strcpy(z, a);
strcpy(a, b);
strcpy(b, z);
}
void swapscore(float a, float b){
float temporary = a;
a = b;
b = temporary;
}
void swapgrade(char A1, char B1) {
char C1 = A1;
A1 = B1;
B1 = C1;
}
void Bubblesort(int mode, struct Student student[100]) {
int i, j;
if(mode == 1) {
for (i=0; i<studata.many; i++) {
for (j=i+1; j<studata.many; j++) {
if(student[j].score > student[i].score) {
swapname(student[i].name, student[j].name);
swapscore(student[i].score, student[j].score);
swapgrade(student[i].grade, student[j].grade);
}
}
}
}
else if(mode == 0) {
for(i=0; i<studata.many; i++) {
for(j=i+1; j<studata.many; j++) {
if(student[j].score < student[i].score) {
swapname(student[i].name, student[j].name);
swapscore(student[i].score, student[j].score);
swapgrade(student[i].grade, student[j].grade);
}
}
}
}
}
int main(){
struct Student student[100];
int selection=1;
FILE *file;
while (selection <= 8 && selection >= 1) {
printf("\n\n\t-------MENU-------\n\n");
printf("0. Enter Data of Students\n");
printf("1. Calculate the Average\n");
printf("2. Show Maximum and Minimum\n");
printf("3. Sort Score Ascending\n");
printf("4. Sort Score Descending\n");
printf("5. Save Scores\n");
printf("6. Load Scores from File\n");
printf("7. Load All Data\n");
printf("Choice (Other than 1-8 to Exit): ");
scanf("%d", &selection);
if(selection == 1) {
printf("=============================\n");
printf("\nHow many students would you like to input: ");
scanf(" %d", &studata.many);
for (int i=0; i<studata.many; i++) {
printf("\nStudent-%d Name\t: ", i+1);
scanf(" %[^\n]s", student[i].name);
printf("Student-%d Score\t: ", i+1);
scanf(" %f", &student[i].score);
while(student[i].score > 100 || student[i].score < 0) {
printf("Hey, wrong input, please input correctly, okay?");
printf("\nStudent-%d Score\t: ", i+1);
scanf(" %f",&student[i].score);
}
if (student[i].score <= 100 && student[i].score >= 90 ) {
student[i].grade= 'A';
}
else if (student[i].score < 90 && student[i].score >= 80) {
student[i].grade= 'B';
}
else if (student[i].score < 80 && student[i].score >=70) {
student[i].grade= 'C';
}
else if (student[i].score < 70 && student[i].score >=60) {
student[i].grade= 'D';
}
else if (student[i].score < 60 && student[i].score >=50) {
student[i].grade= 'E';
}
else {
student[i].grade = 'F';
}
}
}
else if(selection == 2) {
printf("=============================\n");
printf("Average of Score is %.2f", average(student));
}
else if(selection == 3) {
MM(student);
printf("=============================\n");
printf("Minimum\t: %s || %4.2f || %c\n", studata.max1, studata.max, studata.gx);
printf("Maximum\t: %s || %4.2f || %c\n", studata.min1, studata.min, studata.gn);
}
else if(selection == 4) {
printf("=============================\n");
Bubblesort(0,student);
for(int i=0; i<studata.many; i++) {
printf(" %s : %5.2f --> %c\n", student[i].name, student[i].score, student[i].grade);
}
}
else if(selection == 5) {
printf("=============================\n");
Bubblesort(1,student);
for(int i=0; i<studata.many; i++) {
printf(" %s : %5.2f --> %c\n", student[i].name, student[i].score, student[i].grade);
}
}
else if(selection == 6) {
char filename[100];
printf("=============================\n");
printf("Name of the file (with ext.): ");
scanf(" %[^\n]s", filename);
file = fopen(filename, "w");
for(int i=0; i<studata.many; i++) {
fprintf(file,"%.2f %s\n", student[i].score, student[i].name);
}
fclose(file);
}
else if(selection == 7) {
char filename[100];
char sub_ch;
int i;
printf("Enter name of file you want to open (with extension): ");
scanf(" %[^\n]s", filename);
file = fopen(filename, "r");
while (file == NULL) {
printf("I'm Error! Reinput? (Y/n): ");
scanf("%c", &sub_ch);
if(sub_ch == 'Y') {
printf("Enter name of file you want to open (with extension): ");
scanf(" %[^\n]s", filename);
}
file = fopen(filename, "r");
if(sub_ch == 'n') {
exit(1);
}
}
printf("=============================\n");
fscanf(file, "%f %s", &student[i].score, student[i].name);
while (!feof(file)) {
if (student[i].score <= 100 && student[i].score >= 90 ) {
student[i].grade= 'A';
}
else if (student[i].score < 90 && student[i].score >= 80) {
student[i].grade= 'B';
}
else if (student[i].score < 80 && student[i].score >=70) {
student[i].grade= 'C';
}
else if (student[i].score < 70 && student[i].score >=60) {
student[i].grade= 'D';
}
else if (student[i].score < 60 && student[i].score >=50) {
student[i].grade= 'E';
}
else {
student[i].grade= 'F';
}
printf("%s %8.2f --> %c\n", student[i].name, student[i].score, student[i].grade);
fscanf(file, "%f %s", &student[i].score, student[i].name);
}
fclose(file);
}
else if(selection == 8) {
printf("=============================\n");
for (int i=0; i<studata.many; i++) {
printf("Name || Score || Grade\t: %s || %3.2f || %c\n", student[i].name, student[i].score, student[i].grade);
}
}
}
return 0;
}
#包括
#包括
#包括
Studata结构{
浮动最小值,最大值;
int多;
字符*max1,*min1,gx,gn;
}斯图达塔;
结构学生{
字符名称[100],等级;
浮动分数[100];
};
浮动平均值(结构学生[100]){
浮点数;
对于(int i=0;i=70){
学生[i]。成绩='C';
}
否则如果(学生[i]。分数<70和学生[i]。分数>=60){
学生[i]。成绩='D';
}
否则如果(学生[i]。分数<60和学生[i]。分数>=50){
学生[i]。成绩='E';
}
否则{
学生[i]。成绩='F';
}
printf(“%s%8.2f-->%c\n”,学生[i]。姓名,学生[i]。分数,学生[i]。成绩);
fscanf(文件“%f%s”,&student[i]。分数,student[i]。姓名);
}
fclose(文件);
}
else if(选择==8){
printf(“==============================================\n”);
对于(int i=0;i在上面的技巧上进行扩展,使您的代码如此难以阅读(和维护)的原因是您忽略了上面注释中的(2)。您的实现(应用于数据的逻辑)与您的界面(您与用户的交互方式)并没有分开.相反,您的代码在一个跨越多行屏幕的菜单中混乱在一起
将实现与接口分开可以使每个接口的逻辑保持独立且可读。以下是一些可以改进接口代码和实现的其他方面:
不要用不必要的重复输出函数调用来扰乱实现
在编译过程中,compile with将所有相邻的字符串文本串联起来,这些字符串仅由空格分隔。这意味着您不需要10次单独调用printf()
来输出菜单。事实上,由于您显示的菜单中不需要进行任何转换,因此您不需要调用variadicprintf()
函数,更不用说调用它10次了。因为您需要线端控制,只需调用一次fputs()
,例如
fputs ("\n\n\t-----------MENU-----------\n\n"
" 0. Enter Data of Students\n"
" 1. Calculate the Average\n"
" 2. Show Maximum and Minimum\n"
" 3. Sort Score Ascending\n"
" 4. Sort Score Descending\n"
" 5. Save Scores\n"
" 6. Load Scores from File\n"
" 7. Load All Data\n\n"
"Choice (Other than 1-8 to Exit): ", stdout);
如果您希望在最后有一个'\n'
输出,那么只需使用put()
就可以了。一个调用就可以使菜单可读
创建逻辑函数以实现您的界面
您不需要在代码体的while
循环中包含10行菜单。如果您创建一个短函数来显示菜单,例如:
void show_menu (void)
{
fputs ("\n\n\t-----------MENU-----------\n\n"
" 0. Enter Data of Students\n"
" 1. Calculate the Average\n"
" 2. Show Maximum and Minimum\n"
" 3. Sort Score Ascending\n"
" 4. Sort Score Descending\n"
" 5. Save Scores\n"
" 6. Load Scores from File\n"
" 7. Load All Data\n\n"
"Choice (Other than 1-8 to Exit): ", stdout);
}
然后主循环可以保持可读性,例如
while (selection <= 8 && selection >= 1) {
show_menu();
在没有验证的情况下,当在if(selection==1)
中访问selection
(它现在持有一个不确定的值)时,调用未定义的行为。至少必须捕获错误并退出,例如
if (scanf("%d", &selection) != 1) {
fputs ("error: invalid integer input.\n", stderr);
exit (EXIT_FAILURE);
}
要优雅地处理错误,您需要知道使用scanf()
,当发生匹配失败时,从输入流中提取字符的过程将在该点停止,导致失败的违规字符将留在输入流中未读。必须在下一次尝试输入之前清除违规字符,否则输入将因相同原因再次失败,导致无限长的错误在很多情况下都会循环。这个网站上有数百个答案,展示了如何正确使用scanf()
更好的解释是,您不使用scanf()
获取用户输入,而是使用具有适当大小的缓冲区(字符数组)的fgets()
,然后使用sscanf()
从缓冲区中检索所需的任何值,这消除了输入流中未读字符的任何可能性
不要将界面与实现混为一谈
<> P> >没有代码,如果…..否则……如果……/Cord>逻辑用于确定字母级别应该在程序循环的中间。正如上面的 SujMeNuu()>代码>,该实现应该在一个简短的函数中,可以从主循环调用,例如
char get_ltrgrade (float f) /* return letter grade given float score */
{
if (f >= 90) return 'A';
else if (f >= 80) return 'B';
else if (f >= 70) return 'C';
else if (f >= 60) return 'D';
else return 'F';
}
然后,您只需对get\u ltrgrade();
将您的数据结构与您拥有的数据相匹配
您使用的struct Student
和struct Studata
与您显示的输入数据不匹配。您显示的输入数据每个学生都有一个分数。要匹配您的数据,仅使用struct Student
就可以了。现在,如果您有多个班级的学生,那么struct Studata
开始变得更有意义。float score>[100];
允许每个学生获得多个分数,但这与您显示的数据不匹配,并且在struct student
中没有计数器来跟踪该学生的有效分数。从您显示的情况来看,浮动分数:
更有意义
使用qsort()对数组进行排序
C提供qsort()
来处理任何类型的排序数组。qsort()
函数的效率将比您编写的任何排序都高出几个数量级,并且经过几十年的测试。新的C程序员通常避免使用qsort()
,因为它需要编写一个简短的compare()
通常小于5-1的函数
char get_ltrgrade (float f) /* return letter grade given float score */
{
if (f >= 90) return 'A';
else if (f >= 80) return 'B';
else if (f >= 70) return 'C';
else if (f >= 60) return 'D';
else return 'F';
}
#include <stdio.h>
#include <stdlib.h>
#define MAXC 1024 /* if you need a constant, #define one (or more) */
#define MAXN 128
#define MAXS 256
typedef struct { /* typedef allows use of student_t as type */
char name[MAXN],
ltrgrade;
float score;
} student_t;
char get_ltrgrade (float f) /* return letter grade given float score */
{
if (f >= 90) return 'A';
else if (f >= 80) return 'B';
else if (f >= 70) return 'C';
else if (f >= 60) return 'D';
else return 'F';
}
/* qsort compare by student_t->scoore (descending),
* change to >, < for ascending sort.
*/
int compare_score (const void *a, const void *b)
{
student_t *sa = (student_t*)a,
*sb = (student_t*)b;
return (sa->score < sb->score) - (sa->score > sb->score);
}
int main (int argc, char **argv) {
char buf[MAXC]; /* buffer to hold each line read from file */
student_t student[MAXS]; /* array of student_t (MAXS of them) */
size_t n = 0; /* array index (counter) */
/* 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;
}
/* while array not full, read each line into buf, VALIDATE read */
while (n < MAXS && fgets (buf, MAXC, fp)) {
/* split line into score and name, VALIDATE conversion */
if (sscanf (buf, "%f %127[^\n]", &student[n].score, student[n].name) == 2) {
/* get letter grade based on score */
student[n].ltrgrade = get_ltrgrade (student[n].score);
n += 1; /* increment index only on valid converison */
}
else /* handle error */
fprintf (stderr, "error: invalid line format, student[%zu].\n", n);
}
if (fp != stdin) /* close file if not stdin */
fclose (fp);
qsort (student, n, sizeof *student, compare_score); /* sort by score */
for (size_t i = 0; i < n; i++) /* output result */
printf ("%-12s %6.2f %c\n",
student[i].name, student[i].score, student[i].ltrgrade);
return 0;
}
qsort (student, n, sizeof *student, compare_score); /* sort by score */
$ ./bin/studata dat/studata.txt
Jane 90.40 A
John 80.64 B
Jake 78.00 C