|
1
|
- Instructor: Brian M. Dennis
- Teaching Assistants:
- Tom Lechner, Bin Lin, Rachel Goldsborough
- http://www.cs.northwestern.edu/~bmd/cs211/
|
|
2
|
- 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.
|
|
3
|
- C/C++
- User defined datatype
- Collections
- Typed fields
- Heterogeneous
- Accessed by named slots
- Unordered
- Scheme
- Really no analog
- No user defined datatypes
- Vectors indexed by integer
- Can fake it with lists/vectors + procedures
|
|
4
|
- // 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;
- };
|
|
5
|
- // 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;
- }
|
|
6
|
- // 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;
- }
|
|
7
|
- // 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;
- |
|
|
8
|
- // 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;
- }
- }
|
|
9
|
- int slugger(MLBPlayer* hitter,
- MLBPlayer* pitcher) {
- if (!(rand() % 4)) {
- return HOMER;
- } else {
- return -1;
- }
- }
|
|
10
|
- 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;
- }
- }
|
|
11
|
- // 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*);
- };
|
|
12
|
- 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);
- }
|
|
13
|
- // Another user defined type
- const int MAX_NEIGHBORS = 1024;
- struct GraphNode {
- int unique_id;
- GraphNode neighbors[MAX_NEIGHBORS];
- };
|
|
14
|
- // 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];
- };
|
|
15
|
- #ifndef _INT_LIST_H_
- #define _INT_LIST_H_
- // An oldie by goodie
- struct IntListCell;
- typedef IntListCell* IntList;
- struct IntListCell {
- int value;
- IntList tail;
- };
- #endif
|
|
16
|
- #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;
- }
|
|
17
|
- Initialization
- Not guaranteed
- Done by hand
- Packaging datatypes & behavior
- Reuse / extension
|
|
18
|
- Takeaway
- Structs
- User define datatypes
- Collection of typed, named slots
- Instances first class
- Function pointers
- Structs are lame
- Reading
- 6.1 – 6.4 (structs)
- 4.9 (function pointers)
- 5.11 (multidimensional arrays)
- Appendix C
|