CSE 333 Lecture 6 - data structures

Similar documents
CSE 333 Lecture 6 - data structures

CSE 333 Lecture 5 - data structures & modules

Data Structures and Modules

Systems Programming and Computer Architecture ( )

CSci 4061 Introduction to Operating Systems. Programs in C/Unix

CSE 333 Lecture 7 - final C details

Exercise Session 2 Systems Programming and Computer Architecture

CSE 374 Programming Concepts & Tools

Kurt Schmidt. October 30, 2018

Exercise Session 2 Simon Gerber

CSE 374 Programming Concepts & Tools

Midterm Exam Nov 8th, COMS W3157 Advanced Programming Columbia University Fall Instructor: Jae Woo Lee.

CSE 333 Lecture 9 - intro to C++

CSE 333 Midterm Exam 7/22/12

Recitation 2/18/2012

CSE 303, Winter 2006, Final Examination 16 March Please do not turn the page until everyone is ready.

CSE 333 Lecture 2 - arrays, memory, pointers

CS 326 Operating Systems C Programming. Greg Benson Department of Computer Science University of San Francisco

Final C Details. CSE 333 Autumn 2018

Final C Details. CSE 333 Winter Teaching Assistants: Alexey Beall Renshu Gu Harshita Neti David Porter Forrest Timour Soumya Vasisht

CS61C Machine Structures. Lecture 3 Introduction to the C Programming Language. 1/23/2006 John Wawrzynek. www-inst.eecs.berkeley.

Deep C. Multifile projects Getting it running Data types Typecasting Memory management Pointers. CS-343 Operating Systems

Lecture 12 CSE July Today we ll cover the things that you still don t know that you need to know in order to do the assignment.

CSE 333 Midterm Exam 7/29/13

Hello, World! in C. Johann Myrkraverk Oskarsson October 23, The Quintessential Example Program 1. I Printing Text 2. II The Main Function 3

Intermediate Programming, Spring 2017*

CSE 333 Midterm Exam Nov. 3, 2017 Sample Solution

Reviewing gcc, make, gdb, and Linux Editors 1

Arrays and Memory Management

CSE 374 Final Exam 3/15/17 Sample Solution. Question 1. (8 points) Suppose we have the following two statements in a C program:

CSE 374 Final Exam 3/15/17. Name UW ID#

2 Compiling a C program

CS 220: Introduction to Parallel Computing. Beginning C. Lecture 2

Starting to Program in C++ (Basics & I/O)

Outline. COMP 2718: Software Development Tools: gcc and make. C and Java 3/28/16

CSE 333 Interlude - make and build tools

CSE 333 Midterm Exam July 24, Name UW ID#

Programs. Function main. C Refresher. CSCI 4061 Introduction to Operating Systems

cs3157: another C lecture (mon-21-feb-2005) C pre-processor (3).

CSE 333 Midterm Exam 7/25/16. Name UW ID#

Number Review. Lecture #3 More C intro, C Strings, Arrays, & Malloc Variables. Clarification about counting down

QUIZ. What are 3 differences between C and C++ const variables?

CSE 333. Lecture 9 - intro to C++ Hal Perkins Department of Computer Science & Engineering University of Washington

Final C Details, Build Tools

Intermediate Programming, Spring 2017*

CS 110 Computer Architecture. Lecture 2: Introduction to C, Part I. Instructor: Sören Schwertfeger.

Computer Science 2500 Computer Organization Rensselaer Polytechnic Institute Spring Topic Notes: C and Unix Overview

CSCI-243 Exam 1 Review February 22, 2015 Presented by the RIT Computer Science Community

HW1 due Monday by 9:30am Assignment online, submission details to come

CMPT 300. Operating Systems. Brief Intro to UNIX and C

CS3157: Advanced Programming. Outline

CSE 333 Autumn 2014 Midterm Key

Final CSE 131B Spring 2004

CSE 333. Lecture 11 - constructor insanity. Hal Perkins Paul G. Allen School of Computer Science & Engineering University of Washington

PRINCIPLES OF OPERATING SYSTEMS

Computer Science 322 Operating Systems Mount Holyoke College Spring Topic Notes: C and Unix Overview

Recitation: Cache Lab & C

Embedded Software TI2726 B. 3. C tools. Koen Langendoen. Embedded Software Group

High-performance computing and programming Intro to C on Unix/Linux. Uppsala universitet

COSC 2P91. Introduction Part Deux. Week 1b. Brock University. Brock University (Week 1b) Introduction Part Deux 1 / 14

Programming. Lists, Stacks, Queues

CSE 333. Lecture 4 - malloc, free, struct, typedef. Hal Perkins Paul G. Allen School of Computer Science & Engineering University of Washington

Lab 5 Pointers and Arrays

CSE 333 SECTION 3. POSIX I/O Functions

C / C++ Coding Rules

CSCI-243 Exam 2 Review February 22, 2015 Presented by the RIT Computer Science Community

CSE 333 SECTION 3. POSIX I/O Functions

LAB #8. GDB can do four main kinds of things (plus other things in support of these) to help you catch bugs in the act:

LAB #8. Last Survey, I promise!!! Please fill out this really quick survey about paired programming and information about your declared major and CS.

377 Student Guide to C++

CSE 333 Lecture 3 - arrays, memory, pointers

CSE 333 Midterm Exam Sample Solution 7/29/13

ch = argv[i][++j]; /* why does ++j but j++ does not? */

Two s Complement Review. Two s Complement Review. Agenda. Agenda 6/21/2011

CS61C : Machine Structures

Tutorial 1 C Tutorial: Pointers, Strings, Exec

Week 5, continued. This is CS50. Harvard University. Fall Cheng Gong

Lab 8. Follow along with your TA as they demo GDB. Make sure you understand all of the commands, how and when to use them.

Agenda. Peer Instruction Question 1. Peer Instruction Answer 1. Peer Instruction Question 2 6/22/2011

CSE 333 Midterm Exam 7/25/16 Sample Solution. Question 1. (10 points) Preprocessor. Suppose we have the following two files:

Slide Set 9. for ENCM 335 in Fall Steve Norman, PhD, PEng

CSE 333 Midterm Exam July 24, 2017 Sample Solution

C Review. MaxMSP Developers Workshop Summer 2009 CNMAT

CS61C Machine Structures. Lecture 4 C Pointers and Arrays. 1/25/2006 John Wawrzynek. www-inst.eecs.berkeley.edu/~cs61c/

Lecture 14 Notes. Brent Edmunds

Introduction to Supercomputing

CS61, Fall 2012 Section 2 Notes

CSE au Midterm Exam Nov. 2, 2018 Sample Solution

Chapter 11 Introduction to Programming in C

CSE 303, Autumn 2006, Final Examination 12 December 2006

EL2310 Scientific Programming

CSE 333 Lecture smart pointers

CSE 333 Midterm Exam 5/9/14 Sample Solution

Review: C Strings. A string in C is just an array of characters. Lecture #4 C Strings, Arrays, & Malloc

CSE 333 Midterm Exam Sample Solution 7/28/14

QUIZ. Source:

Agenda. CS 61C: Great Ideas in Computer Architecture. Lecture 2: Numbers & C Language 8/29/17. Recap: Binary Number Conversion

CS 61C: Great Ideas in Computer Architecture. Lecture 2: Numbers & C Language. Krste Asanović & Randy Katz

Computer Programming. The greatest gift you can give another is the purity of your attention. Richard Moss

Final assignment: Hash map

Transcription:

CSE 333 Lecture 6 - data structures Hal Perkins Department of Computer Science & Engineering University of Washington

Administrivia Exercises: - ex5 is out: clean up the code from section yesterday, split into separate files, fix bugs More towards the end of the hour - no more exercises due until end of week after HW1 HW: - HW1 due very soon; get going NOW if you haven t yet

Today s topics: - implementing data structures in C - multi-file C programs - brief intro to the C preprocessor

Let s build a simple linked list You ve seen a linked list in CSE143 - each node in a linked list contains: some element as its payload a pointer to the next node in the linked list - the last node in the list contains a NULL pointer (or some other indication that it is the last node) element Z element Y element X head

Linked list node Let s represent a linked list node with a struct - and, for now, assume each element is an int #include <stdio.h> int element; Node; n1 element 1 next int main(int argc, char **argv) { Node n1, n2; n2.element = 2; n2.next = NULL; n1.element = 1; n2.next = &n2; n2 element next 2 NULL manual_list.c

PushOntoList push_list.c #include <stdio.h> #include <stdlib.h> #include <assert.h> int element; Node; Node *Push(Node *head, int e) { Node *n = (Node *) malloc(sizeof(node)); assert(n!= NULL); // crashes if false n->element = e; n->next = head; (main) list NULL return n; int main(int argc, char **argv) { Node *list = NULL; list = Push(list, 1); list = Push(list, 2);

PushOntoList push_list.c #include <stdio.h> #include <stdlib.h> #include <assert.h> int element; Node; Node *Push(Node *head, int e) { Node *n = (Node *) malloc(sizeof(node)); assert(n!= NULL); // crashes if false n->element = e; n->next = head; (main) list NULL return n; int main(int argc, char **argv) { Node *list = NULL; list = Push(list, 1); list = Push(list, 2);

PushOntoList push_list.c #include <stdio.h> #include <stdlib.h> #include <assert.h> int element; Node; Node *Push(Node *head, int e) { Node *n = (Node *) malloc(sizeof(node)); assert(n!= NULL); // crashes if false n->element = e; n->next = head; return n; (main) list (POL) head NULL (POL) e 1 (POL) n??? NULL int main(int argc, char **argv) { Node *list = NULL; list = Push(list, 1); list = Push(list, 2);

PushOntoList push_list.c #include <stdio.h> #include <stdlib.h> #include <assert.h> int element; Node; Node *Push(Node *head, int e) { Node *n = (Node *) malloc(sizeof(node)); assert(n!= NULL); // crashes if false n->element = e; n->next = head; return n; int main(int argc, char **argv) { Node *list = NULL; (main) list (POL) head NULL NULL (POL) e 1 (POL) n element next?????? list = Push(list, 1); list = Push(list, 2);

PushOntoList push_list.c #include <stdio.h> #include <stdlib.h> #include <assert.h> int element; Node; Node *Push(Node *head, int e) { Node *n = (Node *) malloc(sizeof(node)); assert(n!= NULL); // crashes if false n->element = e; n->next = head; return n; int main(int argc, char **argv) { Node *list = NULL; (main) list (POL) head NULL NULL (POL) e 1 (POL) n element next?????? list = Push(list, 1); list = Push(list, 2);

PushOntoList push_list.c #include <stdio.h> #include <stdlib.h> #include <assert.h> int element; Node; Node *Push(Node *head, int e) { Node *n = (Node *) malloc(sizeof(node)); assert(n!= NULL); // crashes if false n->element = e; n->next = head; return n; int main(int argc, char **argv) { Node *list = NULL; (main) list (POL) head NULL NULL (POL) e 1 (POL) n element next 1??? list = Push(list, 1); list = Push(list, 2);

PushOntoList push_list.c #include <stdio.h> #include <stdlib.h> #include <assert.h> int element; Node; Node *Push(Node *head, int e) { Node *n = (Node *) malloc(sizeof(node)); assert(n!= NULL); // crashes if false n->element = e; n->next = head; return n; int main(int argc, char **argv) { Node *list = NULL; (main) list (POL) head NULL NULL (POL) e 1 (POL) n element next 1 NULL list = Push(list, 1); list = Push(list, 2);

PushOntoList push_list.c #include <stdio.h> #include <stdlib.h> #include <assert.h> int element; Node; Node *Push(Node *head, int e) { Node *n = (Node *) malloc(sizeof(node)); assert(n!= NULL); // crashes if false n->element = e; n->next = head; return n; int main(int argc, char **argv) { Node *list = NULL; (main) list (POL) head NULL (POL) e 1 (POL) n element next 1 NULL list = Push(list, 1); list = Push(list, 2);

PushOntoList push_list.c #include <stdio.h> #include <stdlib.h> #include <assert.h> int element; Node; (main) list Node *Push(Node *head, int e) { Node *n = (Node *) malloc(sizeof(node)); assert(n!= NULL); // crashes if false n->element = e; n->next = head; return n; int main(int argc, char **argv) { Node *list = NULL; element next 1 NULL list = Push(list, 1); list = Push(list, 2);

PushOntoList push_list.c #include <stdio.h> #include <stdlib.h> #include <assert.h> int element; Node; Node *Push(Node *head, int e) { Node *n = (Node *) malloc(sizeof(node)); assert(n!= NULL); // crashes if false n->element = e; n->next = head; return n; int main(int argc, char **argv) { Node *list = NULL; (main) list (POL) head (POL) e 2 (POL) n??? element next 1 NULL list = Push(list, 1); list = Push(list, 2);

PushOntoList push_list.c #include <stdio.h> #include <stdlib.h> #include <assert.h> int element; Node; Node *Push(Node *head, int e) { Node *n = (Node *) malloc(sizeof(node)); assert(n!= NULL); // crashes if false n->element = e; n->next = head; return n; int main(int argc, char **argv) { Node *list = NULL; (main) list (POL) head (POL) e 2 (POL) n element next 1 NULL list = Push(list, 1); list = Push(list, 2); element next??????

PushOntoList push_list.c #include <stdio.h> #include <stdlib.h> #include <assert.h> int element; Node; Node *Push(Node *head, int e) { Node *n = (Node *) malloc(sizeof(node)); assert(n!= NULL); // crashes if false n->element = e; n->next = head; return n; int main(int argc, char **argv) { Node *list = NULL; (main) list (POL) head (POL) e 2 (POL) n element next 1 NULL list = Push(list, 1); list = Push(list, 2); element next??????

PushOntoList push_list.c #include <stdio.h> #include <stdlib.h> #include <assert.h> int element; Node; Node *Push(Node *head, int e) { Node *n = (Node *) malloc(sizeof(node)); assert(n!= NULL); // crashes if false n->element = e; n->next = head; return n; int main(int argc, char **argv) { Node *list = NULL; (main) list (POL) head (POL) e 2 (POL) n element next 1 NULL list = Push(list, 1); list = Push(list, 2); element next 2???

PushOntoList push_list.c #include <stdio.h> #include <stdlib.h> #include <assert.h> int element; Node; Node *Push(Node *head, int e) { Node *n = (Node *) malloc(sizeof(node)); assert(n!= NULL); // crashes if false n->element = e; n->next = head; return n; int main(int argc, char **argv) { Node *list = NULL; (main) list (POL) head (POL) e 2 (POL) n element next 1 NULL list = Push(list, 1); list = Push(list, 2); element 2 next

PushOntoList push_list.c #include <stdio.h> #include <stdlib.h> #include <assert.h> int element; Node; Node *Push(Node *head, int e) { Node *n = (Node *) malloc(sizeof(node)); assert(n!= NULL); // crashes if false n->element = e; n->next = head; return n; int main(int argc, char **argv) { Node *list = NULL; (main) list (POL) head (POL) e 2 (POL) n element next 1 NULL list = Push(list, 1); list = Push(list, 2); element 2 next

PushOntoList push_list.c #include <stdio.h> #include <stdlib.h> #include <assert.h> int element; Node; (main) list Node *Push(Node *head, int e) { Node *n = (Node *) malloc(sizeof(node)); assert(n!= NULL); // crashes if false n->element = e; n->next = head; return n; int main(int argc, char **argv) { Node *list = NULL; element next 1 NULL list = Push(list, 1); list = Push(list, 2); element 2 next

PushOntoList push_list.c #include <stdio.h> #include <stdlib.h> #include <assert.h> int element; Node; Node *Push(Node *head, int e) { Node *n = (Node *) malloc(sizeof(node)); a (benign) leak!! try running with valgrind: bash$ gcc -o push_list -g -Wall push_list.c bash$ valgrind --leak-check=full./push_list assert(n!= NULL); // crashes if false n->element = e; n->next = head; return n; int main(int argc, char **argv) { Node *list = NULL; element next 1 NULL list = Push(list, 1); list = Push(list, 2); element 2 next

A generic linked list Previously, our linked list elements were of type int - what if we want to let our customer decide the element type? - idea: let them push a generic pointer -- i.e., a (void *) void *element; Node; Node *Push(Node *head, void *e) { Node *n = (Node *) malloc(sizeof(node)); assert(n!= NULL); // crashes if false n->element = e; n->next = head; return n; element next element next NULL

Using a generic linked list To use it, customers will need to use type casting - convert their data type to a (void *) before pushing - convert from a (void *) back to their data type when accessing void *element; Node; manual_list_void.c Node *Push(Node *head, void *e); // assume last slide s code int main(int argc, char **argv) { char *hello = "Hi there!"; char *goodbye = "Bye bye."; Node *list = NULL; list = Push(list, (void *) hello); list = Push(list, (void *) goodbye); printf("payload: '%s'\n", (char *) ((list->next)->element) );

Using a generic linked list Results in: (main) list (main) goodbye (main) hello element B y e b y e. \0 next element H i t h e r e! \0 next NULL

Multi-file C programs Let s create a linked list module - a module is a self-contained piece of an overall program has externally visible functions that customers can invoke has externally visible typedefs, and perhaps global variables, that customers can use may have internal functions, typedefs, global variables that customers should not look at - the module s interface is its set of public functions, typedefs, and global variables

Modularity The degree to which components of a system can be separated and recombined main program - loose coupling and separation of concerns linked list hash table - modules can be developed independently - modules can be re-used in different projects

C header files header: a C file whose only purpose is to be #include d - generally a filename with the.h extension - holds the variables, types, and function prototype declarations that make up the interface to a module the main idea - every name.c intended to be a module has a name.h - name.h declares the interface to that module - other modules that want to use name will #include name.h and they should assume as little as possible about the implementation in name.c

C module conventions Most C projects adhere to the following rules: -.h files never contain definitions, only declarations -.c files never contain prototype declarations for functions that are intended to be exported through the module interface those function prototype declarations belong in the.h file - never #include a.c file -- only #include.h files - any.c file with an associated.h file should be able to be compiled into a.o file

#include and the C preprocessor The C preprocessor (cpp) transforms your source code before the compiler runs - transforms your original C source code into transformed C source code - processes the directives it finds in your code (#something) #include ll.h -- replaces with post-processed content of ll.h #define PI 3.1415 -- defines a symbol, replaces later occurrences and there are several others we ll see soon... - run on your behalf by gcc during compilation

Example #define BAR 2 + FOO typedef long long int verylong; #define FOO 1 #include "cpp_example.h" cpp_example.h int main(int argc, char **argv) { int x = FOO; // a comment int y = BAR; verylong z = FOO + BAR; cpp_example.c Let s manually run the preprocessor on cpp_example.c: cpp is the preprocessor -P suppresses some extra debugging annotations bash$ cpp -P cpp_example.c out.c bash$ cat out.c typedef long long int verylong; int main(int argc, char **argv) { int x = 1; int y = 2 + 1; verylong z = 1 + 2 + 1;

Program that uses a linked list #include <stdlib.h> #include <assert.h> #include "ll.h" Node *Push(Node *head, void *element) {... implementation here... void *element; Node; Node *Push(Node *head, void *element); ll.c #include "ll.h" int main(int argc, char **argv) { Node *list = NULL; char *hi = hello ; char *bye = goodbye ; list = Push(list, hi); list = Push(list, bye); example_ll_customer.c ll.h

Compiling the program Four steps: - compile example_ll_customer.c into an object file - compile ll.c into an object file - link ll.o, example_ll_customer.o into an executable - test, debug, rinse, repeat bash$ gcc -Wall -g -o example_ll_customer.o -c example_ll_customer.c bash$ gcc -Wall -g -o ll.o -c ll.c bash$ gcc -o example_ll_customer -g ll.o example_ll_customer.o bash$ bash$./example_ll_customer Payload: 'yo!' Payload: 'goodbye' Payload: 'hello' bash$ valgrind --leak-check=full./example_customer...etc.

Building systems This doesn t really scale: gcc -Wall -g -o gadget *.c - Could take hours (think gcc source, linux kernel, etc.) If we change a single source file, what needs building? - foo.c - at least recompile to get foo.o then relink - foo.h - probably need to recompile foo.c then relink But also need to recompile everything that #includes foo.h Directly or indirectly... Easy to forget something and get a broken build Solution: let the computer figure it out!

Build dependencies All build tools work from same core idea: capture build dependencies and recompile only what s needed ex: Dependency graph for example_ll_customer example_ll_customer.c ll.h ll.c example_ll_customer.o ll.o example_ll_customer

make Venerable unix tool to automate build tasks Input is a Makefile with rules describing dependencies: target: sources tab char command(s) Meaning: if any source is newer (file system timestamp) than target then run command(s) - Nothing actually requires command(s) to have anything to do with sources or target, although that is the typical usage. Makefiles can do interesting things.

Makefile for ll project # default target (i.e., first one) is the executable program example_ll_customer: example_ll_customer.o ll.o gcc -Wall -g -o example_ll_customer example_ll_customer.o ll.o # targets for individual source files example_ll_customer.o: example_ll_customer.c ll.h gcc -Wall -g -c example_ll_customer.c ll.o: ll.c ll.h gcc -Wall -g -c ll.c Makefile # clean: remove files built by makefile and emacs backup files clean: rm -f example_ll_customer *.o *~ Run make to build the default (first) target Run make target to build named target

Exercise 1 Extend the linked list program we covered in class: - add a function that returns the number of elements in a list - implement a program that builds a list of lists i.e., it builds a linked list but each element in the list is a (different) linked list - bonus: design and implement a Pop function removes an element from the head of the list make sure your linked list code, and customers code that uses it, contains no memory leaks

Exercise 2 Implement and test a binary search tree - http://en.wikipedia.org/wiki/binary_search_tree don t worry about making it balanced - implement key insert( ) and lookup( ) functions bonus: implement a key delete( ) function - implement it as a C module bst.c, bst.h - implement test_bst.c contains main( ), tests out your BST

Exercise 3 Implement a Complex number module - complex.c, complex.h - includes a typedef to define a complex number a + bi, where a and b are doubles - includes functions to: add, subtract, multiply, and divide complex numbers - implement a test driver in test_complex.c contains main( )

See you on Monday!