You are on page 1of 29

CS 106B, Lecture 3

C++ I/O Streams; Grid

reading:
Programming Abstractions in C++, Chapter 4, 5.1

This document is copyright (C) Stanford Computer Science and Marty Stepp, licensed under Creative Commons Attribution 2.5 License. All rights reserved.
Based on slides created by Keith Schwarz, Julie Zelenski, Jerry Cain, Eric Roberts, Mehran Sahami, Stuart Reges, and others.

What's the output?


void mystery(string a, string& b) {
// erase 1 from index 0
a.erase(0, 1);
b += a[0];
b.insert(3, "FOO");
// insert at index 3
}
// A. arty stepp
int main() { // 01234
// B. marty stepp
string a = "marty";
// C. arty msteppFOO
string b = "stepp";
// D. marty steFOOppa
mystery(a, b);
// E. arty steFOOpp
cout << a << " " << b << endl;
return 0;
}
d4a57b1d

I/O Streams

reading:
Programming Abstractions in C++, Chapter 4

This document is copyright (C) Stanford Computer Science and Marty Stepp, licensed under Creative Commons Attribution 2.5 License. All rights reserved.
Based on slides created by Keith Schwarz, Julie Zelenski, Jerry Cain, Eric Roberts, Mehran Sahami, Stuart Reges, and others.

Reading files (4.3)


#include <fstream>

Introduces ifstream, ofstream classes for input/output files


Common pattern: open a file; read each line from it; close it
// read and print every line of a file
ifstream input;
input.open("poem.txt");
string line;
while (getline(input, line)) {
cout << line << endl;
}
input.close();

cin is a variable of type ifstream; cout is an ofstream

ifstream members (4.3)


Member function

Description

f.fail()

returns true if the last read call failed (e.g. EOF)

f.open(filename)

opens file represented by given C string

f.close()

stops reading file

f.get()

reads and returns 1 character

getline(f&, str&)

reads line of input into a string by reference;


returns a true/false indicator of success

f >> var

reads data from input file into variable (like cin)

Common file I/O bugs


Two ways to read an integer from a file:
ifstream input;
input.open("numbers.txt");
// 1. recommended
string line;
getline(input, line);
int n = stringToInteger(line);
// 2. discouraged
input >> n;

The second style is discouraged because it will fail if you have a


mixture of reading lines (getline) vs. reading individual tokens (>>).
6

Common file I/O bugs


Reading every line from a file:
// 1. correct
string line;
while (getline(input, line)) {
cout << line << endl;
}
// 2. incorrect
while (!input.fail()) {
getline(input, line);
cout << line << endl;
}

The second way is wrong; it prints the last line twice. (Why?)
7

Stanford library (4.3)


#include "filelib.h"
Function name
createDirectory(name)

Description
make a new directory with the given name

deleteFile(name)

erase a file from the disk

fileExists(name)

return true if the given file exists on disk

getCurrentDirectory()

return C++ program's directory as a string

isDirectory(name),
isFile(name)
openFile(ifstream&, name)

return true based on type of file path

promptUserForFile(
ifstream&, prompt)
readEntireFile(ifstream&, lines&)

repeatedly prompt for existing file's name


read file data into a collection of lines

renameFile(oldname, newname)

change a file's name

convenience for opening file by C++ string

Find errors

data.txt
Donald Knuth
M
76
Stanford U.

Q: Given ifstream input reading data.txt at


right, how many of the labeled inputs have bugs/problems?
A: 0

B: 1

D: 3

E: all 4

string name;
name = input.getline();

// #1

"Donald Knuth"

char gender;
gender = input.get();

// #2

'M'

int age;
getline(input, age);
stringToInteger(age);

// #3

76

string jobtitle;
input >> jobtitle;

C: 2

d4a57b1d
// #4

"Stanford U."

Grid

reading:
Programming Abstractions in C++, Section 5.1

This document is copyright (C) Stanford Computer Science and Marty Stepp, licensed under Creative Commons Attribution 2.5 License. All rights reserved.
Based on slides created by Keith Schwarz, Julie Zelenski, Jerry Cain, Eric Roberts, Mehran Sahami, Stuart Reges, and others.

Data and collections


Almost all interesting programs process data.
Data comes from many sources:
files on the local hard disk, databases,
downloaded over the internet,
input from hardware devices, ...

collection: an object that stores data; a.k.a. "data structure"


the objects stored are called elements
some collections maintain an ordering; some allow duplicates
typical operations: add, remove, clear, find/search, size, is empty

11

Stanford C++ vs. STL


Standard Template Library (STL): C++ includes a powerful library of
collections called STL for you to use in your programs.
But it is daunting for new programmers to learn.
It requires knowing lots of advanced C++ featurers.
It can be notoriously hard to understand or debug STL errors.

So we will learn about collections from the Stanford C++ library:


Vector, Grid, Stack, Queue, Set, Map, ...
These collections are very similar to the STL collections.
They have a somewhat simplified interface to use them.
They produce more helpful error messages when you have bugs.

12

Grid (5.1)
grid: a 2-dimensional indexed collection of elements
like a 2-dimensional array, but easier to use, more features
useful for data tables, 2D board games, geometric data, ...
in Stanford C++ lib, a grid can be represented as a Grid object
#include "grid.h"
column

row

75

61

83

71

94

89

98

100

63

54

51

49

Grid of homework scores;


each row is a student,
each column is an assignment
13

Type params (templates)


Grid<type> name;

When constructing a Grid, you must specify the


type of its elements in < >
This is called a type parameter ; Grid is a parameterized class.
In C++, parameterized classes are also called template classes.

The above constructs a Grid object; don't say new as in Java.


You can use any type of elements, even primitive type like int.

Grid<int> matrix(4, 3);


matrix[1][0] = 42;
...

14

Constructing a Grid
Grid<type> name;

// default empty size

The grid is unusable until you resize it to its proper size.


Get/set each element with [r][c] notation.
Grid<string> chessBoard;
chessBoard.resize(8, 8);
chessBoard[2][3] = "knight";
chessBoard[1][6] = "queen";
...

15

Grid members (5.1)*


Grid name<type>();
Grid name<type>(r, c);
g[r][c]
g.get(r, c)

or

constructs a new empty 0x0 grid,


or a grid with a given number of rows/columns
returns value at given row/col

g.fill(value);

set every cell to store the given value

g.inBounds(r, c)

returns true if given position is in the grid

g.numCols()

returns number of columns

g.numRows()

returns number of rows

g.resize(nRows, nCols);

resizes grid to new size, discarding old contents

g[r][c] = value;
or
g.set(r, c, value);

stores value at given row/col

g.toString()

returns a string representation of the grid


such as "{{3, 42}, {-7, 1}, {5, 19}}"

* (a partial list; see 5.1 for other members)

16

Grid documentation
See detailed documentation
about Grid (and any other
Stanford C++ library feature)
from the link on the
course web site.
stanford.edu/~stepp/cppdoc/

17

Iterating over a grid


Row-major order:
for (int r = 0; r < grid.numRows(); r++) {
for (int c = 0; c < grid.numCols(); c++) {
do something with grid[r][c];
0
}
0
75
}

Column-major order:

61

83

71

94

89

98

91

63

54

51

49

61

83

71

for (int c = 0; c < grid.numCols(); c++) {


for (int r = 0; r < grid.numRows(); r++) {
do something with grid[r][c];
0
}
0
75
}
1

94

89

98

91

63

54

51

49
18

What's the grid state?


Q: What is the grid state after the code below?
Grid<int> g(4, 3);
...
// fill with data at right
for (int c = 0; c < g.numCols(); c++) {
for (int r = 1; r < g.numRows(); r++) {
g[r][c] += g[r - 1][c];
}
} //
A.
B.
C.
0

r\c

D.

12

d4a57b1d

19

Grid as parameter
Whenever a Grid (or any object) is passed by value, C++ makes a
complete copy of its contents, rather than sharing it as in Java.
Objects are passed by value by default, not by reference.
Making copies of objects is slow, and often not what you want.
So, if you declare a Grid or another object as a parameter,
you should usually pass it by reference with &.
int computeSum(Grid<int>& g) {
...
}

20

Grid exercise
Write a function knightCanMove that accepts a grid and two row/column pairs
(r1, c1), (r2, c2) as parameters, and returns true if there is a knight at chess board
square (r1, c1) and he can legally move to empty square (r2, c2).
Recall that a knight makes an "L" shaped move, going 2 squares in one
dimension and 1 square in the other.
knightCanMove(board, 1, 2, 2, 4) returns true
0

"king"

"knight"

2
3

"rook"

4
5
6
7
21

Grid exercise solution


bool knightCanMove(Grid<string>& board, int r1, int c1,
int r2, int c2) {
if (!board.inBounds(r1, c1) || !board.inBounds(r2, c2)) {
return false;
}
if (board[r1][c1] != "knight" || board[r2][c2] != "") {
return false;
}
int dr = abs(r1 - r2);
int dc = abs(c1 - c2);
if (!((dr == 1 && dc == 2) || (dr == 2 && dc == 1))) {
return false;
}
return true;
}

22

Grid solution 2
bool knightCanMove(Grid<string>& board, int r1, int c1,
int r2, int c2) {
int dr = abs(r1 - r2), dc = abs(c1 - c2);
return board.inBounds(r1, c1) && board.inBounds(r2, c2)
&& board[r1][c1] == "knight" && board[r2][c2] == ""
&& ((dr == 1 && dc == 2) || (dr == 2 && dc == 1));
}

23

Iterating over neighbors


If you want to examine the neighbors of an element at (r, c):
for (int nr = r - 1; nr <= r + 1; nr++) {
for (int nc = c - 1; nc <= c + 1; c++) {
do something with grid[nr][nc];
}
}

Be careful not to access indexes that are


outside the bounds of the grid.
Example at right: r = 1, c = 2

75

61

83

71

71

94

89

98

91

91

63

54

51

49

49

21

92

68

37

24

Overflow (extra) slides

This document is copyright (C) Stanford Computer Science and Marty Stepp, licensed under Creative Commons Attribution 2.5 License. All rights reserved.
Based on slides created by Keith Schwarz, Julie Zelenski, Jerry Cain, Eric Roberts, Mehran Sahami, Stuart Reges, and others.

String streams (4.3)


#include <sstream>

Allows you to read/write tokens to/from a string as if it were a file


string streams have same members (<<, >>, etc.) as cin/cout, files
Function name
istringstream(str)

Description
open istream to read tokens from string

ostringstream()

open ostream to write tokens into a string

string phone = "650 723 6602";


int n1, n2, n3;
istringstream tokens(phone);
tokens >> n1 >> n2 >> n3;
// (650)723-6602
cout << "(" << n1 << ")" << n2 << "-" << n3 << endl;
ostringstream writer;
writer << phone << ",ext1234";
string phone2 = writer.str();
cout << phone2 << endl;

// 650 723 6602,ext1234

26

Formatted I/O
#include <iomanip>

functions to produce formatted output, a la printf


Function name

Description

setw(n)

right-aligns next token in a field n chars wide

setfill(ch)

sets padding chars inserted by setw to the given char (default ' ')

setbase(b)

prints future numeric tokens in base-b

left, right

left- or right-aligns tokens if setw is used

setprecision(d)

prints future doubles with d digits after decimal

fixed

prints future doubles with a fixed number of digits

scientific

prints future doubles in scientific notation

for (int i = 2; i <= 2000; i *= 10) {


cout << left << setw(4) << i
<< right << setw(8) << fixed
<< setprecision(2) << sqrt(i) << endl;
}

//
//
//
//

2
20
200
2000

1.41
4.47
14.14
44.72
27

Exercise
Given hours.txt of section leader hours worked, in this format:
123 Alex 3 2 4 1
46 Jessica 8.5 1.5 5 5 10 6
7289 Erik 3 6 4 4.68 4

Write code to output hours worked by each SL in this format:


Alex
Jessica
Erik

(ID# 123) worked 10.0 hours (2.50/day)


(ID#
46) worked 36.0 hours (6.00/day)
(ID# 7289) worked 21.7 hours (4.34/day)

28

Exercise solution
while (true) {
double hours;
tokens >> hours;
if (tokens.fail()) {
break;
}
totalHours += hours;
days++;
}

/* This program computes the ... */


#include <fstream>
#include <iomanip>
#include <iostream>
#include <sstream>
using namespace std;
int main() {
ifstream input;
input.open("hours.txt");
string line;
while (getline(input, line)) {
// "7289 Erik 3 6 4 4.68 4"

// Erik
//

istringstream tokens(line);
int id;
// 7289
string name;
// "Erik"
tokens >> id >> name;
// rest of tokens are days
double totalHours = 0.0;
int days = 0;
...

(ID# 7289) worked


21.7 hours (4.34/day)
cout << left << setw(9)
<< name << "(ID#"
<< right << setw(5)
<< id << ") worked "
<< fixed << setprecision(1)
<< totalHours << " hours ("
<< setprecision(2)
<< totalHours/days
<< "/day)" << endl;

}
return 0;
}

29

You might also like