CS 211:
Introduction to Computer Programming II
Instructor: Brian M. Dennis
Teaching Assistants:
Tom Lechner, Bin Lin, Rachel Goldsborough
http://www.cs.northwestern.edu/~bmd/cs211/

Data Abstraction
SICP Chapter 2 intro
Thus, whereas our focus in chapter 1 was on building abstractions by combining procedures to form compound procedures, we turn in this chapter to another key aspect of any programming language: the means it provides for building abstractions by combining data objects to form compound data.
Why do we want compound data in a programming language? For the same reasons that we want compound procedures: to elevate the conceptual level at which we can design our programs, to increase the modularity of our designs, and to enhance the expressive power of our language. Just as the ability to define procedures enables us to deal with processes at a higher conceptual level than that of the primitive operations of the language, the ability to construct compound data objects enables us to deal with data at a higher conceptual level than that of the primitive data objects of the language.

Structs
C/C++
User defined datatype
Collections
Typed fields
Heterogeneous
Accessed by named slots
Unordered
Conceptually
Scheme
Really no analog
No user defined datatypes
Vectors indexed by integer
Can fake it with lists/vectors + procedures
Takes discipline

Basics of Structs
// An example of declaring
// a new user defined type
enum Hit { SINGLE = 0, DOUBLE, TRIPLE, HOMER };
struct MLBPlayer {
char* name;
char* team;
int at_bats;
int walks;
int hits[4];
float batting_average;
bool hits_lefty;
};

Basics of Structs
// An example of declaring instances of our
// new user defined type
int main(int argc, char* argv[]) {
MLBPlayer arod = {
"Alex Rodriguez", "Texas Rangers",
0, 0, {0, 0, 0, 0}, 0.0f, false
};
return 0;
}

Basics of Structs
// An example of declaring instances of our
// new user defined type, and accessing fields
int main(int argc, char* argv[]) {
// Stuff elided…
MLBPlayer bbonds;
bbonds.name = "Barry Bonds";
bbonds.team = "SF Giants";
bbonds.hits_lefty = true;
return 0;
}

Basics of Structs
// A constructor function for our datatype
MLBPlayer make_player(char* name, char* team) {
MLBPlayer temp_player;
int cnt = strlen(name) + 1;
temp_player.name = new char[cnt];
// temp_player.name = (char*)malloc(cnt);
strcpy(temp_player.name, name);
cnt = strlen(team) + 1;
temp_player.team = new char[cnt];
strcpy(temp_player.team, team);
// Initialize the rest of the player
return temp_player;
|

Basics of Structs
// You can have arrays of players
// You can have pointers to players
int main(int argc, char* argv[]) {
// Stuff elided…
MLBPlayer frank_thomas;
// An array of players
MLBPlayer cubs[25];
cubs[20].name = "Henry Rodriguez";
// A pointer to a player;
MLBPlayer* bmd_wishes = &frank_thomas;
for (int i = 0; i < 4; i++) {
bmd_wishes->hits[i] = 0;
}
}

Function Pointers
int slugger(MLBPlayer* hitter,
    MLBPlayer* pitcher) {
if (!(rand() % 4)) {
return HOMER;
} else {
return -1;
}
}

Function Pointers
int leadoff(MLBPlayer* hitter,
    MLBPlayer* pitcher) {
int val = rand() % 24;
switch (val) {
case 0:
case 1:
case 2:
return SINGLE;
case 3:
case 4:
return DOUBLE;
case 5:
return TRIPLE;
case 6:
return HOMER;
default:
return -1;
}
}

Function Pointers
// An example of declaring
// a new user defined type
enum Hit { SINGLE = 0, DOUBLE, TRIPLE, HOMER };
struct MLBPlayer {
char* name;
char* team;
int at_bats;
int walks;
int hits[4]
float batting_average;
bool hits_lefty;
int (*hit_func)(MLBPlayer*, MLBPlayer*);
};

Function Pointers
MLBPlayer pedro =
make_player("Pedro Martinez", "Boston Red Sox");
bbonds.hit_func = slugger;
bmd_wishes->hit_func = leadoff;
int at_bat(MPlayer* hitter, MPlayer* pitcher) {
hitter->hit_func(hitter, pitcher);
}

Basics of Structs
// Another user defined type
const int MAX_NEIGHBORS = 1024;
struct GraphNode {
int unique_id;
GraphNode neighbors[MAX_NEIGHBORS];
};

Basics of Structs
// Another user defined type
// Fixed up to deal with recursive type
const int MAX_NEIGHBORS = 1024;
struct GraphNode {
int unique_id;
GraphNode* neighbors[MAX_NEIGHBORS];
};

Basics of Structs
#ifndef _INT_LIST_H_
#define _INT_LIST_H_
// An oldie by goodie
struct IntListCell;
typedef IntListCell* IntList;
struct IntListCell {
int value;
IntList tail;
};
#endif

Basics of Structs
#include <iostream>
#include <cstring>
#include "IntList.h"
using namespace std;
int main(int argc, char* argv[]) {
// Build up a list of integers
IntList head = 0;
for (int j = 1; j < argc; j++) {
IntList new_head = new IntListCell;
new_head->value = strlen(argv[j])
new_head->tail = head;
head = new_head;
}
return 0;
}

Issues with structs
Initialization
Not guaranteed
Done by hand
Packaging datatypes & behavior
Connecting
Reuse / extension
Salaried players

That’s a Wrap
Takeaway
Structs
User define datatypes
Collection of typed, named slots
Instances first class
Function pointers
First class
Structs are lame
Reading
6.1 – 6.4 (structs)
4.9 (function pointers)
5.11 (multidimensional arrays)
Appendix C
If you need it