################################################################# # c ĒŠ // usage: // ./a.out -c ma // to sort by math grade; // ./a.out -c avg // to sort by average; // ... etc. #include #include #include #include int const MAX_LENGTH = 256; #define MAX_REC 256 typedef struct { char id[10], name[9]; int ch, en, ma; double avg; } student; student data[MAX_REC]; int cmp_by_id(void const * a, void const * b) { int const * p = (int const *) a; int const * q = (int const *) b; return strcmp(data[*p].id, data[*q].id); } int cmp_by_ch(void const * a, void const * b) { int const * p = (int const *) a; int const * q = (int const *) b; return data[*p].ch - data[*q].ch; } int cmp_by_en(void const * a, void const * b) { int const * p = (int const *) a; int const * q = (int const *) b; return data[*p].en - data[*q].en; } int cmp_by_ma(void const * a, void const * b) { int const * p = (int const *) a; int const * q = (int const *) b; return data[*p].ma - data[*q].ma; } int cmp_by_avg(void const * a, void const * b) { int const * p = (int const *) a; int const * q = (int const *) b; return data[*p].avg < data[*q].avg ? -1 : data[*p].avg > data[*q].avg ? 1 : 0; } typedef struct { char const * name; int (* func)(void const *, void const *); } cmp_tab_entry; // To reduce distracting codes, we use assert() to check for error here. // However, this practice is lazy, irresponsible, and not recommended. int main(int argc, char *argv[]) { FILE * f; char s[MAX_LENGTH]; int i, n; int index[MAX_REC]; char * by_what; static cmp_tab_entry const cmp_tab[] = { { "id", cmp_by_id }, { "ch", cmp_by_ch }, { "en", cmp_by_en }, { "ma", cmp_by_ma }, { "avg", cmp_by_avg }, { NULL, NULL } }; n = 0; f = fopen("student.txt", "r"); assert(f); while (fgets(s, MAX_LENGTH, f)) { if (s[0] == '#') continue; i = sscanf(s, "%s %s %d %d %d", data[n].id, data[n].name, &data[n].ch, &data[n].en, &data[n].ma); if (i < 1) continue; assert(i == 5); data[n].avg = (data[n].ch + data[n].en + data[n].ma) / 3.0; index[n] = n; ++n; } fclose(f); if (argc > 1) { assert(strcmp(argv[1], "-c") == 0); by_what = argv[2]; } else by_what = "avg"; for (i=0; cmp_tab[i].name && strcmp(by_what, cmp_tab[i].name); ++i); if (cmp_tab[i].func) qsort(index, n, sizeof(int), cmp_tab[i].func); else fprintf(stderr, "no suitable sorting rule\n"); for (i=0; i) { next if /^#/; @rec{qw(id name ch en ma)} = split " "; next unless defined $rec{id}; print STDERR "parse error on line $.\n" unless defined $rec{ma}; $rec{avg} = ($rec{ch} + $rec{en} + $rec{ma}) / 3.0; push @data, { %rec }; } close F; getopts("c:", \%opts); my (%cmp_tab) = ( id => "cmp_by_id", ch => "cmp_by_ch", en => "cmp_by_en", ma => "cmp_by_ma", avg => "cmp_by_avg", ); my (@index) = 0..$#data; my ($func) = $cmp_tab{ defined $opts{c} ? $opts{c} : "avg" }; if (defined $func) { @result = sort $func @index; } else { print STDERR "no suitable sorting rule\n"; } foreach my $x (@result) { printf "@{$data[$x]}{'id','name','ch','en','ma'} | %4.1f\n", $data[$x]->{avg}; } sub cmp_by_id { return $data[$a]->{id} cmp $data[$b]->{id}; } sub cmp_by_ch { return $data[$a]->{ch} <=> $data[$b]->{ch}; } sub cmp_by_en { return $data[$a]->{en} <=> $data[$b]->{en}; } sub cmp_by_ma { return $data[$a]->{ma} <=> $data[$b]->{ma}; } sub cmp_by_avg { return $data[$a]->{avg} <=> $data[$b]->{avg}; }