You are on page 1of 79

<?

php

// instr function
// checks for an occurance of a string
// within another string
function instr($string,$find,$casesensitive = false) {
$i=0;
while (strlen($string)>=$i) {
unset($substring);
if ($casesensitive) {
$find=strtolower($find);
$string=strtolower($string);
}
$substring=substr($string,$i,strlen($find));
if ($substring==$find) return true;
$i++;
}
return false;
}

// a similar function, returns the number of occurances


function instrcount($string,$find,$casesensitive = false) {
$i=0;
$x=0;
while (strlen($string)>=$i) {
unset($substring);
if ($casesensitive) {
$find=strtolower($find);
$string=strtolower($string);
}
$substring=substr($string,$i,strlen($find));
if ($substring==$find) $x++;
$i++;
}
return $x;
}
// another similar function, this will return the position of
// the string. returns -1 if the string does not exist
function instrpos($string,$find,$casesensitive = false) {
$i=0;
while (strlen($string)>=$i) {
unset($substring);
if ($casesensitive) {
$find=strtolower($find);
$string=strtolower($string);
}
$substring=substr($string,$i,strlen($find));
if ($substring==$find) return $i;
$i++;
}
return -1;
}

?>

instr function ..

<?php

// instr function
// checks for an occurance of a string
// within another string
function instr($string,$find,$casesensitive = false) {
$i=0;
while (strlen($string)>=$i) {
unset($substring);
if ($casesensitive) {
$find=strtolower($find);
$string=strtolower($string);
}
$substring=substr($string,$i,strlen($find));
if ($substring==$find) return true;
$i++;
}
return false;
}

// a similar function, returns the number of occurances


function instrcount($string,$find,$casesensitive = false) {
$i=0;
$x=0;
while (strlen($string)>=$i) {
unset($substring);
if ($casesensitive) {
$find=strtolower($find);
$string=strtolower($string);
}
$substring=substr($string,$i,strlen($find));
if ($substring==$find) $x++;
$i++;
}
return $x;
}

// another similar function, this will return the position of


// the string. returns -1 if the string does not exist
function instrpos($string,$find,$casesensitive = false) {
$i=0;
while (strlen($string)>=$i) {
unset($substring);
if ($casesensitive) {
$find=strtolower($find);
$string=strtolower($string);
}
$substring=substr($string,$i,strlen($find));
if ($substring==$find) return $i;
$i++;
}
return -1;
}

?>
instr function ..

a modest stl tutorial


i am using a software tool called hyperlatex to create this document. the tutorial is also
available in gzip-compressed postscript form or zip-compressed postscript form. for those
wanting to install a copy of these pages on their system, they may be freely copied
providing they are not modified in any significant way (other than, say, locale changes).
the file tut.tar.z contains a tarred distribution of the pages. please note that i will be
making modifications to this document in the coming months, so you may want to
occasionally check for changes. i will start putting in version numbers, and if i can
manage to, changebars.

disclaimer
i started looking at stl in 1995; for a long time i could compile only minimal subsets of
the hp version of the library. more recently, the compilers used by the students i teach
have been able to support more of stl, and i have been adding it to the introductory and
advanced courses i teach. now, at the beginning of 1998, i use stl in the labs for all of the
courses i teach.
i have been using c++ since 1988, and teaching c++ and object-oriented design courses in
industry since 1990. i really like the design philosophies in stl; i think that you can learn a
great deal about how generalization can simplify programming by understanding why stl
is constructed the way it is.
mark nelson's book on stl is very good if you want to understand the internal details, but
is probably overkill for many people. musser and saini have a good book on stl, but it is a
bit out-of-date.
i haven't seen very much online documentation on stl, apart from the good but rather
dense paper by stepanov and lee, i thought i would try to write something to give people a
taste of what a good library will be do for them.
another reason for getting people to start trying out stl soon is to put pressure on the
compiler-writers to get their compilers patched up enough to take the strain it puts on
them...
i would greatly appreciate comments or suggestions from anyone.

outline
stl contains five kinds of components: containers, iterators, algorithms, function objects
and allocators.
in the section example i present a simple example, introducing each of the five categories
of stl components one at a time.
in the section philosophy i explain the rationale behind the organization of stl, and give
some hints on the best ways to use it. (not yet written)
the components section goes into each category of component in more detail.
the section extending stl shows how to define your own types to satisfy the stl
requirements. (not yet written)

a first example
most of you probably use some kind of auto-allocating array-like type. stl has one called
vector. to illustrate how vector works, we will start with a simple c++ program that
reads integers, sorts them, and prints them out. we will gradually replace bits of this
program with stl calls.

version 1: standard c++


here is a standard c++ program to read a list of integers, sort them and print them:
#include <stdlib.h>
#include <iostream.h>

// a and b point to integers. cmp returns -1 if a is less than b,


// 0 if they are equal, and 1 if a is greater than b.
inline int cmp (const void *a, const void *b)
{
int aa = *(int *)a;
int bb = *(int *)b;
return (aa < bb) ? -1 : (aa > bb) ? 1 : 0;
}

// read a list of integers from stdin


// sort (c library qsort)
// print the list

main (int argc, char *argv[])


{
const int size = 1000; // array of 1000 integers
int array [size];
int n = 0;
// read an integer into the n+1 th element of array
while (cin >> array[n++]);
n--; // it got incremented once too many times

qsort (array, n, sizeof(int), cmp);

for (int i = 0; i < n; i++)


cout << array[i] << "\n";
}
version 2: containers, iterators, algorithms
stl provides a number of container types, representing objects that contain other objects.
one of these containers is a class called vector that behaves like an array, but can grow
itself as necessary. one of the operations on vector is push_back, which pushes an
element onto the end of the vector (growing it by one).
a vector contains a block of contiguous initialized elements -- if element index k has been
initialized, then so have all the ones with indices less than k.
a vector can be presized, supplying the size at construction, and you can ask a vector how
many elements it has with size. this is the logical number of elements -- the number of
elements up to the highest-indexed one you have used. there is a also a notion of capacity
-- the number of elements the vector can hold before reallocating.

let's read the elements and push them onto the end of a vector. this removes the arbitrary
limit on the number of elements that can be read.
also, instead of using qsort, we will use the stl sort routine, one of the many algorithms
provided by stl. the sort routine is generic, in that it will work on many different types of
containers. the way this is done is by having algorithms deal not with containers directly,
but with iterators.
preview of iterators
i'll go into iterators in detail later, but for now here is enough to get started.
iterators provide a way of specifying a position in a container. an iterator can be
incremented or dereferenced, and two iterators can be compared. there is a special iterator
value called "past-the-end".
you can ask a vector for an iterator that points to the first element with the message
begin. you can get a past-the-end iterator with the message end. the code
vector<int> v;
// add some integers to v
vector::iterator i1 = v.begin();
vector::iterator i2 = v.end();
will create two iterators like this:

operations like sort take two iterators to specify the source range. to get the source
elements, they increment and dereference the first iterator until it is equal to the second
iterator. note that this is a semi-open range: it includes the start but not the end.
two vector iterators compare equal if they refer to the same element of the same vector.
putting this together, here is the new program:
#include <string.h>
#include <algo.h>
#include <vector.h>
#include <stdlib.h>
#include <iostream.h>

main ()
{
vector<int> v; // create an empty vector of integers
int input;
while (cin >> input) // while not end of file
v.push_back (input); // append to vector

// sort takes two random iterators, and sorts the elements between
// them. as is always the case in stl, this includes the value
// referred to by first but not the one referred to by last; indeed,
// this is often the past-the-end value, and is therefore not
// dereferenceable.
sort(v.begin(), v.end());

int n = v.size();
for (int i = 0; i < n; i++)
cout << v[i] << "\n";
}
incidentally, this is much faster than qsort; at least a factor of 20 on the examples i tried.
this is presumably due to the fact that comparisons are done inline.
version 3: iterator adaptors
in addition to iterating through containers, iterators can iterate over streams, either to read
elements or to write them.
an input stream like cin has the right functionality for an input iterator: it provides access
to a sequence of elements. the trouble is, it has the wrong interface for an iterator:
operations that use iterators expect to be able to increment them and dereference them.
stl provides adaptors, types that transform the interface of other types. this is very much
how electrical adaptors work. one very useful adaptor is istream_iterator. this is a
template type (of course!); you parameterize it by the type of object you want to read
from the stream. in this case we want integers, so we would use an
istream_iterator<int>. istream iterators are initialized by giving them a stream, and
thereafter, dereferencing the iterator reads an element from the stream, and incrementing
the iterator has no effect. an istream iterator that is created with the default constructor
has the past-the-end value, as does an iterator whose stream has reached the end of file.

in order to read the elements into the vector from standard input, we will use the stl copy
algorithm; this takes three iterators. the first two specify the source range, and the third
specifies the destination.
the names can get pretty messy, so make good use of typedefs. iterators are actually
parameterized on two types; the second is a distance type, which i believe is really of use
only on operating systems with multiple memory models. here is a typedef for an iterator
that will read from a stream of integers:
typedef istream_iterator<int,ptrdiff_t> istream_iterator_int;
the second argument to the template should default to ptrdiff_t, but most compilers do not
understand default template arguments. some implementations of stl define
istream_iterators with only one parameter, and supply a hard-coded distance type. so
you will have to see whether your compiler understands default template arguments; if it
does, you can declare the iterator type like this:
typedef istream_iterator<int> istream_iterator_int;
so to copy from standard input into a vector, we can do this:
copy (istream_iterator_int (cin), istream_iterator_int (), v.begin());
the first iterator will be incremented and read from until it is equal to the second iterator.
the second iterator is just created with the default constructor; this gives it the past-the-
end value. the first iterator will also have this value when the end of the stream is
reached. therefore the range specified by these two iterators is from the current position
in the input stream to the end of the stream.
there is a bit of a problem with the third iterator, though: if v does not have enough space
to hold all the elements, the iterator will run off the end, and we will dereference a past-
the-end iterator (which will cause a segfault).
what we really want is an iterator that will do insertion rather than overwriting. there is an
adaptor to do this, called back_insert_iterator. this type is parameterized by the
container type you want to insert into.

so input is done like this:


typedef istream_iterator<int,ptrdiff_t> istream_iterator_int;

vector<int> v;
istream_iterator_int start (cin);
istream_iterator_int end;
back_insert_iterator<vector<int> > dest (v);

copy (start, end, dest);


similarly, to print out the values after sorting, we use copy:
copy (v.begin(), v.end(), ostream_iterator<int> (cout, "\n"));
ostream_iterator is another adaptor; it provides output iterator functionality: assigning
to the dereferenced iterator will write the data out. the ostream_iterator constructor
takes two arguments: the stream to use and the separator. it prints the separator between
elements.

putting this all together,


#include <string.h>
#include <algo.h>
#include <vector.h>
#include <stdlib.h>
#include <iostream.h>

main ()
{
vector<int> v;
istream_iterator<int,ptrdiff_t> start (cin);
istream_iterator<int,ptrdiff_t> end;
back_insert_iterator<vector<int> > dest (v);

copy (start, end, dest);


sort(v.begin(), v.end());
copy (v.begin(), v.end(), ostream_iterator<int>(cout, "\n"));
}

discussion
i find the final version of the program the cleanest, because it reflects the way i think of
the computation happening: the vector is copied into memory, sorted, and copied out
again.
in general, in stl, operations are done on containers as a whole, rather than iterating
through the elements of the container explicitly in a loop. one obvious advantage of this
is that it lends itself easily to parallelization or hairy optimizations (e.g., one could be
clever about the order the elements were accessed in to help avoid thrashing).
most of the stl algorithms apply to ranges of elements in a container, rather than to the
container as a whole. while this is obviously more general than having operations always
apply to the entire container, it makes for slightly clumsy syntax. some implementations
of stl (e.g., objectspace), provide supplementary versions of the algorithms for common
cases. for example, stl has an algorithm count that counts the number of times a
particular element appears in a container:
template <class inputiterator, class t, class size>
void count (inputiterator start, inputiterator end, const t& value,
size& n);
to find how many elements have the value 42 in a vector v, you would write:
int n = 0;
count (v.begin(), v.end(), 42, n);
objectspace defines an algorithm os_count that provides a simpler interface:
int n = os_count (v, 42);

philosophy
the standard template library is designed for use with a style of programming called
generic programming. the essential idea behind generic programming is to create
components that can be composed easily without losing any performance. in some sense,
it moves the effort that is done at run-time in object-oriented programming (dynamic
binding) to compile-time, using templates.

stl components
containers
containers are objects that conceptually contain other objects. they use certain basic
properties of the objects (ability to copy, etc.) but otherwise do not depend on the type of
object they contain.
stl containers may contain pointers to objects, though in this case you will need to do a
little extra work.
vectors, lists, deques, sets, multisets, maps, multimaps, queues, stacks, and priority
queues, did i miss any? are all provided.
perhaps more importantly, built-in containers (c arrays) and user-defined containers can
also be used as stl containers; this is generally useful when applying operations to the
containers, e.g., sorting a container. using user-defined types as stl containers can be
accomplished by satisfying the requirements listed in the stl .
if this is not feasible, you can define an adaptor class that changes the interface to satisfy
the requirements.
all the types are "templated", of course, so you can have a vector of ints or windows or a
vector of vector of sets of multimaps of strings to students. sweat, compiler-writers,
sweat!
to give you a brief idea of the containers that are available, here is the hierarchy:

sequences
contiguous blocks of objects; you can insert elements at any point in the sequence, but the
performance will depend on the type of sequence and where you are inserting.
vectors
fast insertion at end, and allow random access.
lists
fast insertion anywhere, but provide only sequential access.
deques
fast insertion at either end, and allow random access. restricted types, such as stack and
queue, are built from these using adaptors.
stacks and queues

provide restricted versions of these types, in which some operations are not allowed.
associative containers
associative containers are a generalization of sequences. sequences are indexed by
integers; associative containers can be indexed by any type.
the most common type to use as a key is a string; you can have a set of strings, or a map
from strings to employees, and so forth.
it is often useful to have other types as keys; for example, if i want to keep track of the
names of all the widgets in an application, i could use a map from widgets to strings.
sets

sets allow you to add and delete elements, query for membership, and iterate through the
set.
multisets

multisets are just like sets, except that you can have several copies of the same element
(these are often called bags).
maps
maps represent a mapping from one type (the key type) to another type (the value type).
you can associate a value with a key, or find the value associated with a key, very
efficiently; you can also iterate through all the keys.
multimaps

multimaps are just like maps except that a key can be associated with several values.
should add other containers: priority queue, bit vector, queue.

examples using containers


here is a program that generates a random permutation of the first n integers, where n is
specified on the command line.
#include <iostream.h>
#include <vector.h>
#include <algo.h>
#include <iterator.h>

main (int argc, char *argv[])


{
int n = atoi (argv[1]); // argument checking removed for clarity

vector<int> v;
for (int i = 0; i < n; i++) // append integers 0 to n-1 to
v
v.push_back (i);

random_shuffle (v.begin(), v.end()); //


shuffle
copy (v.begin(), v.end(), ostream_iterator<int> (cout, "\n")); //
print
}
this program creates an empty vector and fills it with the integers from 0 to n. it then
shuffles the vector and prints it out.
it is quite common to want a sequence of elements with arithmetically increasing values;
common enough that there is an algorithm that does something like this for us. it is called
iota:
template <class forwarditerator, class t>
void iota (forwarditerator first, forwarditerator last, t value);
this function allows us to fill a range of a container with increasing values, starting with
some initial value:
vector<int> a(100); // initial size 100

iota (a.begin(), a.end(), 0);


this call will fill the array a with the values 0, 1, 2...

unfortunately, this is not quite what we wanted -- this overwrites an existing vector,
whereas in our case, we had an empty vector, and we wanted the elements appended to it.
there are two problems here. the first is that the termination condition for the iota
function is specified by an iterator; the loop terminates when the moving iterator becomes
equal to the terminal iterator.
many algorithms in stl come in several flavors, corresponding to different terminating
conditions. for example, generate uses two iterators to specify a range; generate_n
uses one iterator and an integer to specify the range.
the iota function, unfortunately, does not have an iota_n counterpart, but it is very easy
to write:
template <class forwarditerator, class t>
void iota_n (forwarditerator first, int n, t value)
{
for (int i = 0; i < n; i++)
*first++ = value++;
}
in order to append to the vector instead of overwriting its contents, we will use an adaptor
back_inserter:
#include <iostream.h>
#include <vector.h>
#include <algo.h>
#include <iterator.h>

main (int argc, char *argv[])


{
int n = atoi (argv[1]); // argument checking removed for clarity

vector<int> v;
iota_n (v.begin(), 100, back_inserter(v));

random_shuffle (v.begin(), v.end()); //


shuffle
copy (v.begin(), v.end(), ostream_iterator<int> (cout, "\n")); //
print
}
back_inserter is a function that takes a container as an argument, and returns an
iterator. the iterator is defined in such a way that writing a value through it and
incrementing it will cause the value to be appended to the container.
iterators
iterators are like location specifiers for containers or streams of data, in the same way that
an int* can be used as a location specifier for an array of integers, or an ifstream can be
used as a location specifier for a file. stl provides a variety of iterators for its different
collection types and for streams.
input iterators

input iterators provide access to data sources. the source may be an stl container, another
type of container, a stream, a virtual source (such as a set of permutations), etc.
output iterators
output iterators provide access to data sinks: locations to store the results of a
computation. the sink may be an stl container, a user-defined container, a stream, etc.
using input and output iterators
just input and output iterators are enough to do quite a lot, since many operations boil
down to copying objects around. for example, this function copies all the elements of a
container v to standard output. ostream_iterator is an adaptor; it is an output iterator
type. the iterator operations are defined so that in the case below, assigning through the
iterator prints to standard output, with each print followed by a newline.
copy (v.begin(), v.end(), ostream_iterator<int> (cout, "\\n"));
the first two arguments specify the source data: start an iterator that points to the
beginning of the vector v, and keep going until the iterator compares equal with v.end(),
which is called a past-the-end value. almost all stl operations have one or more pairs of
input iterators specifying the data to work with.
the third argument is an adaptor that turns an ostream like cout into an output iterator;
don't worry about the details for now.
a similar operation reads data into a vector (for now, we will assume the vector has
enough space allocated already):
copy (istream_iterator<int> (cin), istream_iterator<int> (), v.begin());
moreover, input and output iterators are necessary to do many things, since we usually
need to specify what data we want to work with, and where to put the result.
forward iterators

a forward iterator allows traversal of the sequence, reading and/or writing each element,
but no backing up. many algorithms request a forward iterator, for example
long *p = new int [1000];
fill (p, p+100, 0);
fill (p+101, p+1000, 0xdeadbeef);
fill's first two arguments specify the range the operation should take place on, and the
third specifies the value to write through the iterator at each position.
bidirectional iterators

bidirectional iterators can be moved forward or backward, and can be used to read or
write the elements of the sequence. moving an iterator from one part of the sequence to
another takes time proportional to the number of elements between the two.
containers and iterators
all the stl containers provide at least bidirectional iterators: lists, sets, maps, and so on can
be traversed forward or backward. some containers provide even more flexible indexing:
random access iterators

random access iterators can jump from any place to any other place in constant time i am
not sure that this is required, and it is certainly allowed to be amortized constant time.
every c pointer type is an stl random iterator for a c array container. if you have a
random-access container, you can perform all sorts of nifty operations on it, such as
mapping over a vector, with or without accumulation, finding and replacing elements
satisfying predicates, partitions, shuffling, and many more. the extent of this library never
ceases to amaze me given that the source code is really quite small. i think that is a
testimony to this kind of generic programming.

algorithms
the stl algorithms are template c++ functions to perform operations on containers. in
order to be able to work with many different types of containers, the algorithms do not
take containers as arguments. instead, they take iterators that specify part or all of a
container. in this way the algorithms can be used to work on entities that are not
containers; for example, the function copy can be used to copy data from standard input
into a vector.
some algorithms require only the capabilities of input iterators, while others require
random access (e.g., to sort).
the algorithms include sorting operations (sort, merge, min, max...), searching operations
(find, count, equal...), mutating operations (transform, replace, fill, rotate, shuffle...), and
generalized numeric operations (accumulate, adjacent difference...).

function objects
function objects are stl's way of representing "executable data". for example, one of the
stl algorithms is for_each. this applies a function to each object in a container. you need
to be able to specify what to do to each object in the container.
overview
function objects are objects on which at least one parenthesis operation (. . .) is
defined. they are used for three main purposes: generating data, testing data (predicates),
and applying operations.
generators
algorithms like generate walk through a range, calling a function object at each step,
and assigning the result of the function to the current element.
[picture]
for example, here is a function that always returns 0:
int zero() { return 0; }
to fill a vector with zeroes, one could use the algorithm generate with the function
object zero:
vector<int> v (100);
generate (v.begin(), v.end(), zero);
of course, it would be nice if our function were a bit more widely useful -- for example,
allowing an arbitrary arithmetic sequence. in order to do this, the function object has to
store some state indicating where in the sequence it is. there are two ways to do this. one
is to use static variables inside a global function, the other is to define a class of function
objects.
[in an aside] there are several problems with using static variables in a function to store
state. there can only be one position remembered in the sequence -- copies of the function
object will all always be positioned at the same point in the sequence. [other problems?]
here is a class iota. it provides an arithmetic sequence, starting with some initial value,
and repeatedly adding an increment to it. the function call operator returns the current
value and moves on to the next element of the sequence. the template is defined with two
types s and t. usually these will be the same, but they might be different, e.g., date and
int. it is usually a good idea to ask yourself if there is some straightforward
generalization of what you are about to do -- if it doesn't make things much more
complicated, it is probably worth it.
template <class s, class t>
class iota
{
s cur;
t inc;
public:
iota (const s& initial, const t& increment)
: cur (initial), inc (increment)
{ }
s operator()() { s tmp (cur); cur += inc; return tmp; }
};

requirements: if a is an instance of the type s, and b is an instance of the type t, the


following expressions must be valid:
s a (b)
a += b
this template class can be used with any types s and t that satisfy the requirements; for
example, if both s and t are int, the requirements are satisfied:
vector<int> v (365);
generate (v.begin(), v.end(), iota<int,int> (0, 1));
cout << v << endl;
it is a bit tedious to have to keep specifying the types of the arguments; you might hope
that the compiler could figure them out from the expressions provided. unfortunately, you
can't create an instance of a template class without providing the types, but you
<em>can</em> use a function to help out, and get the same effect:
template <class s, class t>
iota<s, t> makeiota (const s& s, const t& t)
{
return iota<s, t> (s, t);
}
and now the user code becomes:
vector<int> v (365);
generate (v.begin(), v.end(), makeiota (0, 1));
cout << v << endl;
here, the function object is storing some state between calls; it is what is called a
<em>closure</em> in some languages. anything needed to initialize the data is provided
in the construction of the function object.
predicates
the second type of function object is used to test things; the parenthesis operator will be
defined to return something that can be tested for truth.
find_if uses a function object to test each element of a range, returning an iterator
pointing to the first element that satisfies the test. in this case, the function object takes an
argument, the element of the range, and returns a boolean:
bool greaterthanzero (int i) return i > 0;
this could be used to move to the first strictly positive element of a range:
typedef vector<int>::iterator iterator;
typedef vector<int> vector;
typedef ostream_iterator<int> output;

vector v;
iterator iter = find_if (v.begin(), v.end(), greaterthanzero);
if (iter == v.end())
cout << "no elements greater than zero" << endl;
else
{
cout << "elements starting from first greater than zero: ";
copy (iter, v.end(), output (cout, " "));
}
again, it is often useful to be able to provide state in the predicate object. here is a
predicate that tests true if the element is within a specified range:
class inrange
{
const t& low;
const t& high;
public:
inrange (const t& l, const t& h) : low (l), high (h) { }
bool operator()(const t& t) { return ! (t < l) && t < h; }
};
here we find, and print, all the elements of a vector that fall within a particular range:
typedef vector<int>::iterator iterator;
typedef vector<int> vector;
typedef ostream_iterator<int> output;

vector v (100);
generate (v.begin(), v.end(), rand);

iterator iter (v);


while (iter != v.end())
{
iter = find (v.begin(), v.end(), inrange (0, 10000));
cout << *iter << endl;
}

it is possible to simulate lexical scoping.


there are many pre-defined (templated, of course) function objects that can be used --
many algorithms expect a function as an argument.
example

adaptors
sometimes you have a class that does the right thing, but has the wrong interface for your
purposes. adaptors are classes that sit between you and another class, and translate the
messages you want to send into the messages the other class wants to receive.
for example, the copy function expects an input iterator to get its data from. the istream
class has the right functionality: it acts as a source of data, but it has the wrong interface:
it uses << etc.

there is an adaptor called istream_iterator that provides the interface that copy
expects, translating requests into istream operations.

other adaptors provide backward-moving iterators from forward-moving iterators, and


queues from lists, for example.
adaptors are very useful, but you don't have to understand them to use stl; treat them as
black magic for now.

allocators
i confess i don't really understand stl's allocation model properly yet, so i won't say
anything about this for now. you don't need to know anything about them for now either.

extending stl
examples
iterators

the stl iterator model is somewhat different from most iterators i have seen. most
importantly, it is very flexible in regards to the type of thing iterators are ranging over.
containers are conceptually grouped by the type of access iterators can provide to them,
and iterations on any random access container (for example) is done the same way -- the
object doing the iteration does not know what kind of container it is.
the other important difference is that whereas many iterator mechanisms are mainly
intended for iteration over the entire collection, stl always deals in terms of ranges,
though of course the entire collection is just a particular range.
be careful not to confuse the past-the-end iterator value with the "null" value that other
iterator types often provide to indicate the end of the container. in particular, don't use the
past-the-end iterator to indicate an error; if you want to indicate errors, you should
provide singular iterator values; i will describe these in the section on iterators.

example 2: finding scheduling conflicts


there is just a sketch of the problem and solution here. students are associated with a list
of courses, and courses with a list of timeslots. we want to know which students have
different courses with same timeslot. uses:
• algorithms: copy, find

• iterators: istream_iterator, ostream_iterator

• adaptors: istream_iterator, ostream_iterator

• containers: multiset, set


problem
i have a file of information about students, of the form:
name [course...]
...
and a file of information about courses, of the form:
course [timeslot...]
...
the names, courses and timeslots are arbitrary strings, but for simplicity we will assume
that each token is one word (e.g., we write student names like jak_kirman.
the program must print out the names of students who have collisions in their course
schedules, along with the courses causing the collisions. repetitions in the lists of courses
or lists of timeslots should be ignored.

example 3: stream calculator


there is just a sketch of the problem and solution here. i want to give my program
command-line expressions in reverse polish notation, like a b + to mean (a+b). the
elements of expressions can be constants or filenames. the program should repeatedly
evaluate the expression, replacing any occurrence of a file name with the next number
read from that file.
as an added bonus, the types we define will allow us to combine arbitrary streams of
input with arbitrary operations.
• algorithms: copy, find

• iterators: input_iterator, istream_iterator, ostream_iterator

• functions: binary_function, unary_function

• adaptors: istream_iterator, ostream_iterator

• containers: stack, vector

problem
i want a program that will let me perform arithmetic operations on streams of numbers,
with each stream coming from a different file. so as not to complicate the example with
parsing, i will use reverse polish notation, e.g., 2 cost1 * 3 cost2 * + 5 /. the
calculator has an internal stack. the expression is read left to right; if we find a number,
we push it onto the stack. if we find a name, we read a number from that file and push it
onto the stack. if we find an operator, we apply it, popping elements off the stack as
arguments. the above expression computes ((2 * cost1) + (3 * cost2))/5.
sketch of design
i will have a stack of input_iterators:
template <class t>
typedef input_iterator<t> *input_iterator_p;

template <class t>


typedef stack<vector<input_iterator_p<t> > > input_stack;
as each token is read from the command line, we create an iterator, using the stack as the
source of any arguments. at the end, the stack should have a single iterator, which we can
then copy to the output stream. the only tricky part here is the "dynamic inheritance".
i will have a kind of input_iterator called constant_source, for which

• increment does nothing

• dereference returns the constant


template <class t, class distance> // default distance = ptrdiff_t
class constant_source : public input_iterator<t,distance>
{
private:
const t& value;
bool bad;
public:
friend bool operator==(const number_source<t, distance>& x,
const number_source<t, distance>& y)
{ return x.bad == y.bad; }
number_source() : bad (true) {}
number_source (const t& t) : value (t), bad (false){}
number_source<t,distance>& operator++(int = 0) { return *this; }
const t& operator*() const { return value; }
};
a combiner input iterator is created from two input iterators s1 and s2, and a function
object func of type binary_function<t,t,t>.
increment
increments s1 and s2
dereference
dereferences s1 and s2, applies func and returns the result
template <class t, class distance> // default distance = ptrdiff_t
class combiner : public input_iterator<t,distance>
{
protected:
void read() { ++source1; ++source2; value = func (*source1,
*source2); }
friend bool operator==(const combiner<t, distance>& x,
const combiner<t, distance>& y)
{ return (x.source1 == source1) && (y.source1 == source2); }

combiner() : source1(), source2() {}


combiner (input_iterator<t,distance>& s1,
input_iterator<t,distance>& s2,
binary_function<t,t,t> f) : source1 (s1), source2 (s2),
func (f)
combiner<t,distance>& operator++() { read(); return *this; }
combiner<t,distance>& operator++(int)
{ combiner<t,distance>& tmp = *this; read(); return tmp;
const t& operator*() const { return value; }
};
now, for example, to read pairs from file1 and file2 and print their sums:
main (int argc, char *argv[])
{
combiner<double> adder (istream_iterator<double>(ifstream (argv[1])),
istream_iterator<double>(ifstream (argv[2])),
plus<double>);

copy (adder, combiner<double>(), ostream_iterator<double>(cout));


}

appendices
lambda expressions
suppose we want to apply a function to all the elements of a vector. we can define the
function locally, since it is a type definition. it can take any context it needs in the
constructor, and store it internally.
this is not as elegant as lisp or perl's lexical scoping, but it is better than nothing.
function addoffset(vector<int>& v, int n)
{

// we want to add n to each element of v


struct addn : public unary_function<int>
{ addn(int n) : _n (n) {};
int operator() (const int& k) { return k + n; }
};
transform (v.begin(), v.end(), v.begin(), addn(n));
}

null iterator values


why doesn't stl have null iterator values? stl iterators are supposed to be generalized
pointers, right? that phrase has been bandied about a great deal, but it is very misleading.
stl iterators are generalizations of array pointers, that is, a pointer set to point into an
array, and then incremented or decremented. it does not make sense to talk about such a
pointer having a null value.
in c and c++, null pointers are used to indicate errors, or abnormal conditions. when you
have a c++ iterator type, there is normally only one kind of error value it will return: one
indicating "i fell off the end of the list". it is natural, therefore, for most iterator classes to
use null as the "past-the-end" value. if you find yourself wanting a null stl iterator, you
probably want the past-the-end value.

alice vs humpty const


in "alice through the looking glass", alice meets humpty dumpty, and they have a
discussion during which humpty uses a word to mean something completely different
from its usual meaning. alice protests that that was not what the word meant; words mean
what the dictionary says. humpty says that words mean what he wants them to mean; he
pays them enough.
courtesy of eric anderson and j coleman, here is the section, taken from <a
href="http://www.cs.indiana.edu/metastuff/looking/looking.txt.gz">the text at indiana
university</a>:
`when _i_ use a word,' humpty dumpty said in rather a scornful
tone, `it means just what i choose it to mean -- neither more nor
less.'

`the question is,' said alice, `whether you can make words mean
so many different things.'

`the question is,' said humpty dumpty, `which is to be master -


- that's all.'
alice const is the "dictionary" const, or language definition const, which says that a
member function is constant if and only if the member function does not modify any of
the data members.
humpty const is the "conceptual" const, or design const, which says that the object has
the same appearance to the user after the operation as before, and that it is ok to apply the
operation to objects that must not be modified.
in a string class,
class string
{
private:
char *_data;
mutable int _len;
public:
string (const char *data) : _data (data), _len (-1) { }
void capitalize() { char *p = _data; while (*p) *p = toupper(*p++);
}
int length() const { if (_len == -1) _len = strlen (_data); return
_len; }
};
capitalize is alice const (the value of the pointer doesn't change), but not humpty const --
to the user it seems like a mutating function, and it should not be applied to objects that
are constant.
length is humpty const (the user thinks of it as an operation that does not modify the
string, and it can be applied to constant strings), but not alice const, since _len changes.
the keyword mutable allows you to change a variable so specified in a const member
function.
jak@cs.brown.edu

stl vector:
vector: dynamic array of variables, struct or objects. insert data at the end. 

simple example of storing stl strings in a vector. this example shows three 
methods of accessing the data within the vector: 
#include <iostream>
#include <vector>
#include <string>

using namespace std;

main()
{
vector<string> ss;

ss.push_back("the number is 10");


ss.push_back("the number is 20");
ss.push_back("the number is 30");

cout << "loop by index:" << endl;

int ii;
for(ii=0; ii < ss.size(); ii++)
{
cout << ss[ii] << endl;
}

cout << endl << "constant iterator:" << endl;

vector<string>::const_iterator cii;
for(cii=ss.begin(); cii!=ss.end(); cii++)
{
cout << *cii << endl;
}

cout << endl << "reverse iterator:" << endl;

vector<string>::reverse_iterator rii;
for(rii=ss.rbegin(); rii!=ss.rend(); ++rii)
{
cout << *rii << endl;
}

cout << endl << "sample output:" << endl;

cout << ss.size() << endl;


cout << ss[2] << endl;

swap(ss[0], ss[2]);
cout << ss[2] << endl;
}

compile: g++ examplevector.cpp 
run: ./a.out 

output: 
loop by index:
the number is 10
the number is 20
the number is 30
constant iterator:
the number is 10
the number is 20
the number is 30

reverse iterator:
the number is 30
the number is 20
the number is 10

sample output:
3
the number is 30
the number is 10

two / three / multi dimensioned arrays using vector: 

a two dimensional array is a vector of vectors. the vector contructor can initialize 
the length of the array and set the initial value. 
example of a vector of vectors to represent a two dimensional array: 
#include <iostream>
#include <vector>

using namespace std;

main()
{
// declare size of two dimensional array and initialize.
vector< vector<int> > vi2matrix(3, vector<int>(2,0));

vi2matrix[0][0] = 0;
vi2matrix[0][1] = 1;
vi2matrix[1][0] = 10;
vi2matrix[1][1] = 11;
vi2matrix[2][0] = 20;
vi2matrix[2][1] = 21;

cout << "loop by index:" << endl;

int ii, jj;


for(ii=0; ii < 3; ii++)
{
for(jj=0; jj < 2; jj++)
{
cout << vi2matrix[ii][jj] << endl;
}
}
}

compile: g++ examplevector2.cpp 
run: ./a.out 
loop by index:
0
1
10
11
20
21

a three dimensional vector would be declared as: 
#include <iostream>
#include <vector>

using namespace std;

main()
{
// vector length of 3 initialized to 0
vector<int> vi1matrix(3,0);

// vector length of 4 initialized to hold


another
// vector vi1matrix which has been
initialized to 0
vector< vector<int> > vi2matrix(4, vi1matrix);

// vector of length 5 containing two


dimensional vectors
vector< vector< vector<int> > > vi3matrix(5, vi2matrix);

...

or declare all in one statement: 
#include <iostream>
#include <vector>

using namespace std;

main()
{
vector< vector< vector<int> > > vi3matrix(2, vector< vector<int> >
(3, vector<int>(4,0)) );

for(int kk=0; kk<4; kk++)


{
for(int jj=0; jj<3; jj++)
{
for(int ii=0; ii<2; ii++)
{
cout << vi3matrix[ii][jj][kk] << endl;
}
}
}
}

using an iterator: 
example of iterators used with a two dimensional vector. 
#include <iostream>
#include <vector>

using namespace std;

main()
{
vector< vector<int> > vi2matrix; // declare two dimensional array
vector<int> a, b;
vector< vector<int> >::iterator iter_ii;
vector<int>::iterator iter_jj;

a.push_back(10);
a.push_back(20);
a.push_back(30);
b.push_back(100);
b.push_back(200);
b.push_back(300);

vi2matrix.push_back(a);
vi2matrix.push_back(b);

cout << endl << "using iterator:" << endl;

for(iter_ii=vi2matrix.begin(); iter_ii!=vi2matrix.end(); iter_ii++)


{
for(iter_jj=(*iter_ii).begin(); iter_jj!=(*iter_ii).end();
iter_jj++)
{
cout << *iter_jj << endl;
}
}
}

compile: g++ examplevector2.cpp 
run: ./a.out 
using iterator:
10
20
30
100
200
300

constructor/declaration: 

method/operator description
vector<t> v; vector declaration of data type "t".
vector<t> v(size_type n); declaration of vector containing type "t" and of 
size "n" (quantity).
vector<t> v(size_type n,const t&  declaration of vector containing type "t", of 
t); size "n" (quantity) containing value "t".
declaration: vector(size_type n, const t&
t)

vector<t>  copy of vector of data type "t" and range 
v(begin_iterator,end_iterator); begin_iterator to end_iterator.
declaration: template vector(inputiterator,
inputiterator)

size methods/operators: 

method/operator description
empty() returns bool (true/false). true if empty.
declaration: bool empty() const
size() number of elements of vector.
declaration: size_type size() const
resize(n, t=t()) adjust by adding or deleting elements of vector so that its size 
is "n".
declaration: void resize(n, t = t())
capacity() max number of elements of vector before reallocation.
declaration: size_type capacity() const
reserve(size_t n) max number of elements of vector set to "n" before 
reallocation.
declaration: void reserve(size_t)
max_size() max number of elements of vector possible.
declaration: size_type max_size() const
note: size_type is an unsigned integer. 
other methods/operators: 

method/operator description
erase() erase all elements of vector.
clear() declaration: void clear()
erase(iterator) erase element of vector. returns iterator to 
erase(begin_iterator,end_iterator) next element.
erase element range of vector. returns 
iterator to next element.
declarations: 
• iterator erase(iterator pos) 
iterator erase(iterator first,
iterator last) 

= assign/copy entire contents of one vector 
example: x=y() into another.
declaration: vector& operator=(const
vector&)

< comparison of one vector to another.
declaration: bool operator<(const
vector&, const vector&)

== returns bool. true if every element is 
equal.
declaration: bool operator==(const
vector&, const vector&)

at(index) element of vector. left and right value 
v[index] assignment: v.at(i)=e; and e=v.at(i);
declaration: reference
operator[](size_type n)

front() first element of vector. (left and right value 
v[0] assignment.)
declaration: reference front()
back() last element of vector. (left and right value 
assignment.)
declaration: reference back()
push_back(const t& value) add element to end of vector.
declaration: void push_back(const t&)
pop_back() remove element from end of vector.
declaration: void pop_back()
assign(size_type n,const t& t) assign first n elements a value "t".
assign(begin_iterator,end_iterator) replace data in range defined by iterators.
declaration: 
insert(iterator, const t& t) insert at element "iterator", element of 
value "t".
declaration: iterator insert(iterator
pos, const t& x)

insert(iterator pos, size_type n, const  starting before element "pos", insert first n 
t& x) elements of value "x".
declaration: void insert(iterator pos,
size_type n, const t& x)

insert(iterator pos,  starting before element "pos", insert 
begin_iterator,end_iterator) range begin_iterator to end_iterator.
declaration: void insert(iterator pos,
inputiterator f, inputiterator l)

swap(vector& v2) swap contents of two vectors.
declaration: void swap(vector&)
iterator methods/operators: 
method/operator description
begin() return iterator to first element of vector.
declaration: const_iterator begin() const
end() return iterator to last element of vector.
declaration: const_iterator end() const
rbegin() return iterator to first element of vector (reverse order).
declaration: const_reverse_iterator rbegin() const
rend() return iterator to last element of vector (reverse order).
declaration: const_reverse_iterator rend() const
++ increment iterator.
­­ decrement iterator.
vector links: 
• sgi: vector ­ detail of all vector member functions and operators available. 

• also see boost ptr_vector ­ used to hold vector of pointers. 

stl list:
list: linked list of variables, struct or objects. insert/remove anywhere. 

two examples are given: 
1. the first stl example is for data type int 

2. the second for a list of class instances. 
they are used to show a simple example and a more complex real world 
application. 
1. lets start with a simple example of a program using stl for a linked list: 
// standard template library example

#include <iostream>
#include <list>
using namespace std;

// simple example uses type int

main()
{
list<int> l;
l.push_back(0); // insert a new element at the end
l.push_front(0); // insert a new element at the beginning
l.insert(++l.begin(),2); // insert "2" before position of first
argument
// (place before second argument)
l.push_back(5);
l.push_back(6);

list<int>::iterator i;

for(i=l.begin(); i != l.end(); ++i) cout << *i << " ";


cout << endl;
return 0;
}

compile: g++ example1.cpp 
run: ./a.out 

output: 0 2 0 5 6 

[potential pitfall]: in red hat linux versions 7.x one could omit the "using
namespace std;" statement. use of this statement is good programming practice 
and is required in red hat 8.0. 

[potential pitfall]: red hat 8.0 requires the reference to "#include <iostream>". red 
hat versions 7.x used "#include <iostream.h>". 

2. the stl tutorials and texts seem to give simple examples which do not apply to 
the real world. the following example is for a doubly linked list. since we are using 
a class and we are not using defined built­in c++ types we have included the 
following: 

• to make this example more complete, a copy constructor has been 
included although the compiler will generate a member­wise one 
automatically if needed. this has the same functionality as the assignment 
operator (=). 

• the assignment (=) operator must be specified so that sort routines can 
assign a new order to the members of the list. 

• the "less than" (<) operator must be specified so that sort routines can 
determine if one class instance is "less than" another. 

• the "equals to" (==) operator must be specified so that sort routines can 
determine if one class instance is "equals to" another. 
// standard template library example using a class.

#include <iostream>
#include <list>
using namespace std;

// the list stl template requires overloading operators =, == and <.

class aaa
{
friend ostream &operator<<(ostream &, const aaa &);

public:
int x;
int y;
float z;

aaa();
aaa(const aaa &);
~aaa(){};
aaa &operator=(const aaa &rhs);
int operator==(const aaa &rhs) const;
int operator<(const aaa &rhs) const;
};

aaa::aaa() // constructor
{
x = 0;
y = 0;
z = 0;
}
aaa::aaa(const aaa &copyin) // copy constructor to handle pass by
value.
{
x = copyin.x;
y = copyin.y;
z = copyin.z;
}

ostream &operator<<(ostream &output, const aaa &aaa)


{
output << aaa.x << ' ' << aaa.y << ' ' << aaa.z << endl;
return output;
}

aaa& aaa::operator=(const aaa &rhs)


{
this->x = rhs.x;
this->y = rhs.y;
this->z = rhs.z;
return *this;
}

int aaa::operator==(const aaa &rhs) const


{
if( this->x != rhs.x) return 0;
if( this->y != rhs.y) return 0;
if( this->z != rhs.z) return 0;
return 1;
}

// this function is required for built-in stl list functions like sort
int aaa::operator<(const aaa &rhs) const
{
if( this->x == rhs.x && this->y == rhs.y && this->z < rhs.z) return
1;
if( this->x == rhs.x && this->y < rhs.y) return 1;
if( this->x < rhs.x ) return 1;
return 0;
}

main()
{
list<aaa> l;
aaa ablob ;

ablob.x=7;
ablob.y=2;
ablob.z=4.2355;
l.push_back(ablob); // insert a new element at the end

ablob.x=5;
l.push_back(ablob); // object passed by value. uses default member-
wise
// copy constructor
ablob.z=3.2355;
l.push_back(ablob);
ablob.x=3;
ablob.y=7;
ablob.z=7.2355;
l.push_back(ablob);

list<aaa>::iterator i;

for(i=l.begin(); i != l.end(); ++i) cout << (*i).x << " "; // print
member
cout << endl;
for(i=l.begin(); i != l.end(); ++i) cout << *i << " "; // print all
cout << endl;

cout << "sorted: " << endl;


l.sort();
for(i=l.begin(); i != l.end(); ++i) cout << *i << " "; // print all
cout << endl;

return 0;
}

output: 
7 5 5 3
7 2 4.2355
5 2 4.2355
5 2 3.2355
3 7 7.2355

sorted:
3 7 7.2355
5 2 3.2355
5 2 4.2355
7 2 4.2355

list links: 
• sgi: list ­ detail of all "list" member functions and operators available. 

• boost ptr_list and stl list of pointers ­ yolinux tutorial 

• also see boost ptr_list ­ used to hold list of pointers. 

stl vector vs list function comparison:
function vector list
constructor yes yes
destructor yes yes
empty() yes yes
size() yes yes
resize() yes yes
capacity() yes no
reserve() yes no
max_size() yes yes
erase() yes yes
clear() yes yes
operator= yes yes
operator< yes yes
operator== yes yes
operator[] yes no
at() yes no
front() yes yes
back() yes yes
push_back() yes yes
pop_back() yes yes
assign() yes yes
insert() yes yes
swap() yes yes
push_front() no yes
pop_front() no yes
merge() no yes
remove() no yes
remove_if() no yes
reverse() no yes
sort() no yes
splice() no yes
unique() no yes

links/information:
• gnu string class ­ yolinux tutorial 
• "modest tutorial" 

• technical university vienna tutorial 

• boost pointer container library ­ containter libraries (vectors,lists,maps,...) to 

hold pointers. 

• an old fashioned linked list with pointers (old homework problem) 

• gtk api: 

o singly linked list api 

o doubly linked list api 

software and documentation available from: 

• http://www.sgi.com/tech/stl/ ­ stl home page 

books:
the c++ standard library: a tutorial 
reference 
nicolai m. josuttis 
isbn #0201379260, addison wesley 
longman 
this book is the only book i have seen 
which covers string classes as 
implemented by current linux 
distributions. it also offers a fairly 
complete coverage of the c++ standard 
template library (stl). good reference 
book. 
stl for c++ programmers 
leen ammeraal 
isbn #0 471 97181 2, john wiley & sons 
ltd. 
short book which teaches c++ standard 
template library (stl) by example. not as 
great as a reference but is the best at 
introducing all the concepts necessary to 
grasp stl completely and good if you 
want to learn stl quickly. this book is 
easy to read and follow. 

data structures with c++ using stl 
william ford, willaim topp 
isbn #0130858501, prentice hall 

stl tutorial and reference guide: c++ 
programming with the standard template 
library 
david r. musser, gillmer j. derge, atul 
saini 
isbn #0201379236, addison­wesley 
publications 

the c++ templates: the complete guide. 
david vandevoorde, nicolai josuttis 
isbn #0201734842, addison wesley pub 
co. 
covers complex use of c++ templates. 
c++ how to program 
by harvey m. deitel, paul j. deitel 
isbn #0131857576, prentice hall 
fifth edition. the first edition of this book 
(and professor sheely at uta) taught me 
to program c++. it is complete and 
covers all the nuances of the c++ 
language. it also has good code 
examples. good for both learning and 
reference. 

dr. dobb's journal 
free
subscription 

free subscription to the premier resource 
for professional programmers and 
software developers. multi­language and 
multi­platform with program listings, 
coding tips, design issue discussions 
and algorithms. subscribe here! 

example: boost ptr_list:

#include <boost/ptr_container/ptr_list.hpp>
#include <iostream>

using namespace std;

class abc
{
public:
int i;
float j;
};

main()
{
boost::ptr_list<abc> intlist;
boost::ptr_list<abc>::iterator iterintlist;

abc *a= new abc;


abc *b= new abc;
abc *c= new abc;

a->i = 1;
b->i = 2;
c->i = 3;

intlist.push_back(a);
intlist.push_back(b);
intlist.push_back(c);

for (iterintlist = intlist.begin();


iterintlist != intlist.end();
iterintlist++)
{
cout << iterintlist->i << endl;
}

intlist.clear(); // all pointers held in list are deleted.

compile: g++ testboostptrlist.cpp 
run: ./a.out 
1
2
3
see http://www.boost.org/libs/ptr_container/doc/ptr_list.html 
red hat rpm packages: boost, boost-devel newer linux releases like red hat 
enterprise 5/centos 5 include boost "ptr_list". rhel4 included boost libraries but did 
not include "ptr_list". 

ubuntu installation: apt-get install libboost-dev libboost-doc 

example: stl list of pointers:

// g++ -g teststlptrlist.cpp
#include <iostream>
#include <list>

using namespace std;

class abc
{
public:
int i;
float j;
};

main()
{
list<abc*> intlist;
list<abc*>::iterator iterintlist;

abc *a= new abc;


abc *b= new abc;
abc *c= new abc;

a->i = 1;
b->i = 2;
c->i = 3;

intlist.push_back(a);
intlist.push_back(b);
intlist.push_back(c);

for (iterintlist = intlist.begin();


iterintlist != intlist.end();
iterintlist++)
{
cout << (*iterintlist)->i << endl;
}

// free pointers
for (iterintlist = intlist.begin();
iterintlist != intlist.end();
iterintlist++)
{
delete *iterintlist;
}

intlist.clear(); // list is deleted.

this example shows how one must delete each pointer individually. 
for more information on stl list, see the yolinux.com stl vector and stl list tutorial 

gdb: pointers and memory investigation
you can test the above programs and investigate their respective memory clean­
up in gdb. 

see the yolinux.com gdb tutorial. 

using gdb: 

• compile with debugging enabled: g++ -g -o teststlptrlist
teststlptrlist.cpp 

• start gdb: gdb teststlptrlist 

• show listing with line numbers: list 
• set break point: break 30 

• run program till break point: run 

• find memory location of variable in gdb: print &(c->i) 
(gdb) p &(c->i)
$4 = (int *) 0x503050

• dereference memory location: p (*0x503050) 
(gdb) p (*0x503050)
$5 = 3

• dereference memory location after memory is freed: p (*0x503050) 
(gdb) p (*0x503050)
$7 = 0

using rhel5. note older systems may give you a nonsense value. 

books:
the c++ standard library: a tutorial 
reference 
nicolai m. josuttis 
isbn #0201379260, addison wesley 
longman 
this book is the only book i have seen 
which covers string classes as 
implemented by current linux distributions. 
it also offers a fairly complete coverage of 
the c++ standard template library (stl). 
good reference book. 

stl for c++ programmers 
leen ammeraal 
isbn #0 471 97181 2, john wiley & sons ltd. 
short book which teaches c++ standard 
template library (stl) by example. not as 
great as a reference but is the best at 
introducing all the concepts necessary to 
grasp stl completely and good if you want 
to learn stl quickly. this book is easy to 
read and follow. 

data structures with c++ using stl 
william ford, willaim topp 
isbn #0130858501, prentice hall 

stl tutorial and reference guide: c++ 
programming with the standard template 
library 
david r. musser, gillmer j. derge, atul saini 
isbn #0201379236, addison­wesley 
publications 
the c++ templates: the complete guide. 
david vandevoorde, nicolai josuttis 
isbn #0201734842, addison wesley pub co. 
covers complex use of c++ templates. 

c++ how to program 
by harvey m. deitel, paul j. deitel 
isbn #0131857576, prentice hall 
fifth edition. the first edition of this book 
(and professor sheely at uta) taught me to 
program c++. it is complete and covers all 
the nuances of the c++ language. it also 
has good code examples. good for both 
learning and reference. 
dr. dobb's journal 
free subscription to the premier resource 
for professional programmers and software 
developers. multi­language and multi­
platform with program listings, coding tips, 
design issue discussions and algorithms. 
subscribe here! 

c++ gui framework toolkits:
cross platform (linux, ms/windows, irix, solaris (gnome will be standard on solaris 
10)) 

• gtk.org: gtk+ (cross platform) 

o yolinux tutorial: gtk+ tips and tricks ­ building a gui using gtk+ 

o linux magazine: gui building with gtk+ 

o glade home page ­ gtk+ gui builder. 

o glade tutorial ­ by ishan chattopadhyaya 

• trolltech.com: qt ­ used to develop kde (ms/windows, mac, linux) 

o ics.com: graphpak, quics table and kd tools (qt widgets) for qt. 

• wxwindows.org ­ supports all platforms and many ide's 

• fox toolkit ­ linux, windows, most unix 

• glut: toolkit and gui written in opengl. cross platform ms/win32 and x11 

o api spec 

o tutorial 

• mozilla xpt ­ can also use xml to define gui layout 

• openoffice.org: gsl 
• borland.com: clx 

• winehq.com ­ winelib ­ libraries to support windows api (linux and bsd only. 

not truly cross platform but a good porting tool) 

• gnustep: gorm (objective c) 

gui framework links: 

• ibm developer site: gui components and vendors ­ slightly out of date 

• list of cross platform gui libraries 

• another list of cross platform gui libraries 

c++ graphic componets and widgets:
• sl.com ­ sherrill ­ lubinski sl­gms 

dynamic graphic gui components and controls for real time interfaces and 
displays. common ".m1" file graphic framework for c++ and java. graphic 
sources include visio, bitmaps and dxf. supports pan, zoom, drill­down and 
hyperlink capability. supports input as well as displays. 

• kinesix.com: sammi ­ similar to sl­gms but not as good. 

• genlogic.com: glg ­ dynamic, data driven visual components. 

• int.com 

• ilog.com: views ­ diagraming and data graphing capabilities. 

c++ web server cgi toolkits:
• gnu c++ cgi 

programming web server cgi programs with c++ and the gnu cgicc library ­ 

yolinux tutorial 

• cgilib ­ red hat 

• yacgi: yet another c/c++ library for cgi programming 

• c++ cgi for sql/oracle 

software testing tools:
• cppunit c++ port of ibm's java junit test framework. test report output is in 

xml or text. 

• cxxtest ­ c++ test framework 

• unit++ ­ testing library and framework 

c/c++ development environment for linux:
the following tools will provide the infrastructure for a c++ on linux development 
environment: 
(eclipse ide, scm and the build tools are cross platform and can be duplicated on 
ms/windows and other unix environemnts) 

• ide (integrated development environment): eclipse 
download http://eclipse.org/downloads/ ­ i.e. eclipse-sdk-3.1.1-linux-gtk-
x86_64.tar.gz 
eclipse also requires the java installation. see yolinux java download/installation 

install eclipse: 

o for all on system: 

 mv eclipse-sdk-3.1.1-linux-gtk-x86_64.tar.gz /opt 

 tar xzf eclipse-sdk-3.1.1-linux-gtk-x86_64.tar.gz 

this installs eclipse under /opt/eclipse 
or 
o for yourself only: 

 download to your home directory. 

 tar xzf eclipse-sdk-3.1.1-linux-gtk-x86_64.tar.gz 

this installs eclipse under /home/your-user-id/eclipse 
be sure to include the following eclipse plug­ins: 

o cdt: c/c++ development plug­in for eclipse ­ [cdt manual] 

install cdt plug­in: 

 install from web: in eclipse select "help" from the menu bar + 
"software updates" + "find and install" + "search for new 
features to install" + "next" + "new remote site" to add an 
update site with the url: 
http://download.eclipse.org/tools/cdt/releases/eclips
e3.1 
or 

 download and install "tar.gz" file: 
http://download.eclipse.org/ 

 download appropriate tar bundle for your platform: i.e. 
org.eclipse.cdt-3.0.0-linux.x86_64.tar.gz 
to the parent of the eclipse directory: i.e. /opt 
 tar xzf org.eclipse.cdt-3.0.0-
linux.x86_64.tar.gz 
(to view contents of tar file: tar tzf
org.eclipse.cdt-3.0.0-linux.x86_64.tar.gz) 

verify installation: "help" + "about eclipse sdk" + "plug­in details". 
"c/c++ development tools" should be listed. 
note that cdt is not platform independant. you must download and 
install the plug­in compiled for your platform. eclipse "help" menu 
will include tutorials on cdt after plug­in installation. also see "help" 
+ "welcome" + select "cdt tutorials". 
o subclipse: subversion plug­in for eclipse 

installation: 

 download site.0.9.36.zip to eclipse directory: 
/opt/eclipse 

 unzip file (may require installation of rpm package unzip): 
unzip site.0.9.36.zip 

 start eclipse ide: /opt/eclipse/eclipse & 

 in eclipse select: "help" (from menu bar) + "software 
updates" + "find and install" (wait a minute or so for it to 
respond. no joke, on slow systems expect to wait over 3 
min.) + "search for new features to install" + "next" + "new 
local site". 
browse to: /opt/eclipse/update/ + select "ok" 

 select the box next to "eclipse/update" + "next" + select the "i 
accept the terms ..." + "next" + features to install: select 
"subclipse 0.9.36" + "finish" + "install all" + "yes" to restart 
eclipse. 

 select "window" from the menu bar + "open perspective", 
select "other...", select "svn repository exploring", select "ok" 
buttons on top right of eclipse window can change back and forth 
from the ide to subversion browsing, or select "window" from the 
menu bar + "open perspective" + "other" + "svn repository 
exploring" and then click "ok". 
to add a new svn repository: right click in "svn repository" exploring 
pane + right click "new", "repository location". in the "add svn 
repository" window enter in the "url:" space under "location" the svn 
location + select "finish". 

o subversive: another subversion plug­in for eclipse. includes more 

details for advanced subversion users. displays lots of version info. 
annoying if you want a clean simple interface. 

o ehep: hex file viewer plug­in 

o vi plug-in ­ for those who love vi editing and cursor manipulation key 

bindings. 

o prc-eclipse ­ palm os development plug­in 

o cca: c source code security analyzer plug­in 

[potential pitfall]: if eclipse is installed in /opt/eclipse/ for system wide 
use, you may want to start eclipse with the following command: 
eclipse -data /home/user1/workspace 

[potential pitfall]: when downloading eclipse and eclipse plug­ins, look at 
the readme files (eclipse/readme/readme_eclipse.html) to see if you 
have a matching gtk+ release. if the version of eclipse and plug­ins are too 
new for the version of gtk+ on your system then eclipse may not display 
properly. for older versions of linux, you may have to install older versions 
of eclipse and older plug­ins. i.e. the latest version of eclipse (3.1.1) on the 
older red hat linux 8.0 will not operate properly. eclipse 3.1.1 requires gtk 
2.2.1 while red hat 8.0 uses gtk 2.0. 

[potential pitfall]: don't mix 32 bit java with 64 bit (amd64/em64t) eclipse. 
choose all 32 or all 64 bit for eclipse environment. 
error in ~/workspace/.metadata/.log 
!session 2005-10-31 00:19:28.817 -----------------------------------------------
eclipse.buildid=m20050929-0840
java.version=1.4.2_09
java.vendor=sun microsystems inc.
bootloader constants: os=linux, arch=x86_64, ws=gtk, nl=en_us
command-line arguments: -os linux -ws gtk -arch x86_64

!entry org.eclipse.osgi 2005-10-31 00:19:29.787


!message application error
!stack 1
java.lang.unsatisfiedlinkerror:
/opt/eclipse/configuration/org.eclipse.osgi/bundles/24/1/.cp/libswt-pi-gtk-3139.so
...xxxxxxxxxxx...: cannot open shared object file:
such file or directory
at java.lang.classloader$nativelibrary.load(native method)
at java.lang.classloader.loadlibrary0(classloader.java:1586)
at java.lang.classloader.loadlibrary(classloader.java:1495)
at java.lang.runtime.loadlibrary0(runtime.java:788)
at java.lang.system.loadlibrary(system.java:834)
at org.eclipse.swt.internal.library.loadlibrary(library.java:123)
at org.eclipse.swt.internal.gtk.os.(os.java:19)
at org.eclipse.swt.internal.converter.wcstombcs(converter.java:63)
at org.eclipse.swt.internal.converter.wcstombcs(converter.java:54)
at org.eclipse.swt.widgets.display.(display.java:122)
at org.eclipse.ui.internal.workbench.createdisplay(workbench.java:381)
at org.eclipse.ui.platformui.createdisplay(platformui.java:155)
at
org.eclipse.ui.internal.ide.ideapplication.createdisplay(ideapplication.java:128)
at org.eclipse.ui.internal.ide.ideapplication.run(ideapplication.java:79)
at
org.eclipse.core.internal.runtime.platformactivator$1.run(platformactivator.java:2
at
org.eclipse.core.runtime.adaptor.eclipsestarter.run(eclipsestarter.java:376)
at
org.eclipse.core.runtime.adaptor.eclipsestarter.run(eclipsestarter.java:163)
at sun.reflect.nativemethodaccessorimpl.invoke0(native method)
at
sun.reflect.nativemethodaccessorimpl.invoke(nativemethodaccessorimpl.java:39)
at
sun.reflect.delegatingmethodaccessorimpl.invoke(delegatingmethodaccessorimpl.java:
at java.lang.reflect.method.invoke(method.java:324)
at org.eclipse.core.launcher.main.invokeframework(main.java:334)
at org.eclipse.core.launcher.main.basicrun(main.java:278)
at org.eclipse.core.launcher.main.run(main.java:973)
at org.eclipse.core.launcher.main.main(main.java:948)

installing the rpm jdk-1_5_0_05-linux-amd64.rpm instead of the i586 
version of java to run with the x86_64 version of eclipse fixes this problem. 
notes: 
o help/welcome screen is default upon start­up and gives an 
introduction and tutorials on eclipse . you can later return to this 
menu: "help" + "welcome". 

o i could not find any way to enter gdb debugger commands. the only 
input accepted is through the gui. while it offers similar capability to 
ms/vc++, hard core debugging is best left to ddd. 

• alternate c/c++ ide: i can also recomend the anjuta ide for c/c++ 
development. solid, simple, intuitive, bug free ide for c/c++ development 
on linux. search/indexing, edit, compile and debug. 
packages: 

o yum: yum install anjuta 

o rpms available from dag wieers: anjuta. 

o ubuntu/debian: apt-get install anjuta (requires: anjuta-common,


libgtk2.0-dev libgtkmm2.0-dev libgnome2-dev libgnomemm2.0-
dev devhelp-books glade-2 glade-gnome-2 cvs automake
autogen indent ctags devhelp gnome-devel libtool) 

• scm (software configuration management): 

o subversion cm server and trac bug tracking server ­ version control ­ 

subversion is a cvs follow­on with new features. operates much like 
old cvs. 

 yolinux subversion user tutorial 

o ibm rational clearcase: 

 clearcase client installation 

 clearcase server installation 

 clearcase commands 

o yolinux cm tools links 


• bug / issue tracking: 

o trac bug tracking server ­ installation, configuration and integration with 

subversion. 

o see yolinux bug tracking systems links 

• build systems: 

o gnu gmake/make: gnu make is a build system based on the original 

unix "make" build system but with more features. install rpm 
package: make 
gnu make manual 

o scons: newer python based, cross platform build system. great for 

cross platform development (i.e. ms/windows and linux/unix) 

• automated nightly/continuous build and reporting systems: 

o yolinux tutorial - cabie installation/configuration: multi­platform build 

system for subversion, cvs or perforce 

o yolinux.com: list of continuous and nightly build / test systems 

• file compare tools: 

o gtkdiff: has diff3 and merge features. written with gtk+. after gtkdiff­

0.8.0, gnome required. 

o fldiff: graphical file and directory diff. (cross platform) 

o kdiff3: graphical directory and file diff, merge and edit. kde3/qt 

based. supports drag and drop. comes with s.u.s.e. distro. (cross 
platform) ms/windows download available. 

 difference: kdiff file1 file2 

 difference: kdiff file1 file2 file3 

 difference of two files: kdiff directory1/file directory2 

 difference: kdiff directory1 directory2 

 merge: kdiff directory1 directory2 -o dest-directory 


 merge: kdiff file1 file2 -m 

 merge: kdiff file1 file2 -o output-file 

o kompare: ships with kde sdk. [manual] 

o meld: compare, edit and merge. 

o mgdiff: [download] motif­based graphical file difference browser and 

merge. comes with s.u.s.e. distro. 

o tkdiff: [download] 

o gvim and gvimdiff 

o dirdiff: directory difference viewer. 

• compiler: install rpm packages for gnu compiler gcc, gcc-c++, binutils


(linker), glibc, glibc-devel, gdb 

note: 

• also see javadoc like tagged comments the auto document generation facility: doxygen ­ 
yolinux tutorial 

• the above environment is cross platform and can be used on ms/windows 
as well. 

• eclipse (and plug­ins) can be substituted by vi or emacs, ddd or gdb and 
raw svn commands. 

coding for cross platform deployment with gcc/g++:
the gcc/g++ compiler is compiled with a number of defined preprocessor 
variables. the list of defined variables compiled into gcc/g++ can be viewed by 
issuing the command: g++ -dumpspecs 

the defined preprocessor variables can then be used to handle platform 
dependencies. 
platform  variable:  variable:  variable:  architecture 
platform
variable name unix posix _posix_source variable
fedora core 3  linux * *
linux __gnu_linux__
linux
red hat 8 linux * * *
__gnu_linux__
linux
suse 9.2 linux *
__gnu_linux__
sun 
sparc __arch64
solaris/sparc
mips
sgi irix/mips sgi * _sgi_source
host_mips
cygwin  __cygwin32
* * _x86_
win/intel­32 win32
example c/c++ source code 1: 
#ifdef sparc
...
#endif
#ifdef linux
...
#endif
#ifdef __cygwin32
...
#endif
...
#if defined(linux) || defined(sparc)
...
#endif
...

example c/c++ source code 2: 
#ifdef sgi
#ifdef sgi
return fn_sgi();
#include file_sgi.h
#elif defined(__cygwin32)
#elif defined(sparc)
return fn_win();
#include file_sparc.h
#elif defined(linux)
#elif defined(linux)
return fn_linux(); or  #include file_linux.h
#else
#else
struct time ts;
#error unknown os type
return fn_time();
#endif
#endif
...
...

note use of the "#error" for error processing. 

also see yolinux gnu makefile cross platform tips 

notes:
• link error solution: 
if you get a similar error classname::classname[not-in-charge] 
the solution is to change the order of the libraries. 
i.e. if the following compile results in an error: 
g++ source-file.cpp -lxxx -lyyy -lzzz -l../xxx -l../yyy -l../zzz 
the solution is to change the order of the libraries: 
g++ source-file.cpp -lyyy -lzzz -lxxx -l../xxx -l../yyy -l../zzz 
the order of the library paths is irrellevant (­l). 

• c++ link error: "undefined reference to `vtable for classname-goes-


here`" 
my fix was to define a destructor. the virtual base class and destructor 
required the derived class to define a destructor. 

• architecture independent data types and pointers: 

o avoid 32/64 bit cross platform issues by using pointer type: 
intptr_t 
use include file stdint.h. ms/windows uses int_ptr. 

o avoid integer word size issues by using defined types in stdint.h 

o libraries are typically found in /usr/lib and /lib. on systems which 
mix 32 and 64 bit libraries look for /usr/lib64 and /lib64. 

links:
• c++ references: 

o gnu c++ library user's guide 

o sun's c++ 5.0 compiler programming guide ­ very good coverage of 

advanced features 

o c++ programming language tutorials 

o ucsd.edu: standard c 

o cplusplus.com 

o informit.com: c++ reference guide 

• c++ library references: 
o gnu c++ iostream library 

o stl ­ home (sgi) 

o c++ data structures source code 

o list of c++ libraries 

o c++ library reference 

o c++ standard library - a tutorial and reference ­ nicolai josuttis 

• c++ api's and toolkits: 

o c++ motif toolkit 

o object oriented programming ­ c++ gui and c++ frameworks 

o ace c++ framework ­ schmidt 

o c++ boost libraries 

• c++ links and info: 

o c/c++ users journal ­ magazine articles 

o freshsources.com 

o c++ pitfalls ­ by cay s. horstmann 

o programmersheaven.com: c++ links 

o us chapter of the association of c/c++ users 

o the comp.lang.c++ faq 

o coding standards 

o c-c++ beautifier how-to 

o cpp-home.com 

o csourcesearch.net ­ c/c++ database of searchable source code 
books:
c++ how to program 
by harvey m. deitel, paul j. deitel 
isbn #0131857576, prentice hall 
fifth edition. the first edition of this book 
(and professor sheely at uta) taught me to 
program c++. it is complete and covers all 
the nuances of the c++ language. it also 
has good code examples. good for both 
learning and reference. 

exceptional c++: 47 engineering puzzles, 
programming problems and solutions 
by herb sutter 
isbn #0201615622, addison­wesley 
professional 
advanced c++ features and stl. 

more exceptional c++ 
by herb sutter 
isbn #020170434x, addison­wesley 
professional 

effective c++: 50 specific ways to improve 
your programs and design (2nd edition) 
by scott meyers 
isbn #0201924889, addison­wesley 
professional 
more effective c++: 35 new ways to 
improve your programs and designs 
by scott meyers 
isbn #020163371x, addison­wesley 
professional 

dr. dobb's journal 
free subscription to the premier resource 
for professional programmers and software 
developers. multi­language and multi­
platform with program listings, coding tips, 
design issue discussions and algorithms. 
subscribe here! 
comparison of fortran and c/c++ datatypes:

fortran
c/c++

integer*2
short int

integer
long int or int

integer iabc(2,3)
int iabc[3][2];

logical
long int or int

logical*1
bool
(c++, one byte)

real
float

real*8
double

complex
struct{float r, i;}

double complex
struct{double dr, di;}

character*6 abc
char abc[6];

parameter
#define parameter value
note: 
• order of multi dimensional arrays in c/c++ is the 
opposite of fortran. 

• it is best not to re­dimension multi dimensional 
arrays within a function. pass array size "n" and 
declare array as x[n][]; 

linking fortran and c subroutines:

note: the entry point names for some fortran compilers 
have an underscore appended to the name. this is also 
true for common block/structure names as shown above. 
fortran
c

call subra( ... )
subra_( ... )

the f77 comiler flags "-fno-underscore" and "-fno-
second-underscore" will alter the default naming in the 
object code and thus affect linking. one may view the 
object file with the command nm (i.e.: nm file.o). 

note: the case in fortran is not preserved and is 
represented in lower case in the object file. the g77 
compiler option "-fsource-case-lower" is default. gnu 
g77 fortran can be case sensitive with the compile option 
"-fsource-case-preserve". 

note: when debugging with gdb, the fortran subroutines 
must be referenced with names as they appear in the 
symbol table. this is the same as the "c" representation. 
thus when setting a break point at the fortran subroutine 
subra(), issue the comand "break subra_". 
man pages: 

• nm ­ list symbols from object files 

• g77/f77 

function arguments:

all arguments in fortran are passed by reference and not 
by value. thus c must pass fortran arguments as a 
pointer. 
fortran
c

call subra( i, x)
subra_( int *i, float *x)

character variables: 

• linux and gnu compilers: when passing character 
strings, the length must follow as separate 
arguments which are passed by value. 
fortran
c

call subra( string_a, string_b)
len_a = strlen(string_a); 
len_b = strlen(string_a); 
subra_( char *string_a, len_a, char *string_b, len_b)

• i have also seen the passing of a data structure 
containing two elements, the character string and 
an integer storing the length. this is common with 
databases such as oracle. 

• classic at&t unix: 
when passing character strings, the length must 
be appended as separate arguments which are 
passed by value. 
fortran
c

call subra( string_a, string_b)
subra_( char *string_a, char *string_b, len_a, len_b)

alternate returns:

fortran
c
call sub(a,b,c,*,*)
return 1
end
int sub_(int *a,int *b,int *c)
{
return(1)
}

goto(1, 2, 3), sub()


if( sub() ) goto errs;

note: when using alternate returns to turn on/off an 
intlevel by returning a 1/0 you must use a fortran wrapper 
to perform this function on the csc norwich mainframe. 
this is because the c compiler is old. 
•  buffering output: your machine may be configured 
where the output buffering defaults for fortran and c may 
be configured the same or differently. c output may be 
buffered buffered while fortran may not. if so, execute a 
function initialization task to unbuffer c otherwise print 
statements for c will be output out of order and at the 
end. 
#include <stdio.h>

void ersetb(void){
setbuf(stdout,null); /* set output to
unbuffered */
}

common blocks:
fortran common block and global c/c++ extern structs of 
same name are equivalent. never use un­named 
common blocks! reference variables in same order, same 
type and with the same name for both c and fortran. 
character data is aligned on word boundaries. 
fortran:
double precision x
integer a, b, c
common/abc/ x, a, b, c

c:
extern struct{
double x;
int a, b, c;
} abc_;

c++:
extern "c" {
extern struct{
double x;
int a, b, c;
} abc_;
}

note: use of extern requires that the common block be 
referenced first by fortran. if referenced first by c then 
drop the extern. the extern statement states that it is 
trying to reference memory which has already been set 
aside elsewhere. 

[potential pitfall]: byte alignment can be a source of data 
corruption if memory boundaries between fortran and 
c/c++ are different. each language may also align 
structure data differently. one must preserver the 
alignment of memory between the c/c++ "struct" and 
fortran "common block" by ordering the variables in the 
exact same order and exactly matching the size of each 
variable. it is best to order the variables from the largest 
word size down to the smallest. start with "double" 
followed by "float" and "int". bool and byte aligned data 
should be listed last. 
fortran:
integer a, b, c
double precision d, e, f
logical*1 flag
common/abc/ a, d, flag, b, e

c:
extern struct{
int a;
double d;
bool flag;
int b;
double e;
} abc_;

c++:
extern "c" {
extern struct{
int a;
double d;
bool flag;
int b;
double e;
} abc_;
}

using gdb to examine alignment: 

• set a breakpoint in the c/c++ section of code which 
has visibility to the struct. 

• while in a c/c++ section of code: 
(gdb) print &abc_.b 
$3 = (int *) 0x5013e8 

• set a breakpoint in the fortran section of code 
which has visibility to the common block. 

• while in a fortran section of code: 
(gdb) print &b 
$2 = (ptr to -> ( integer )) 0x5013e8 
this will print the hex memory address of the variable as 
c/c++ and fortran view the variable. the hex address 
should be the same for both. if not, the data will be 
passed improperly. 
forcing alignment with compiler arguments: mixing 
intel fortran compiler and gnu g++: use the following 
compiler flags to force a common memory alignment and 
padding to achieve a common double word alignment of 
variables: 

• intel fortran: -warn alignments -align all


-align rec8byte 

• intel c/c++: -zp8 

• gnu g++: -wpadded -wpacked -malign-double


-mpreferred-stack-boundary=8 
example warning: warning: padding struct size
to alignment boundary 

• gnu g77: -malign-double 

example:

fortran program calling a c function: 
testf.f
testc.c
program test

integer ii, jj, kk


common/ijk/ ii, jj, kk
real*8 ff
character*32 cc

ii = 2
jj = 3
kk = 4
ff = 9.0567
cc = 'example of a character string'

write(6,10) ii, ff
10 format('ii= ',i2,' ff= ',f10.4)

call abc(ii)

write(6,20) ii
20 format('ii= ',i2)

write(6,30) ii, jj, kk


call doubleijk(cc)

write(6,30) ii, jj, kk


30 format('ii= ',i2,' jj= ', i2, ' kk= ', i2)

write(6, 40) cc
40 format(a32)

stop
end

subroutine abc(jj)
jj = jj * 2
return
end
#include <stdio.h>

extern struct
{
int ii, jj, kk;
} ijk_;

int doubleijk_(char *cc, int ll)


{
printf("from doubleijk: %s\n",cc);

ijk_.ii *=2;
ijk_.jj *=2;
ijk_.kk *=2;

return(1);
}

compile: 

• f77 -c testf.f 

• gcc -c testc.c 

• f77 -o test testf.o testc.o 

note: if there is use of c/c++ standard libraries you may 
have to include the following linking arguments: -lc or 
-lstdc++ 

run: ./test 
ii= 2 ff= 9.0567
ii= 4
ii= 4 jj= 3 kk= 4
from doubleijk: example of a character string
ii= 8 jj= 6 kk= 8
example of a character string
c++ calling a fortran function: 
testc.cpp
testf.f
#include <iostream>

using namespace std;

extern"c" {
void fortfunc_(int *ii, float *ff);
}

main()
{

int ii=5;
float ff=5.5;

fortfunc_(&ii, &ff);

return 0;
}
subroutine fortfunc(ii,ff)
integer ii
real*4 ff

write(6,100) ii, ff
100 format('ii=',i2,' ff=',f6.3)

return
end

compile: 

• f77 -c testf.f 

• g++ -c testc.cpp 

• g++ -o test testf.o testc.o -lg2c 

run: ./test 
ii= 5 ff= 5.500

vax extensions:

the gnu fortran compilers have only ported a small subset 
of vax extensions. the vast majority will require a clever 
re­write. 
vax variable format expressions:
vax expression
ported to gnu fortran
integer*4 ivar(3), nfor
nfor=3
...

write(6,100) (ivar(i), i=1,nfor)


100 format(<nfor>i3)
do 20 i=1,nfor
write(6,200) ivar(i)
200 format(i3,$) !! supress carriage return
20 continue

write(6,400) !! write carriage return


400 format()

vax intrinsic functions:
many are not supported in gnu fortran and require the 
creation of an equivalent library written in "c". 
return type
vax fortran intrinsic function
argument type

integer*4
nint(arg)
jnint(arg)
real*4

integer*4
idnint(arg)
jidnint(arg)
real*8

integer*2
inint(arg)
real*4

integer*8
knint(arg)
real*4

integer*2
iidnnt(arg)
real*8

integer*8
kidnnt(arg)
real*8

integer*2
iiqnnt(arg)
real*16

integer*4
iqnint(arg)
jiqnnt(arg)
real*16

integer*8
kiqnnt(arg)
real*16

example: inint.c 
short int inint_(float *rval)
{
if(*rval < 0.0)
return (*rval - 0.5);
else
return (*rval + 0.5);
}

• gcc -c inint.c 

• gcc -c idnint.c 

• ... 

• create library: ar -cvq libvax.a inint.o


idnint.o ... 

c++:
when mixing fortran with c++, name mangling must be 
prevented. 
#ifdef _cplusplus
extern"c" {
#endif
.
.
place declarations here
.
.
#ifdef __cplusplus
}
#endif

the intel fortran compiler:

the intel fortran compiler has become a popular fortran 


compiler for linux as it supports many of the fortran 
extensions supported by the compaq (old dec vax) and 
sgi fortran compilers. (i.e. "structure", "record", "external", 
"encode", "decode", "find", "virtual", "pointer", "union", 
various intr8insic functions, i/o directives, ...) it links with 
object code generated by gnu gcc/g++ compilers as well 
as their own intel c/c++ compilers. 

installation: (as root) 

• mkdir /opt/intel 

• cd /opt/intel 

• move intel fortram compiler tar ball to this 
directory. 

• tar xzf 1_fc_c_9.0.033_ia32.tar.gz 

• cd 1_fc_c_9.0.033/ 

• ./install.sh 
1 : install 
2 : provide name of an existing license file. 
license file path : 
/path-to-license-file/commercial_for_1_f2wc-
5fdzv87r.lic 
(file copied to /opt/intel/licenses) 
1 (typical installation) 
type "accept" to agree to license terms. 
accept default location: /opt/intel/fc/9.0 
accept default location: /opt/intel/idb/9.0 
x : installation done 

compiler use and user configurations: 

file: $home/.bashrc 
..
...

#
# intel compiler
#

# flexlm license server


export intel_license_file=28518@license-server

# support for intel fortran compiler


if [ -f /opt/intel/fc/9.0/bin/ifortvars.sh ];
then
source /opt/intel/fc/9.0/bin/ifortvars.sh
fi

# support for intel c/c++ compiler


if [ -f /opt/intel/cc/9.0/bin/iccvars.sh ];
then
source /opt/intel/cc/9.0/bin/iccvars.sh
fi

# support for intel debugger


if [ -f /opt/intel/cc/9.0/bin/idbvars.sh ];
then
source /opt/intel/cc/9.0/bin/idbvars.sh
fi

...
...

export ld_library_path
export path

file: makefile (snipet) 
f77=/opt/intel/fc/9.0/bin/ifort
f77flags= -extend_source -fpp -f77rtl -intconstant
-ftz -pad-source -sox \
-lowercase -warn alignments -cxxlibgcc
cxx=g++
cppflags=-wpadded -wpacked
ldflags=-l/opt/intel/fc/9.0/lib -lifport -lifcore
-limf -wabi -wcast-align
debug=-g

objs=file1.o file2.o

cpp-exe: $(objs)
$(cc) $(ldflags) -o name-of-exe $(objs)

.cpp.o:
$(cxx) -c $(debug) $(cppflags) $<

.f.o:
$(f77) -c $(debug) $(f77flags) $<

intel compiler directives: 
directive
description

­extend_source
length of line in source file allows for greater than 72 
characters.

­vax
vax fortran runtime behavior. changes read behavior. i 
never use this.

­f77rtl
fortran 77 runtime behavior.

­fpp
run preprocessor. i.e. handles #define and #ifdef
macros.

­intconstant
use fortran 77 semantics to determine the kind of 
parameter for integer constants.

­ftz
flushes denormal results to zero.
­pad­source
specifies that fixed­form source records shorter than the 
statement field width should be padded with spacs (on 
the right) to the end of the field.

­lowercase
all function names are represented as lower case 
symbols.

­sox
store compiler options and version in the executable.

­warn alignments
warning if common block records require padding for 
alignment.

­align all
will get rid of warning: "because of common, the
alignment of object is inconsistent with its type
[variable-name]
this requires a matching alignment for all code which links 
with this, c, c++ or fortan.

use gnu g++ or intel c++ compiler to compile and link with 
main(): 
g++ -o name-of-exe main_prog.cpp file1.o file2.o -l
/opt/intel/fc/9.0/lib -lifport -lifcore -limf -wabi
-wcast-align 

using ddd as a front­end for the intel debugger: 
ddd --debugger "/opt/intel/idb/9.0/bin/idb
-gdb" exe-file 

[potential pitfall]: i found that i could not install the intel 
fortran compiler from an nfs mounted drive. i had to copy 
the intel installation files to a local drive and install from 
there. 

links:
• mixed language programming using c++ and fortran 77 

• fortran gl api: (sgi gl library emulation for linux) 

o ygl: written in x11 (2d) and opengl (3d) for c 

and fortran 

o repgl 

books:

"introduction to programming with fortran" 
with coverage of fortran 90, 95, 2003 and 77 
by ian chivers, jane sleightholme 
springer; 1st edition, isbn# 1846280532 

"fortran 90 for scientists and engineers" 
by brian hahn 
butterworth­heinemann, isbn# 0340600349 
"introduction to fortran 90 for engineers and scientists" 
by larry r. nyhoff, sanford leestma 
prentice hall; 1st edition, isbn# 0135052157 

dr. dobb's journal 
free subscription to the premier resource for professional 
programmers and software developers. multi­language 
and multi­platform with program listings, coding tips, 
design issue discussions and algorithms. subscribe here! 
free
subscription 

return to 
http://yolinux.co
m for more linux 
links, information 
and tutorials 
return to yolinux
tutorial index 
feedback form 
copyright © 2001, 
2005, 2006 by greg  
ippolito 

yolinux tutorial ­ software 
development on linux
programming linux applications

this tutorial covers 
the tools available 
for programming 
languages 
supported by linux. 
java programmers, 
also see the yolinux
java on linux tutorial. 

c++ programmers, 
also see: yolinux c++
on linux tutorial. 

contents: 
• # 
compile
rs 

• # 
develop
ment
tools 

• # ide:
integrat
ed
develop
ment
environ
ment 

• # 
memory
debuggi
ng tools

• # 
softwar
e
design 

• # cm:
change
/
configur
ation
manage
ment 

• # build
systems

• # 
autocon

• # 
nightly /
contino
us build
and test
systems

• # bug /
change
tracking

• # 
develop
ment
libraries

• # 
softwar
e install
/ update
systems
• # linux
softwar
e
develop
ment
notes 

• # links 

• # books

return to http://yolinux.com for more linux links, 
information and tutorials 
return to yolinux tutorial index 
feedback form 
copyright © 2000, 2001, 2002, 2003, 2004, 2005, 2006 by 
greg ippolito 

You might also like