Notes week of Dec 1

Sample programs

We did some vector and string processing on Monday (first four programs below) and then explored how to use a tally vector on Wednesday (the freq and bellcurve progras).

countfunc.cpp

//countfunc.cpp
#include <iostream>
using namespace std;

// Function declarations (aka prototypes)
//   parameters in the parentheses
//   return type is to the left
//   void = doesn't return a value
void print_countdown_from(int n);
int factorial_of(int n);

int main()
{
    const int NUM = 10;
    print_countdown_from(NUM);    // function call (call site)
    cout << "Ready?" << endl;
    cout << "Factorial of " << NUM << " is " << factorial_of(NUM) << endl;
    // above: function call embedded within a cout
    return 0;
}

// Definition looks just like the prototype, but
// curly braces instead of semi-colon.
void print_countdown_from(int n)
{
    // do something here
    cout << "Counting down!!!!!" << endl;
    for(int i = n; i > 0; i--)
    {
        cout << i << endl;
    }
}

int factorial_of(int n)
{
    // do something here
    cout << "Calculating factorial!!!!" << endl;

    // example: 5*4*3*2*1

    // Here is the loop definition:

    int result = 1;  // accumulator variable
    for(int i = n; i > 0; i--)  // countdown; i is counter variable
    {
        result *= i;
    }
    return result;

    // Here is the recursive definition:

    // if(n == 1) return 1;
    // else return n * factorial_of(n-1); // recursive!

    // factorial_of(5)
    // 5 * factorial_of(4)
    // 5 * 4 * factorial_of(3)
    // 5 * 4 * 3 * factorial_of(2)
    // 5 * 4 * 3 * 2 * factorial_of(1)
    // 5 * 4 * 3 * 2 * 1
    // 20 * 3 * 2 * 1
    // 60 * 2 * 1
    // 120 * 1
    // 120
}

vecfunc.cpp

// vecfunc.cpp
#include <iostream>
#include <vector>
#include <string>
using namespace std;

// Prototype
void print_roster(vector<string> roster);
int how_many_long_names(vector<string> list);

int main()
{
    vector<string> names;
    names.push_back("alice");
    names.push_back("robert");
    names.push_back("christophe");
    names.push_back("dee");
    names.push_back("evelyn");
    names.push_back("frank");
    names.push_back("george");

    print_roster(names);        // call

    cout << "There are " << how_many_long_names(names)
         << " long names!" << endl;
}

void print_roster(vector<string> roster)
{
    cout << "printing roster..." << endl;
    for(int i = 0; i < roster.size(); i++)
    {
        cout << i+1 << ". " << roster.at(i) << endl;
    }
    return; // Can still specify return, but no value because it's void
}

// Suppose a "long" name is MORE than 5 characters.
int how_many_long_names(vector<string> list)
{
    int count = 0;
    for(int i = 0; i < list.size(); i++)
    {
        if( list.at(i).size() > 5 )
        {
            //cout << "LONG: " << list.at(i) << endl;
            count++;
        }
    }
    return count;
}

arrayvsvec.cpp

#include <iostream>
#include <vector>
using namespace std;
int main()
{
    // Vector with two integers
    vector<int> v;
    v.push_back(99);
    v.push_back(42);

    // Array with two integers
    int a[2] = { 99, 42 };

    cout << "Access array out of bounds:" << endl;
    cout << a[2] << endl;       // probably some arbitrary integer
                                // that could leak sensitive information!

    cout << "Access vector out of bounds:" << endl;
    cout << v.at(2) << endl;    // controlled termination

    return 0;
}

nulchar.cpp

// nulchar.cpp
#include <iostream>
#include <cstring>
using namespace std;
int main()
{
    char s3[] = "I like pizza\0and hamburgers.";
    cout << "BEFORE: " << strlen(s3) << " chars" << endl;
    cout << s3 << endl;

    s3[12] = '!';

    cout << "AFTER: " << strlen(s3) << " chars" << endl;
    cout << s3 << endl;

    return 0;
}

freq.cpp

#include <iostream>
#include <vector>
#include <string>
#include <cctype>
#include <iomanip>
using namespace std;

int main()
{
    const int ALPHABET_SIZE = 26;

    cout << "Enter a sentence, and press enter:" << endl;
    string sentence;
    getline(cin, sentence);

    // I believe this will automatically set each entry to zero.
    // If not, we'll need to do that ourselves, in a loop.
    vector<int> tally(ALPHABET_SIZE);

    for(int i = 0; i < sentence.length(); i++)
    {
        if( islower(sentence.at(i)) ) { // Only process lower-case
            cout << sentence.at(i) << '*';
            // Convert a-z into 0-25.
            int position = sentence.at(i) - 'a';
            // Increase the count at that position.
            tally.at(position)++;
        }
    }
    cout << endl;

    // Print the tally
    for(int i = 0; i < ALPHABET_SIZE; i++) {
        if(i%5 == 0) {
            cout << endl;
        }
        char letter = 'a' + i;
        cout << letter << ":" << setw(5) << tally.at(i) << "      ";
    }
    cout << endl;
    return 0;
}

bellcurve.cpp

// bell curve you get for probability of the sum of two dice
#include <iostream>
#include <vector>
#include <ctime>
#include <cstdlib>
#include <iomanip>
using namespace std;
int main()
{
    const int NUM_ROLLS = 50000000;
    srand(time(NULL)); // Initialize PRNG

    // We have to add or subtract 2 when converting from
    // the sum of dice to a position in the tally vector.
    //  0  1  2  3  4  5  6  7  8  9 10 <- vector indices
    //  2  3  4  5  6  7  8  9 10 11 12 <- possible sums

    vector<int> tally(11);

    cout << "Rolling a pair of dice, " << NUM_ROLLS << " times." << endl;
    for(int i = 0; i < NUM_ROLLS; i++)
    {
        int d1 = (rand()%6) + 1;         // Roll a number 1-6
        int d2 = (rand()%6) + 1;         // Roll a number 1-6
        int sum = d1 + d2;
        int position = sum - 2;
        tally.at(position)++;
    }

    // Print out the tally
    for(int i = 0; i < tally.size(); i++)
    {
        int sum = i + 2;
        cout << setw(2) << sum << ": "
             << setw(6) << tally.at(i) << "  ";
        // bar graph
        int num_stars = tally.at(i) / (NUM_ROLLS / 250);
        for(int j = 0; j < num_stars; j++)
        {
            cout << '*';
        }
        cout << endl;
    }
    return 0;
}

On readings

What’s the real difference between an array and a vector?

A vector carries its size along with its elements, so it’s always available.

An array also has a limited size, but it’s not stored along with the elements so you have to pass around the size separately. This can be error-prone.

With a vector, the .at(i) function is checked – is i within the size of the array? (See the arrayvsvec.cpp program, above.)

C strings vs C++ strings

The string data type we’ve been using was introduced in C++, but not in the original, “core” C language. So now there are two ways to represent strings, and two different sets of functions on them.

// C-style string is a "pointer" to a (sequence of) character(s)
const char* s1 = "Hello";
string s2 = "World";

// In both cases, the string is terminated by a NUL character, '\0'
string s3 = "I like pizza\0and hamburgers.";
cout << s3

See the nulchar.cpp program for an example.

Functions on C-style strings

We access the C-style functions by including the cstring library:

#include <cstring>

This includes these, and others:

  • strlen – calculates the length of the string (up to the first null character.)

  • strcmp – string comparison – alphabetic order. Returns == 0 if strings are the same, or < 0 if first comes before second in alphabet, or > 0 for opposite.

  • strchr – searches for position of a character within a string.