/* * Copyright 2011 Steven Gribble * * This file is the solution to an exercise problem posed during * one of the UW CSE 333 lectures (333exercises). * * 333exercises is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * 333exercises is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with 333exercises. If not, see . */ // Lecture 6 exercise 1 // // // Write a program that: // - uses argc/argv to receive the name of a text file // - reads the contents of the file a line at a time // - parses each line, converting text into a uint32_t // - builds an array of the parsed uint32_t’s // - sorts the array // - prints the sorted array to stdout // hints: use “man” to read about getline, sscanf, realloc, and qsort #include #include #include #include #include // Reads a line of input from stdin using fgets(), or // NULL on error. Caller is responsible for free()'ing the // returned string. Does not include a newline at the // end of the string. char *GetNextLine(FILE *f); // Read in the array of integers from the file F. int *ReadIntArray(FILE *f, int *arrlen); // Compare two integers; passed to qsort. int IntComparator(const void *el1, const void *el2); void Usage(void) { fprintf(stderr, "usage: ./exercise1 filename\n"); exit(EXIT_FAILURE); } int main(int argc, char **argv) { FILE *f; int *array, arraylen; if (argc != 2) Usage(); f = fopen(argv[1], "r"); if (f == NULL) { fprintf(stderr, "Couldn't open '%s':", argv[1]); perror(NULL); Usage(); } array = ReadIntArray(f, &arraylen); if (array == NULL) { fprintf(stderr, "File '%s' doesn't contain integers\n", argv[1]); exit(EXIT_FAILURE); } qsort(array, arraylen, sizeof(int), &IntComparator); { int i; for (i = 0; i < arraylen; i++ ) { printf("%d\n", array[i]); } } fclose(f); free(array); return EXIT_SUCCESS; } int *ReadIntArray(FILE *f, int *arrlen) { int *array = NULL, len = 0; while (1) { char *nextline; int nextint, res; // Read the next line of input. nextline = GetNextLine(f); if (nextline == NULL) { // EOF break; } // Convert to an integer. res = sscanf(nextline, "%d", &nextint); if (res == 0) { // bogus string -- not an integer. exit with failure. fprintf(stderr, "file doesn't contain integers; quitting.\n"); exit(EXIT_FAILURE); } // Grow the integer array. array = (int *) realloc(array, (len + 1) * sizeof(int)); array[len] = nextint; len++; free(nextline); } *arrlen = len; return array; } // We re-use and modify the GetNextLine() function from // lecture 7 exercise 1. char *GetNextLine(FILE *f) { char *linestr = NULL; int count = 0; // Initialize linestr to contain a NULL-terminated // string. We'll grow it one character at a time // using realloc(). ("man realloc") linestr = (char *) malloc(1 * sizeof(char)); if (linestr == NULL) return NULL; linestr[0] = '\0'; while ( 1 ) { // Allocate space for the next character + NULL. Yes, this // is not the most elegant use of realloc(), but it gets the // job done. ;) linestr = realloc(linestr, count+2); if (linestr == NULL) { free(linestr); return NULL; } // Read in the next character. Note fgets reads (size-1) // characters and adds a '\0', so we need size=2. if (fgets(&(linestr[count]), 2, f) == NULL) { // We hit the end of file. Return our string, or null // if we didn't read anything. if (count == 0) { free(linestr); return NULL; } return linestr; } if (linestr[count] == '\n') { // We hit the end of a line. Return our string, but overwrite // the newline with '\0'. linestr[count] = '\0'; return linestr; } // fall through to next loop. count++; } } int IntComparator(const void *el1, const void *el2) { int *int1ptr, *int2ptr; int1ptr = (int *) el1; int2ptr = (int *) el2; if (*int1ptr > *int2ptr) return 1; if (*int1ptr < *int2ptr) return -1; return 0; }