C Programming Column by Al Stevens Listing One #include 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 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 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 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 #include 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 #include 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 #include 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