Download as pdf or txt
Download as pdf or txt
You are on page 1of 24

File IO and Characters

Maps

Typedefs and constants

Object-orientated Programming for Automation and Robotics


Lecture 5: File IO, Maps, Typedefs

Dr. Christoph Schubert


TU Dortmund Chair of Software-Technology https://ls10-wiki.cs.uni-dortmund.de/oop/

Winter Term 2010/11

File IO and Characters

Maps

Typedefs and constants

Lets recall what we did last week. . .

File IO and Characters

Maps

Typedefs and constants

Our program for today

File IO and Characters

Maps

Typedefs and constants

File IO and Characters

Maps

Typedefs and constants

Overview

File IO and Characters

Maps

Typedefs and constants

File IO and Characters

Maps

Typedefs and constants

Reading from les


Reading from a le works like reading from the console. Example: read all integers from a le and print them to the console:
1 2 3 4 5 6 7 8 9 10 11 12 13 14

# include < fstream > # include < iostream > int main () { std :: ifstream in_file ( " input . txt " ) ; if ( not in_file ) std :: perror ( " input . txt " ) ; else { int x (0) ; while ( in_file >> x ) std :: cout << x << " \ n " ; in_file . close () ; } }

(listing 13-1.cpp)

File IO and Characters

Maps

Typedefs and constants

Reading from les: explanation


line line

1 In order to use le IO, one has to include fstream 5 Create a new std::ifstream variable (an object) and ask it to try to open the le input.txt
std::ifstream (= input le stream) is a data-type declared

in fstream
line

6 Check if input.txt was opened correctly. (Similar to checking after reading from std::cin) 7 If not: print an error message. We use std::perror

line line line

10 Read integers from in_file as long as possible. 12 Finally, close in_file. This should always be done.

Reading from les works in exactly the same way as reading from std::cin: just remember that you have to open the le rst, and that you should close it later.

File IO and Characters

Maps

Typedefs and constants

Writing to les
Lets try to nd out what the following program does (leIO.cpp):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17

# include < fstream > int main () { std :: ifstream in_file ( " input . txt " ) ; if ( not in_file ) std :: perror ( " input . txt " ) ; else { std :: ofstream out_file ( " output . txt " ) ; if ( not out_file ) std :: perror ( " output . txt " ) ; else { int x (0) ; int i (1) ; while ( in_file >> x ) out_file < < " line " << i ++ <<" : " <<x < < " \ n " ; out_file . close () ; in_file . close () ; } } }

File IO and Characters

Maps

Typedefs and constants

Writing to les: explanations


line

6 Create a new std::ofstream variable (an object) and ask it to try to open the le output.txt
std::ofstream (= output le stream) is a data-type

declared in fstream
line line line

7 Check if output.txt was opened correctly. 8 If not: print an error message.

12 Write the integers read from in_file (line 11) to out_file. Notice the similarity to writing to std::cout 13 Close out_file. This should always be done.

line

Writing to les works in exactly the same way as writing to std::cout. First open a le, check whether it could be opened, dont forget to close it.

File IO and Characters

Maps

Typedefs and constants

Characters
The data-type char presents single characters. char literals (constants in program code) have to be enclosed in single quotation marks. Example: c. chars are special integers: A limited form of arithmetic is available: for instance, 7 - 0 == 7 holds. This is not so useful as it used to be (most computers

nowadays use Unicode instead of ASCII)


std::strings can be thought of as vectors of chars IO for chars: as usual (std::cin, std::cout, and le-objects): char x ( ) ; std :: cin >> x ; Beware: by default, std::cin skips whitespace characters.

File IO and Characters

Maps

Typedefs and constants

Useful input functions


So far we had trouble reading whole lines into std::strings or single characters into chars. The following functions help us out:
std::cin.get(c) reads a single character into char c. std::getline(std::cin, s) reads a whole line (including whitespaces) into std::string s.

These also works for ifstreams. Example:


char x ( ) ; std :: string str ; std :: ifstream ifile ( " input . txt " ) ; std :: getline ( ifile , str ) ; // reads a whole line into str ifile . get ( x ) ; // read the next character into x

File IO and Characters

Maps

Typedefs and constants

Example: reading in a date


Lets read in a date like February 27th, 2011 (parsedate.cpp):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17

int main () { std :: string monthName ; int year (0) ; int day (0) ; char c ( ) ; std :: cin >> monthName ; std :: cin >> day ; while ( c != \ n and std :: cin . get ( c ) ) if ( c >= 0 and c <= 9 ) { year = c - 0 ; while ( std :: cin . get ( c ) and c >= 0 and c <= 9 ) year = year *10 + c - 0 ; } std :: cout << year < < / << monthName < < / << day ; }

File IO and Characters

Maps

Typedefs and constants

Overview

File IO and Characters

Maps

Typedefs and constants

File IO and Characters

Maps

Typedefs and constants

Maps
A map (= dictionary, association) is a data-structure which

stores pairs of keys and values. For example, the following declares a map of std::strings and ints (one has to use #include <map>):
std :: map < std :: string , int > wordcounts ;

the keys are std::strings and the values are ints. Keys are unique inside a map. The map allows us to access the values through the keys:
++ wordcounts [ " hi " ]; wordcounts["hi"] gives access to the value stored for key "hi". We can use it like any int-variable (increase it, . . . ) When accessing a value for an unknown key, a pair consisting

of the key and a default value is added. This can cause problems.

File IO and Characters

Maps

Typedefs and constants

Iterating over maps


In order to iterate over a map, one should use iterators. Using iterators works in the same way as for std::vectors (begin(), end(), ++ operator) The value of a map-iterator is a std::pair object which has

two components: first and second.


In order to access first and second one should use the -> operator: iter->first is shorthand for (*iter).first It is not possible to use [] together with an index to access all values of a map: whenever we uss [] with an index (= key)

not in the map, this key together with a default value is automatically added.

File IO and Characters

Maps

Typedefs and constants

Example: counting ints


Lets rewrite the solution to assignment 3.4 using maps:
1 2 3 4 5 6 7 8 9 10

# include < iostream > # include <map > int main () { std :: map < int , int > histogram ; int x ; while ( std :: cin >> x ) ++ histogram [ x ]; // now we iterate over the histogram and print out all the ( key , value ) - pairs : for ( std :: map < int , int >:: iterator iter ( histogram . begin () ) ; iter != histogram . end () ; ++ iter ) std :: cout << iter - > first << \ t << iter - > second << \ n ; }

11 12 13 14 15 16

File IO and Characters

Maps

Typedefs and constants

Finding in maps

You can use find(key) to check whether a value with the given key exists in a map.
If a value could be found, find returns an iterator pointing

to this value
otherwise, find returns the end() of the map.

Since the pairs in a map are sorted using the keys, find() is very fast.

File IO and Characters

Maps

Typedefs and constants

Putting it all together


Lets try to make our day from date (Assignment 4.4) program more user-friendly by allowing input of the form february 22nd, 2009. We know already:
how to calculate the day when month, day, year are given as ints (solution 4.4) how to transform a date as above into a string and two ints:

monthName == "february", day == 22, year == 2009 How to translate the monthName to an int? Any ideas?
How about using a std::map<std::string, int> to get the

number of the month from the name?


How about getting this map from a le?

File IO and Characters

Maps

Typedefs and constants

Putting it all together


Lets try to make our day from date (Assignment 4.4) program more user-friendly by allowing input of the form february 22nd, 2009. We know already:
how to calculate the day when month, day, year are given as ints (solution 4.4) how to transform a date as above into a string and two ints:

monthName == "february", day == 22, year == 2009 How to translate the monthName to an int? Any ideas?
How about using a std::map<std::string, int> to get the

number of the month from the name?


How about getting this map from a le?

File IO and Characters

Maps

Typedefs and constants

Missing piece: reading the names of the month from a le


The le monthnames.txt contains data of the following form:
July 7 august 8

The following code reads this data into the map mNames:
1 2 3 4 5 6 7 8 9 10 11

std :: map < std :: string , int > mNames ; std :: ifstream namefile ( " monthnames . txt " ) ; if ( not namefile ) std :: perror ( " monthnames . txt " ) ; else { std :: string s ; int i (0) ; while ( namefile >> s >> i ) mNames [ s ] = i ; namefile . close () ; }

File IO and Characters

Maps

Typedefs and constants

Putting the pieces together


Things we need to do 1. read in the le with the month-names (see last slide) 2. read in the date from the user (see slide 11) 3. look up the name of the month in the map, get a numerical value
std :: map < std :: string , int >:: iterator monthIter ( mNames . find ( monthName ) ) ; if ( monthIter != mNames . end () ) month = monthIter - > second ;

4. calculate the day corresponding to the date as in solution 4.4. Advantage of storing names of the months in a le: we can add new names without recompiling the program. See dayscomplete.cpp.

File IO and Characters

Maps

Typedefs and constants

Overview

File IO and Characters

Maps

Typedefs and constants

File IO and Characters

Maps

Typedefs and constants

Typedefs
The names of the data-types we use in our programs can be quite long (remember std::vector<int>::iterator ?)
C++ allows us to give new names to types using typedef: typedef std :: vector < string >:: iterator string_iter ;

allows us to use string_iter in place of the longer name.


The general form of a typedef is

t y p e d e f d a t a t y p e newname ;
typedefs follow the same scope-rules as variable denitions. Choosing good names for data-types makes your programs easier to write/read/understand, and easier to modify.

Moreover, it reduces the chance to make errors.

File IO and Characters

Maps

Typedefs and constants

Constants
Values that are never going to change can be given a name using the const modier. For instance:
int const daysOfYear (365) ;

Constant must be initialized when they are declared and can never be changed. Thus:
daysOfYear = 300; // error !! // value of daysOfYear cannot be changed

You can declare constants of any type (std::string, bool, char, . . . ). As a rule of thumb: always use constants, never literal values! This makes your program easier to read and modify!

File IO and Characters

Maps

Typedefs and constants

What have we learned today?

You might also like