C Programming Column
by Al Stevens


Listing One
#include <iostream.h>
int main()
{
    int* ip = 0;    // null pointer
    // ...
    int& ir = *ip;  // refers to nonexisting int
    cout << ir;     // error! dereferences nonexisting int
    return 0;
}


Listing Two
#include <iostream.h>
int main()
{
    int* ip = new int;  // allocate heap int
    int& ir = *ip;      // reference to heap int
    ir = 123;
    // ...
    delete ip;          // destroy heap int
    cout << ir;         // error: dereference destroyed heap int
    return 0;
}


Listing Three
#include <iostream.h>
struct foo {
    struct bar {
        int ifb[10];
    } foobar[2];
};
void dofoo(foo*);
int main()
{
    foo f = {{{9,8,7,6,5,4,3,2,1,0},{0,1,2,3,4,5,6,7,8,9}}};
   dofoo(&f);
    return 0;
}
void dofoo(foo* fp)
{
    for (int i = 0; i < 2; i++) {
        for (int j = 0; j < 10; j++)    {
            // reference to int dereferenced by complex notation
            int& ir = fp->foobar[i].ifb[j];
            // use the reference for less code clutter
            ir += 20;
            cout << ir << ' ';
            ir -= 10;
            cout << ir << ' ';
        }
    }
}

Listing Four
#include <iostream.h>
class Date {
    int day, month, year;
public:
    Date(int d, int m, int y) : day(d), month(m), year(y)
        { }
    friend int operator-(const Date& d1, const Date& d2);
};
int operator-(const Date& d1, const Date& d2)
{
    int diff;
    // ... overloaded - code here
    return diff;
}
int main()
{
    Date dt1(6,24,1940);
    Date dt2(11,17,1941);
    cout << (dt1-dt2);
    return 0;
}


Listing Five
#include <iostream.h>
#include <string.h>
class foo {
    int ix;
    int& ry;
    char* pt;
public:
    foo(const char* t, int x, int& y);
    virtual ~foo();
    friend ostream& operator<<(ostream& os, const foo& f);
    foo& operator=(const foo&);
};
foo::foo(const char* t, int x, int& y) : ix(x), ry(y)
{
    pt = new char[strlen(t)+1]; 
    strcpy(pt, t);
}
foo::~foo()
{
    delete [] pt;
}
foo& foo::operator=(const foo& fr)
{
    if (&fr != this)    {
        ix = fr.ix;
        delete [] pt;
        pt = new char[strlen(fr.pt)+1]; 
        strcpy(pt, fr.pt);
        // --- hack the assignment of the reference member
        char* pc1 = (char*) &ix + sizeof(int);
        char* pc2 = (char*) &fr.ix + sizeof(int);
        memmove(pc1, pc2, sizeof(void*));
    }
    return *this;
}
ostream& operator<<(ostream& os, const foo& f)
{
    os << f.pt << ' ' << f.ix << ' ' << f.ry << '\n';
    return os;
}
int main()
{
    int x(123), y(456);
    foo bar1("Hello", 11, x);
    foo bar2("Dolly", 22, y);

    cout << bar1;
    cout << bar2;

    bar2 = bar1;    // use overloaded assignment
    cout << bar2;
    return 0;
}


Listing Six
#include <iostream.h>
#include <string.h>
class Foo {
    char* m_ps;
    union {
        int& m_rny; // incorrect C++, but compiles
        void* m_vp;
    };
    int m_nz;
    friend ostream& operator<<(ostream& os, Foo& foo);
public:
    Foo(const char* ps, int& y, int z);
    ~Foo();
    Foo& operator=(Foo& foo);
};
Foo::Foo(const char* ps, int& y, int z) : m_rny(y), m_nz(z)
{
    m_ps = new char[strlen(ps)+1];
    strcpy(m_ps, ps);
}
Foo::~Foo()
{
    delete [] m_ps;
}
Foo& Foo::operator=(Foo& foo)
{
    if (&foo != this)   {
        delete [] m_ps;
        m_ps = new char[strlen(foo.m_ps)+1];
        strcpy(m_ps, foo.m_ps);
        m_nz = foo.m_nz;
        // --- fake the reference assignment with a union
        m_vp = foo.m_vp;
    }
    return *this;
}
ostream& operator<<(ostream& os, Foo& foo)
{
    os << foo.m_ps << ' ' << foo.m_rny << ' ' << foo.m_nz;
    return os;
}
int main()
{
    int y2(2), y3(3);
    Foo foo1("One:",y2,3);
    cout << foo1 << '\n';
    Foo foo2("Two:",y3,4);
    cout << foo2 << '\n';
    foo1 = foo2;
    cout << foo1 << '\n';
    return 0;
}


Listing Seven
#include <iostream.h>
#include <string.h>
class Foo {
    char* m_ps;
    int& m_rny;
    int m_nz;
    friend ostream& operator<<(ostream& os, Foo& foo);
public:
    Foo(const char* ps, int& y, int z);
    ~Foo();
    Foo& operator=(Foo& foo);
};
Foo::Foo(const char* ps, int& y, int z) : m_rny(y), m_nz(z)
{
    m_ps = new char[strlen(ps)+1];
    strcpy(m_ps, ps);
}
Foo::~Foo()
{
    delete [] m_ps;
}
Foo& Foo::operator=(Foo& foo)
{
    if (&foo != this)   {
        delete [] m_ps;
        // --- imitate default assignment
        memmove(this, &foo, sizeof(Foo));
        m_ps = new char[strlen(foo.m_ps)+1];
        strcpy(m_ps, foo.m_ps);
        m_nz = foo.m_nz;
    }
    return *this;
}
ostream& operator<<(ostream& os, Foo& foo)
{
    os << foo.m_ps << ' ' << foo.m_rny << ' ' << foo.m_nz;
    return os;
}
int main()
{
    int y2(2), y3(3);
    Foo foo1("One:",y2,3);
    cout << foo1 << '\n';
    Foo foo2("Two:",y3,4);
    cout << foo2 << '\n';
    foo1 = foo2;
    cout << foo1 << '\n';
    return 0;
}
5


