Your algorithm to sort the array of float
values is flawed: you return the difference of the float
values, which is converted to int
, which uses rounding, hence may produce an incorrect result.
The comparison function should be changed to:
int comp(const void *p1, const void *p2) {
float f1 = *(const float *)p1;
float f2 = *(const float *)p2;
return (f1 > f2) - (f1 < f2);
}
There are other problems;
avg
should be initialized to NULL
.
To print the lines, you should use an array of structures with the average and a copy of the line:
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX 300
typedef struct {
double avg;
int lineno;
char *line;
} element;
int comp(const void *p1, const void *p2) {
const element *e1 = p1;
const element *e2 = p2;
if (e1->avg == e2->avg) {
// keep lines with an identical average in the original order
return (e1->lineno > e2->lineno) - (e1->lineno < e2->lineno);
} else {
return (e1->avg > e2->avg) - (e1->avg < e2->avg);
}
}
double compute_avg(const char *s) {
double sum = 0;
int count = 0;
for (;;) {
char *p;
double val = strtod(s, &p);
if (p == s) // no more numbers
break;
sum += val;
count++;
s = p;
}
if (count > 0)
return sum / count;
else
return HUGE_VAL; // sort empty lines at the end
}
int main(int argc, char *argv[]) {
if (argc != 2) {
printf("Invalid format.
");
return -1;
}
FILE *fin = fopen(argv[1], "r");
if (!fin) {
printf("Error opening file %s.
", argv[1]);
return 1;
}
char buf[MAX];
int countLines = 0;
element *array = NULL;
while (fgets(buf, MAX, fin)) {
buf[strcspn(buf, "
")] = ''; // strip the trailing newline if any
array = realloc(array, (countLines + 1) * sizeof(*array));
array[countLines].line = strdup(buf);
array[countLines].lineno = countLines;
array[countLines].avg = compute_avg(buf);
countLines++;
}
fclose(fin);
qsort(array, countLines, sizeof(*array), comp);
for (int i = 0; i < countLines; i++) {
printf("%f: %s
", array[i].avg, array[i].line); // debug
//printf("%s
", array[i].line);
free(array[i].line);
}
return 0;
}
Notes:
for (;;)
is an infinite loop: a for
loop with no test. You could also write while (1)
but 1
looks confusingly similar to l
. This syntax is used in many languages who took it from C
: C++, java, javascript, C#...
return HUGE_VAL;
returns the maximum value of type double
, defined in <math.h>
. In most modern systems, this value is +Infinity. (INF
was a mistake). Storing this value as the average for empty lines will sort the at the end.
array = realloc(array, (countLines + 1) * sizeof(*array));
uses sizeof(*array)
instead of sizeof(element)
because it is more generic: taking the size of the array element is always correct and you do not need to update the code if the type of array
changes.
(f1 > f2) - (f1 < f2);
is expression that evaluates to -1
, 0
, 1
respectively if f1 < f2
, f1 == f2
and f1 > f2
, assuming neither f1
nor f2
are NaN values. The comparison operations in C have type int
and values 1
for true and 0
for false.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…