/* Notes about scoring: * * All things below may affect the score. * * Good things: * * * - Good use of functions and STL, and good style, is worth points * according to the correction template. For STL points you use at * least one container in a proper way and one iterator. * - Using setw and setfill * - Closing the file when done with it. * - const& på parametrar av klasstyp * * * Deviations from specification * * - Extra output not requested by specification * - Not skipping bars with zero length * - Not checking the numer of arguments properly. * - Not exiting if file could not be opened. * - Not using cerr for error messages * - Not finding all digits, or finding some twice, or buffer entire file * GOOD: while ( fin >> c ) * GOOD: while ( fin.get(c) ) * POOR: while ( fin >> word ) for (int i = 0; i < word.size(); ++i) * BAD: while ( getline(fin, line ) ) * // above reads entire (huge) file to string if file has only one line * BAD: while ( ! fin.eof() ) * // above may read last value from file twice, sometimes * * * Serious mistakes * * - Compiler errors or segmentation fault or bus error * - Stupid enumerations that can be replaced by loops or calculations. * This occured in several forms: * - Initiate vectors or lists with a loop. * - A map is automatically initiated when items are added, so need no * initiation. * - If a character is a digits should be at least poorly done: * GOOD: if ( isdigit(c) ) * OK: if ( c >= '0' && c <= '9' ) * INVENTIVE: int i; stringstream iss(string(c)); if ( iss >> i ) * POOR: for ( char n = '0'; n <= '9'; ++n ) if ( c == n ) * FAIL: if ( c == '0' || c == '1' || ... || c == '9' ) * (Always avoid enumerations in the code, programming let the * comuter do any enumeration.) * - Misleading names (mostly functions), a function "draw_diagram" * will for example be expected to draw a diagram, not a single bar * in a bar-graph. * - Uninitiated variables * * * Stupid things * * - Inappropriate or complicated solutions (opening file twice, * reading "int" or "string" when "char" is most appropriate, or * not understanding the the index operator[] of the map * automatically inserts the key with value zero if the key did not * exist). * - Empty if-statements * - Nonstandard names on the arguments to main(int argc, char* argv[]) * - Using ascii codes instead of character constants * GOOD: int i = (c - '0'); // convert digit to corresponding integer * INVENTIVE: see stringstream solution above... * POOR: int i = (c - 48); * BAD: int i = 0; for ( char n = '0'; n <= '9'; ++n ) { if ( c == n ) break; ++i; } * FAIL: switch ( c ) case 48: i = 0; case '1': i = 1; case ... * // above manually enumerates all cases * * * Trivial mistakes * * - Compiler warnings with -Wall -Wextra -std=c++98 * - No comments at all, or pointless comments * - Mistakes in style, including overuse of std:: * - Bars that do not look exectly as specification request * */ #include #include #include #include #include using namespace std; void draw_bar(char label, int lenght, ostream& os = cout) { os << setfill('-') << setw(lenght+1) << ' ' << endl; os << left << setfill(' ') << setw(lenght) << label << right << "| " << lenght << endl; os << setfill('-') << setw(lenght+1) << ' ' << endl << setfill(' '); } int main(int argc, char* argv[]) { if (argc != 2) { cerr << "Error: filname must be first argument." << endl; return 1; } ifstream infile; infile.open(argv[1]); if ( ! infile) { cerr << "Error: '" << argv[1] << "' could not be opened..." << endl; return 2; } char c; map freq_table; while (infile.get(c)) { if (isdigit(c)) { ++freq_table[c]; } } // freq_table['5']; map::iterator i; for (i = freq_table.begin(); i != freq_table.end(); ++i) { draw_bar(i->first, i->second); } return 0; }