I dont know where I ‘m going wrong. Code below is expected to accept user input of olympic swimmers’ fname, lname country and finishing time and qsort the result on the fastest time as below;
**Sample Input** ADLINGTON Rebecca GBR 4:03.01 MUFFAT Camille FRA 4:01.45 FRIIS Lotte DNK 4:03.98 SCHMITT Allison USA 4:01.77 **Sample Output** MUFFAT Camille FRA 4:01.45 SCHMITT Allison USA 4:01.77 ADLINGTON Rebecca GBR 4:03.01 FRIIS Lotte DNK 4:03.98
struct mtime_t {
int mins;
int secs;
int fsecs;
};
typedef struct mtime_t mtime;
struct olympians {
char fname[15];
char lname[15];
char country[3];
int time;
int mins, secs, fsecs;
mtime otime;
};
/* qsort struct comparision function (time float field) */
int struct_cmp_by_time(const void *a, const void *b)
{
struct olympians *ia = (struct olympians *)a;
struct olympians *ib = (struct olympians *)b;
return (int)(60*ia->time - 60*ib->time);
}
/* struct array printing function */
void print_struct_array(struct olympians *array, size_t len)
{
size_t i;
for(i=0; i<len; i++)
printf("%s %s %s \t %d:%d,%d\n", array[i].lname, array[i].fname,
array[i].country, &array[i].otime.mins,
&array[i].otime.secs, &array[i].otime.fsecs);
puts("\n");
}
/* sorting structs using qsort() */
void sort_structs_time()
{
int i, ath_num;
struct olympians *ath_recs;
scanf("%d", &ath_num);
ath_recs = (struct olympians *) malloc(ath_num*sizeof(struct olympians));
for(i = 0; i < ath_num; i++) {
scanf("%s %s %s %d:%d,%d\n", ath_recs[i].fname, ath_recs[i].lname,
ath_recs[i].country, &ath_recs[i].mins, &ath_recs[i].secs, &ath_recs[i].fsecs);
}
puts("\n");
/* print original struct array */
print_struct_array(ath_recs, ath_num);
/* sort array using qsort function */
qsort(ath_recs, (size_t) ath_num, sizeof(struct olympians), struct_cmp_by_time);
/* print sorted struct array */
print_struct_array(ath_recs, ath_num);
}
/* call to the function) */
int main()
{
/* run the function */
sort_structs_time();
return 0;
}
Another problem is that your input and output formats use
,as the decimal point; your sample data uses.as the decimal point.And another problem is that you don’t set the
timefield to any value during input. I’d probably go with:If I was being paranoid, I’d ensure that the minutes, seconds and fractional seconds were all zero or positive (non-negative). And I’d probably write the code to read a whole line into a buffer with
fgets()and then parse withsscanf(); it makes error detection easier.It would be better not to make the user do the counting of the data; computers are good at counting. You just have to allocate the array as you go, which requires a modicum of care to avoid quadratic behaviour.
Then, in the comparison code, there’s no need to multiply by 60:
I use the structure shown for comparator functions because it is extensible, and because it avoids problems with arithmetic overflow. In this application, it is very unlikely that the difference between two times will ever cause problems, but avoiding trouble is still a good idea, and subtracting two integers could lead to overflow (wraparound) in general.
In your code:
My compiler complains about the
&in front ofmins,secsandfsecs. If your compiler isn’t doing that, turn up the warning levels until it does, or get a better compiler.Your athlete printing code uses the
otimesub-structure ofstruct olympians, but your code doesn’t set it (and it duplicates the values in the separate membersmins,secs,fsecs). That threw me off track for a bit while debugging your code. This code works. It includes a separate little functionprint_athlete()(which should probably beprint_olympian()) to print a single athlete, and theprint_struct_array()code uses it — but I was also able to use it while working out why the input data wasn’t being printed in the output (that call is still in the code). Echoing input after reading it is a basic debugging technique. The code also checks thatmalloc()succeeded. (I usually have a function such asvoid dump_olympian(FILE *fp, const char *tag, const struct olympian *athlete);to print a complex structure to a nominated file. The tag is printed too, which allows me to annotate each call to to the dump function. The dump function should normally dump every element of the structure.)In production code, I have a set of functions such as
extern void err_error(const char *fmt, ...);which report an error with an interface like theprintf()functions;err_error()exits too. This reduces the 4 lines of error reporting to just 1, which means I’m more likely to do it.For the input data (note switch of
.and,):The output is:
The first block is from the debug printing in the input loop; the other two are the before and after images, of course, from your original code.
Unfixed issue
There’s one problem you’ll need to resolve (in two parts). The easy bit is that the output:
should be
or even:
This is fixed by using
%.2dinstead of%din the print formats.The hard part is that if the input time string is:
it needs to be treated as 4:03,10 and not as 4:03,01. Worse, 4:3,9 should be 4:03,90, not 4:03,09; that gives the athlete a 0.81 second advantage in the sorting, simply because the trailing zero was omitted (so it really does matter). This will require different input code; I might even go so far as to read the fraction part into a string of length 3 with
%2[0-9], and then post-process that into a number. That way you can tell whether one or two digits were entered.Incidentally, you could avoid the conversion to
timealtogether by sorting directly on the component parts, and then the systematic structure of the comparator becomes beneficial:(On the whole, you were pretty close to getting your code right — well done.)
Mildly hacked but working code
Not all the recommended changes are in this code, but it produces reasonable output, more or less.