################################################################# # c ĒŠ // usage: // ./a.out -c ma // to sort by math grade; // ./a.out -c avg // to sort by average grade; // ... etc. #include #include #include #include int const MAX_LENGTH = 256; int const MAX_REC = 256; typedef struct { char id[10], name[9]; int ch, en, ma; double avg; } student; int cmp_by_id(void const * a, void const * b) { student const * p = (student const *) a; student const * q = (student const *) b; return strcmp(p->id, q->id); } int cmp_by_ch(void const * a, void const * b) { student const * p = (student const *) a; student const * q = (student const *) b; return p->ch - q->ch; } int cmp_by_en(void const * a, void const * b) { student const * p = (student const *) a; student const * q = (student const *) b; return p->en - q->en; } int cmp_by_ma(void const * a, void const * b) { student const * p = (student const *) a; student const * q = (student const *) b; return p->ma - q->ma; } int cmp_by_avg(void const * a, void const * b) { student const * p = (student const *) a; student const * q = (student const *) b; return p->avg < q->avg ? -1 : p->avg > q->avg ? 1 : 0; } // 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; student data[MAX_REC]; 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; ++n; } fclose(f); if (argc > 1) { assert(strcmp(argv[1], "-c") == 0); if (strcmp(argv[2], "id") == 0) qsort(data, n, sizeof(student), cmp_by_id); else if (strcmp(argv[2], "ch") == 0) qsort(data, n, sizeof(student), cmp_by_ch); else if (strcmp(argv[2], "en") == 0) qsort(data, n, sizeof(student), cmp_by_en); else if (strcmp(argv[2], "ma") == 0) qsort(data, n, sizeof(student), cmp_by_ma); else if (strcmp(argv[2], "avg") == 0) qsort(data, n, sizeof(student), cmp_by_avg); else fprintf(stderr, "no suitable sorting rule\n"); } else qsort(data, n, sizeof(student), cmp_by_avg); 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); if (not defined $opts{c} or $opts{c} eq "avg") { @result = sort cmp_by_avg @data; } elsif ($opts{c} eq "id") { @result = sort cmp_by_id @data; } elsif ($opts{c} eq "ch") { @result = sort cmp_by_ch @data; } elsif ($opts{c} eq "en") { @result = sort cmp_by_en @data; } elsif ($opts{c} eq "ma") { @result = sort cmp_by_ma @data; } else { print STDERR "no suitable sorting rule\n"; } foreach my $x (@result) { printf "@{$x}{'id','name','ch','en','ma'} | %4.1f\n", $x->{avg}; } sub cmp_by_id { return $a->{id} cmp $b->{id}; } sub cmp_by_ch { return $a->{ch} <=> $b->{ch}; } sub cmp_by_en { return $a->{en} <=> $b->{en}; } sub cmp_by_ma { return $a->{ma} <=> $b->{ma}; } sub cmp_by_avg { return $a->{avg} <=> $b->{avg}; }