450 likes | 580 Views
A C++ Crash Course. UW Association for Computing Machinery http://www.cs.washington.edu/orgs/acm/tutorials acm@cs.washington.edu. Questions & Feedback to Hannah C. Tang (hctang) and Albert J. Wong (awong). Goals of Java. Java Simple Consistent Huge OO Focus
E N D
A C++ Crash Course UW Association for Computing Machinery http://www.cs.washington.edu/orgs/acm/tutorials acm@cs.washington.edu Questions & Feedback to Hannah C. Tang (hctang) and Albert J. Wong (awong)
Goals of Java Java • Simple • Consistent • Huge OO Focus • Cross platform via a virtual machine • Originally for embedded systems Java, C, and C++, have different design goals.
Goals of C and C++ C and C++ are popular because they have met, with reasonable success, their goals. C • Low level • No Runtime Type info • Easy implementation C++ • Originally to add some OO functionality to C • Attempt to be a higher-level language • Now it’s a totally different language
The compilation Process Libraries Preprocesser Resolves #define, #include Source code (text) .c .h .c .h Preprocessor Compiler C/C++ code (text) Translates code to Machine Language. It outputs an “object file.” This code is not executable Compiler Object code (bin) Linker Linker Takes object files and resolves references to functions and variables in different files Native Executable (bin) executable
Declarations - (bad) Example What is wrong with the following code? Will it compile in C? in C++? int main(void) { int result; ... result = add(20, 3); ... return 0; } int add(int a, int b) { return a + b; } Hint: It has to do with the declaration and use of add.
add is declared in the shaded regions Declaration Regions Corrected Code 2 (global prototype) Corrected Code 1 (local prototype) int main(void) { int result; int add(int,int); ... result = add(20, 3); ... return 0; } int add(int a, int b) { return a + b; } ... int add(int,int); int main(void) { int result; ... result = add(20, 3); ... return 0; } int add(int a, int b) { return a + b; } ...
#define • #define Tag Substitution • Replaces all following occurrences of Tag with Substitution • The Substitution may be the empty string • Does not replace Tag if it is inside quotation marks • #define Tag(x,y,z) Substitution • Creates a Function-like macro Tag • The Substitution may refer to the parameters x, y, or z • Only items of the form Tag(x,y,z) will be replaced (Just plain Tag will be ignored) int ar[80]; point->xCoord “lalala”->f03j? #define MAX_SIZE 80 #define GET_FIELD(a,b) a->b int ar[MAX_SIZE]; GET_FIELD(point, xCoord); GET_FIELD(“lalala", f03j?);
Header Files Common Usages: • Creates an informal module interface (No relation to Java interfaces) • Provides documentation • Each module usually has a header file • Often include the following: • function prototypes • struct and class declarations • typedefs • global variable declarations • Lots of (high-level) comments • Abstracts code for optimization (less common)
#include #include essentially copies and pastes the given file into the current line • There are two forms of #include • They differ in the order in which directories are search for the given file • The search order is implementation defined • Here is the general pattern for different compilers: #include <filename> • Searches the “include path,” then the current directory #include “filename” • Searches the current directory, then the “include path”
Header Guards Header Guards are a common C/C++ idiom Wrap each header file with the lines: #ifndef FILENAME_H #define FILENAME_H <header file body here> #endif /* FILENAME_H */ There is almost no reason to put things outside of header guards
point2d.h #ifndef POINT2D_H #define POINT2D_H struct Point2D { int x; int y; }; typedef struct Point2D Point2D; /* returns the result of the vector addition of * a and b. */ Point2D add(Point2D *a, Point2D *b); /* returns the result of the vector subtraction of * b from a */ Point2D sub(Point2D *a, Point2D *b); #endif /* POINT2D_H */ Header File
Classes • Roots come from C-style structs • Fairly similar to Java classes in concept. • Used to group related data and functions. • Can be used to write OO code class Queue { public: Queue(); void enqueue(int n); int dequeue(); ~Queue(); private: int numElements; int capacity; int *queueData; };
Declaring a class: class [optional name] { [access modifier] <type> member1; <type> member2; [access modifier] <type> member3; <type> member4; … } [instance list]; Example: class Point2D{ private: int x; int y; public: Point2D(int x, int y); int getX(); int getY(); } p1(2,3); Point2D p2(1,3); Point2D *p; Basic class Syntax Declaring a class without inheritance
Classes form a closed namespace Declaring & Defining methods /* point2d.h */ #ifndef POINT2D_H #define POINT2D_H class Point2D{ private: int x; int y; public: Point2D(int x, int y); int getX(); int getY(); }; #endif /* POINT2D_H */ /* point2d.cc */ #include “point2d.h” Point2D::Point2D(int x, int y){ x = 0; y = 0; } int Point2D::getX(){ return x; } int Point2D::getY(){ return y; }
Constructors Constructors are functions that get called when a class is instantiated • Constructors have the same name as their class • Constructors may not pass off control to another constructor • A default (zero argument) constructor is provided when no other constructors declared • Constructors may invoke the constructors of their super class, and of their member variables via member-wise initialization.
Destructors Destructors are called when a class is deallocated • Destructors are have no return type and have the same name as their class with a ‘~’ prepended. • If no destructor is given, a trivial destructor, which calls the destructor for all elements is given.
Inheritance Inheritance is specified by a : and a list of access specifiers + class names in the class declaration class Point2D{ private: int x; int y; public: Point2D(int x, int y); int getX(); int getY(); }; class ColorPoint2D : public Point2D { private: int color; public: ColorPoint2D(int x, int y, int color); int getColor(); };
Inheritance continued • Base classes can be public, protected, or private • In public inheritance, all public and protected members are inherited • In protected inheritance, all public members from the base class become protected • In private inheritance, all public and protected members become private • Java only has public inheritance • You can call any ancestor’s class method using the scope resolution operator (::)
Dynamic Memory • Dynamically sized memory in C and C++ must be manually managed • Dynamic memory is not necessarily much slower than static memory • All allocated memory must be freed by the user • Do not free memory twice (double free). • Do not free memory that was allocated by you • Manual memory management allows for finer grained control of your program • It’s not that scary, nor that hard.
new, delete, delete[] • the new operator allocates new memory, initializes it and returns a pointer to it. • the delete operator deallocates memory allocated by new • If you allocate a new array, you must delete it with delete[] and not delete Example: Point2D *p = new Point; delete p; p = NULL; int *ar = new int[50]; delete[] ar; ar = NULL; Improper use of delete and delete[] will cause undefined behavior!
malloc, calloc, realloc, free • These are C memory management functions • Do not mix them with the C++ ones! (that is, don’t try to delete memory from malloc, etc.) • These functions return void* (pointers to anything) • They are not typesafe • They do not call initializers for the memory • There is no realloc equivalent for C++ • Some low-level memory management may be faster with these functions, but don’t bank on that.
myArray[5] myArray[4] myArray[3] myArray[2] myArray[1] myArray[0] or myArray Arrays <ArrayType> arrayName[ numElements ] • Arrays are contiguous memory locations, and its name refers only to the address of the first element • Indexing into an array is the same as adding an offset to the address of the first element • When declaring an array, its size must be known at compile-time
Arrays as function parameters <ReturnType> funcName( ArrayType arrName[ ] ) int sumOfArray( int values[], int numValues ) • Arrays are not passed by copy. Instead, the address of the first element is passed to the function • Note how array parameters and non-parameter arrays behave identically
x(4104) y(4100) 4096 n(4096) 7 Pointers: vocabulary • A pointer is a variable which contains addresses of other variables • Accessing the data at the contained address is called “dereferencing a pointer” or “following a pointer”
Declaring Pointers Declaring a pointer: <Type> * ptrName; “ptrName is a variable which contains the address of something of type <Type>” For example: int * nPtr1, * nPtr2; void aFunc( int aParam, int * ptrParam); Using Pointers Dereferencing a pointer: *ptrName “Go to the address contained in the variable ptrName” Getting the address of a variable: &aVar “Get the address of aVar” For example: aFunc(myInt, &anotherInt); anInt = *myPtr * 4; *dinner = 100; Pointer Syntax
The code int * p; int q; p = &q *p = 5; Box Diagrams “p’s type is int pointer. q’s type is int.” “Assign 5 to where p points (which is q).” 5 p Pointers: Putting it all together Memory Layout pcontains the address of anint. qcontains anint. Go to the address thatpcontains, and place a 5 there. 8196 p (8200) q q (8196) 5
p(8200) p(8200) p(8200) 8192 8192 8192 b (8196) b (8196) b (8196) 300 9 9 a (8192) a (8192) a (8192) 200 200 16 Pointer Arithmetic Pointers are numbers, so you can do math on them! int * p = &a; *p = 200; *(p+1) = 300; Pointer p refers to an int, so adding 1 to p increments the address by the size of one int. The C/C++ expression for this is sizeof(int)
Pointers and Arrays Pointers and arrays are (almost) interchangeable Given: myArray[4] (9000) int myArray[5]; int * p = myArray; myArray[3] (8196) myArray[2] (8192) These are equivalent: • *p • myArray[0] • *(p+0) • *myArray • p[0] • 0[p] myArray[1] (8188) myArray[0] (8184) p (8180) 8184
Function Pointers <ReturnType> (*ptrName)(arg type list ); • Functions are pieces of code in memory • Pointers can point to functions. • Notice that the name of the variable appears in the middle of the statement! • You do not have to dereference a function pointer Function pointers are not scary. They are useful!
Function Pointers - example void foo(int i, char b); void bar(int i, char b); int main(void) { void (*p)(int,char); p = foo; p(1, ‘c’); // equivalent to foo(1, ’c’); p = bar; p(2, ‘b’); // equivalent to bar(2, ‘b’); (*p)(2, ‘b’); // Exactly the same return 0; }
C-style struct A struct is used to group related data items struct student { int id; char name[80;] }; Note that the it is optional to name a struct • To the programmer • id and name are now related • structstudent creates a convenient grouping • To the compiler • Id and name have a fixed ordering (not offset) in memory • Struct student is a first-class type that can be passed to functions
Declaring a Struct Declaring a struct: struct [optional name] { <type> field1; <type> field2; … } [instance list]; Examples: struct Foo { int field1; char field2; } foo,*foo_ptr; struct Foo foo2; struct { int a; } blah; Access struct fields Accessing a field in a struct: foo.field1; “gets field1 from the instance foo of struct Foo” Pointers syntax and structs The * has lower precedence than the ‘.’ : *foo_ptr.field1; means *(foo_ptr.field1); Which won’t compile Accessing a field in a struct pointer: (*foo_ptr).field1; foo_ptr->field1; struct Syntax
Typedef Typedef is used to create an alias to a type typedef unsigned char byte; unsigned char mybyte; byte mybyte; • byte now represents an unsigned char • Both definitions of mybyte are equivalent to the compiler. • The second definition is preferred as it gives more info
Typedefs – structs/enums/unions People often make a typedef of an anonymous struct or enum typedef struct { int id; char name[80]; } Student; Student st; struct Student { int id; char name[80]; }; struct Student st; These are almost the same. However, anonymous structs cannot refer to themselves. struct List { int data; struct List *next; };
I/O C-style C-style IO is an acquired taste. Learn to like it. Basic functions: • printf, scanf, fprintf, fscanf, sprintf, sscanf, etc. • gets, puts, getc, putc, getchar • read, write, fread, fwrite • We will cover the basics of the “formated” family of functions (printf, scanf, etc). • For the others, read the man pages in Unix.
printf printf(char *format_string, ...); fprintf(FILE*, char *format_string, ...); snprintf(char* buf, size_t n, char *format_string, ...); • In C, all devices are treated like files • Three standard files are: • stdin Often the keyboard • stdout Often the text console • stderr Often the text console • printf(....) is fprintf(stdout, ....) • The format string is a pattern for the output; it describes how to display the arguments to printf. • Snprintf write to the string “buf”. The variable n specifies the size of the buffer. • printf returns the number of characters written
format string • Format strings are normal strings with embedded “conversion specifications” which are placeholders for arguments • Conversion specifications are a ‘%’ and a letter with an optional set of arguments in between the ‘%’ and letter. • To print a ‘%’, you need to write ‘%%’ Example: printf(“Here is a number: %d\n”, 10); %d is the conversion specification for signed integers.
Conversion Specifications Converion specifications tell how to translate a data value into a string Conversion Specifications: • %d, %i -- signed integer • %u -- unsigned integer • %f -- floating point number • %c -- character • %s -- string • %x -- hexadecimal value • %p -- pointer Options: • l -- long (32-bit value) • ll -- long long (64-bit value) • n -- field width of n digits • .n -- precision of n digits • 0 -- fill unused field with 0s There are many more! Read man pages, or Google it.
I/O C++-style C++-style IO is easier for simple stuff Basic classes: • iostream (cout, cin, cerr) • ostringstream, istringstream cout << “Hello World!” << endll; cout << “Boo! “ << 10 << ‘c’ << endl; cerr << “Here’s the error stream” << endl; int n; cin >> n; char ch; cin >> ch;
I/O C++-style continued... ...but harder for complex stuff printf(“%.3f rounded to 2 decimals is %.2f\n”, 2.325, 2.325); …becomes… cout << setprecision(3) << 2.325 << “ rounded to 2 decimals is “ << setprecision(2) << 2.3.25 << endl;
Global Variables • Global Variables are not evil! • Allocated at program start. • Deallocated at program end. • By default, initialized to bit-wise zero (do not depend on this). • Need to understand modifiers: extern, static, and const to use properly. • Need to understand linking to use properly.
/* util.c */ int g_numCalls = 0; void someFunc(void) { fprintf(stderr, “Num Calls to %s: %d\n”, __func__, g_numCalls); ... } Global Variables - Gotcha What is wrong with this code? /* test.c */ void someFunc(void); int g_numCalls = 0; int main(void) { fprintf(stderr, “Num Calls to %s: %d\n”, __func__, g_numCalls); someFunc(); someFunc(); ... } compile line: gcc -Wall -ansi util.c test.c -o test
static static has 3 very separate meanings On a global variable or a function static int g_someGlobalVariable; static void myFunction(void); Tells the linker not to export the variable or function. Essentially makes the identifier “file scope,” as the linker will not use it fulfill dependencies from other files. On a local (function) variable void someFunc(void) { static int array[4000]; } Places the variable off the stack. This has the side-effect that it retains it value across calls. It is often used when a variable is too large to be put on the stack. On a class member (covered when we discuss classes)
/* util.c */ static int g_numCalls = 0; void someFunc(void) { fprintf(stderr, “Num Calls to %s: %d\n”, __func__, g_numCalls); ... } Globals Variables - Gotcha (fixed) Static to the rescue!!!!! /* test.c */ void someFunc(void); static int g_numCalls = 0; int main(void) { fprintf(stderr, “Num Calls to %s: %d\n”, __func__, g_numCalls); someFunc(); someFunc(); ... } compile line: gcc -Wall -ansi util.c test.c -o test The two variables “g_numCalls” have no relation. Think of them as private to each file.