/* * Program that, given a set of ranges and an input file of integers, * says how many items in the input file are in each range. * * Command-line arguments: * input file * ranges in the form N,M */ #include #include #include typedef struct { int start; int end; int count; } range_counter_t; int rcount_compar(const void *e1, const void *e2); int main(int argc, char *argv[]) { /* check for errors in command-line arguments */ if (argc < 3) { printf("usage %s input file ranges .... (in form N,M)\n", argv[0]); return 1; } char *filename = argv[1]; int num_rcounts = argc-2; range_counter_t rcounts[num_rcounts]; /* rather than this, could also use malloc to make array */ char *endptr; for (int i = 0; i < num_rcounts; ++i) { rcounts[i].start = strtol(argv[2+i], &endptr, 10); if (*endptr != ',') { puts("ranges must be in the form N,M"); return 1; } rcounts[i].end = strtol(endptr+1, &endptr, 10); if (*endptr != '\0') { puts("ranges must be in the form N,M"); return 1; } rcounts[i].count = 0; if (rcounts[i].start > rcounts[i].end) { printf("warning: N > M for range %s\n", argv[2+i]); /* FIXME might be better to skip? */ } } /* * sort ranges and check for overlap */ qsort(rcounts, num_rcounts, sizeof rcounts[0], rcount_compar); for (int i = 0; i < num_rcounts-1; ++i) { if (rcounts[i].end >= rcounts[i+1].start) { printf("warning: overlapping ranges %d,%d and %d,%d\n", rcounts[i].start, rcounts[i].end, rcounts[i+1].start, rcounts[i+1].end); } } /* * process input file and print result */ FILE * infile = fopen(filename, "r"); if (infile == NULL) { printf("cannot open input file %s\n", filename); return 1; } int input; int not_in_a_range = 0; while (fscanf(infile, "%d", &input) == 1) { bool found = false; for (int i = 0; i < num_rcounts; ++i) { if ((input >= rcounts[i].start) && (input <= rcounts[i].end)) { rcounts[i].count += 1; found = true; } } if (!found) { not_in_a_range += 1; } } if (!feof(infile)) { puts("invalid data in input file"); /* FIXME or return 1 here? */ } for (int i = 0; i < num_rcounts; ++i) { printf("[%d,%d]: %d\n", rcounts[i].start, rcounts[i].end, rcounts[i].count); } printf("%d input values not in a range\n", not_in_a_range); return 0; } /* * comparison function for ranges (to pass to qsort) * sorts by start value, then by end value */ int rcount_compar(const void *e1, const void *e2) { const range_counter_t *r1 = e1; const range_counter_t *r2 = e2; if (r1->start < r2->start) { return -1; } else if (r1->start > r2->start) { return 1; } else if (r1->end < r2->end) { return -1; } else if (r1->end > r2->end) { return -1; } else { return 0; } }