COMS W4995 C++ Deep Dive for C Programmers

Index of 2025-9/code/09

Parent directory
Makefile
grades-malformed.txt
grades.txt
io1.cpp
io2.cpp
io3.cpp

Makefile

CC  = g++
CXX = g++

CFLAGS   = -g -Wall
CXXFLAGS = -g -Wall -std=c++20

executables = io1 io2 io3

.PHONY: default
default: $(executables)

io1: io1.o

io2: io2.o

io3: io3.o

.PHONY: clean
clean:
	rm -f *~ a.out core *.o $(executables)

.PHONY: all
all: clean default

grades-malformed.txt

   "Edgar Allan Poe" , 88.8

"Mark Twain",,    66.6

  "Herman Melville",77.7

grades.txt

   "Edgar Allan Poe" , 88.8

"Mark Twain",     66.6

  "Herman Melville",77.7

io1.cpp

#include <iostream>
#include <iomanip>

void print_io_states(std::ios& io) {
    std::cout << '\t';
    std::cout << " fail()==" << io.fail();
    std::cout << "  bad()==" << io.bad();
    std::cout << "  eof()==" << io.eof();
    std::cout << '\n';
}

int sum_ints(std::istream& is) {
    int i, sum = 0;
    while (is >> i) {
        sum += i;
        std::cout << "current sum: " << std::setw(4) << sum;
        print_io_states(is);
    }
    return sum;
}

int main() {
    int sum = sum_ints(std::cin);
    std::cout << "  final sum: " << std::setw(4) << sum;
    print_io_states(std::cin);
}

io2.cpp

#include <iostream>
#include <iomanip>

void print_io_states(std::ios& io) {
    std::cout << '\t';
    std::cout << " fail()==" << io.fail();
    std::cout << "  bad()==" << io.bad();
    std::cout << "  eof()==" << io.eof();
    std::cout << '\n';
}

int sum_ints(std::istream& is) {
    int i, sum = 0;
    while (!is.eof()) {
        is >> i;
        if (is.bad()) {
            throw std::runtime_error{"bad istream"};
        } else if (is.fail()) {
            // fail(), but not bad()
            if (is.eof()) {
                // failbit && eofbit: this is normal (trailing whitespace)
                break;
            }
            // failbit && !eofbit: probably non-digit; just skip it
            is.clear();
            char c;
            is.get(c);
            std::cout << "  skipped: " << c << '\n';
        } else {
            // read i successfully;
            // we could have hit eof or not (depends on trailing whitespace)
            sum += i;
            std::cout << "current sum: " << std::setw(4) << sum;
            print_io_states(is);
        }
    }
    return sum;
}

int main() {
    int sum = sum_ints(std::cin);
    std::cout << "  final sum: " << std::setw(4) << sum;
    print_io_states(std::cin);
}

io3.cpp

#include <iostream>
#include <iomanip>
#include <fstream>
#include <sstream>
using namespace std;

static ostream& operator<<(ostream& os, const pair<string,double>& e) {
    return os << "[" << e.first << "] (" << e.second << ")";
}

static istream& operator>>(istream& is, pair<string,double>& e) {
    char c;
    // read opening quote, skipping whitespace
    if (is >> c && c == '"') {
        string student;
        // read all chars into student, stop at closing quote, then discard it
        if (std::getline(is, student, '"')) {
            // read a comma, skipping whitespace
            if (is >> c && c == ',') {
                double grade;
                if (is >> grade) {
                    // returns an std::pair of student & grade
                    e = make_pair(student, grade);
                    return is;
                }
            }
        }
    }
    // if we are here, we could not read "student name", grade
    is.setstate(ios_base::failbit);
    return is;
}

void f1(istream& is);
void f2(istream& is);
void f3(const char* filename);

int main(int argc, char** argv) {
    try {
        f1(cin);
        // f2(cin);
        // f3(argv[1]);
    } catch (const exception& x) {
        cerr << x.what() << '\n';
    }
}

void f1(istream& is) {
    while (!is.eof()) {
        is >> std::ws;          // discard leading whitespace
        if (!is || is.eof()) {  // break if nothing else
            break;
        }
        pair<string,double> e;
        is >> e;
        if (is.fail()) {
            break;
        }
        cout << e << '\n';
    }

    if (is.bad()) {
        throw runtime_error{"bad istream"};
    } else if (is.fail()) {
        throw invalid_argument{"bad grade format"};
    }
}

void f2(istream& is) {
    string str;

    while (std::getline(is, str)) {
        istringstream iss(str);

        try {
            f1(iss);
        } catch (const invalid_argument& x) {
            cerr << x.what() << ": " << str << '\n';
        }
    }
}

void f3(const char* filename) {
    ifstream ifs { filename };
    if (!ifs) {
        if (filename != nullptr)
            throw runtime_error{"can't open file: "s + filename};
        else
            throw runtime_error{"no file name provided"};
    }
    f2(ifs);
}