/*
* 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;
}