# CSE332S Lecture 4 ## Namespace details ### Motivation Classes encapsulate behavior (methods) and state (member data) behind an interface. Structs are similar, but with state accessible. Classes and structs are used to specify self contained, cohesive abstractions. - Can say what class/struct does in one sentence. What if we want to describe more loosely related collections of state and behavior? Could use a class or struct - But that dilutes their design intent. ### Namespace Cpp offers an appropriate scoping mechanism for **loosely related** aggregates: Namespaces. - Good for large function collections. - E.g. a set of related algorithms and function objects - Good for general purpose collections - E.g. program utilities, performance statistics, etc. Declarative region - Where a variable/function can be used - From where declared to end of declarative region ### Namespace Properties Declared/(re)opend with `namespace` keyword. - `namespace name { ... }` - `namespace name = namespace existing_name { ... };` Access members using scoping `operator::` - `std::cout << "Hello, World!" << std::endl;` Everything not declared in another namespace is in the global namespace. Can nest namespace declarations - `namespace outer { namespace inner { ... } }` ### Using Namespaces The `using` keyword make elements visible. - Only apples to the current scope. Can add entire name space to the current scope - `using namespace std;` - `cout << "Hello, World!" << endl;` Can also declare unnamed namespaces - Elements are visible after the declaration - `namespace { int i = 42; }` will make `i` visible in the current file. ## C-style vs. C++ strings ### C++ string class ```cpp #include #include using namespace std; int main (int argc, char *argv[]) { string s = "Hello,"; s += " World!"; cout << s << endl; // prints "Hello, World!" return 0; } ``` - Using `` header - Various constructions - Assignment operator - Overloaded operators - Indexing operator, we can index cpp strings like arrays, `s[i]` ### C-style strings ```cpp #include #include using namespace std; int main (int argc, char *argv[]) { char *h = "Hello, "; string sh = "Hello, "; char *w = "World!"; string sw = "World!"; cout << (h < w) << endl; // this returns 0 because we are comparing pointers cout << (sh < sw) << endl; // this returns 1 because we are comparing values of strings in alphabetical order h += w; // this operation is illegal because we are trying to add a pointer to a pointer sh += sw; // concatenates the strings cout << h << endl; // this prints char repeatedly till the termination char cout << sh << endl; // this prints the string return 0; } ``` - C-style strings continguous arrays of char - Often accessed as `char *` by pointer. - Cpp string class provides a rich set of operations. - Cpp strings do "what you expected" as a programmer. - C-style strings do "what you expected" as a machine designer. Use cpp strings for most string operations. ## Cpp native array ### Storing Other Data Types Besides `char` There are many options to store non-char data in an array. Native C-style arrays - Cannot add or remove positions - Can index positions directly (constant time) - Not necessary zero-terminated (no null terminator as ending) STL list container (bi-linked list) - Add/remove position on either end - Cannot index positions directly STL vector container ("back stack") - Can add/remove position at the back - Can index positions directly ### Pointer and Arrays ```cpp #include using namespace std; int main (int argc, char *argv[]) { int a[10]; int *p = &a[0]; int *q = a; // p and q are pointing to the same location ++q; // q is now pointing to the second element of the array } ``` An array holds a contiguous sequence of memory locations - Can refer to locations using either array index or pointer location - `int a[0]` vs `int *p` - `a[i]` vs `*(a + i)` Array variable essentially behaves like a const pointer - Like `int * const arr;` - Cannot change where it points - Can change locations unless declared as const, eg `const int arr[10];` Can initalize other pointers to the start of the array - Using array name - `int *p = a;` - `int *p = &a[0];` Adding or subtracting int pointer n moves a pointer by n of the type it points to - `int *p = a;` - `p += 1;` moves pointer by 1 `sizeof(int)` - `p -= 1;` moves pointer by 1 `sizeof(int)` Remember that cpp only guarantees `sizeof(char)` is 1. ### Array of (and Pointers to) Pointers ```cpp #include using namespace std; int main (int argc, char *argv[]) { // could declare char ** argv for (int i = 0; i < argc; i++) { cout << argv[i] << endl; } return 0; } ``` Can have array of pointers to pointers Can also have an array of pointers to arrays - `int (*a)[10];` - `a[0]` is an array of 10 ints - `a[0][0]` is the first int in the first array ### Rules for pointer arithmetic ```cpp #include using namespace std; int main (int argc, char *argv[]) { int a[10]; int *p = &a[0]; int *q = p + 1; return 0; } ``` You can subtract pointers to get the number of elements between them (no addition, multiplication, or division) - `int n = q - p;` - `n` is the number of elements between `p` and `q` You can add/subtract an integer to a pointer to get a new pointer - `int *p2 = p + 1;` - `p2` is a pointer to the second element of the array - `p+(q-p)/2` is allowed but not `(p+q)/2` Array and pointer arithmetic: Given a pointer `p` and integer `n`, `p[n]` is equivalent to `*(p+n)`. Dereferencing a 0 pointer is undefined behavior. Accessing memory outside of an array may - Crash the program - Let you read/write memory you shouldn't (hard to debug) Watch out for: - Uninitialized pointers - Failing to check for null pointers - Accessing memory outside of an array - Error in loop initialization, termination, or increment ### Dynamic Memory Allocation Aray can be allocated, and deallocated dynamically Arrays have particular syntax for dynamic allocation Don't leak, destroy safely. ```cpp Foo * baz (){ // note the array form of new int * const a = new int[3]; a[0] = 1; a[1] = 2; a[2] = 3; Foo *f = new Foo; f->reset(a); return f; } void Foo::reset(int *a) { // ctor must initialize to 0 delete [] this->array_ptr; this->array_ptr = a; } void Foo::~Foo() { // note the array form of delete delete [] this->array_ptr; } ``` ## Vectors ```cpp #include #include using namespace std; int main (int argc, char *argv[]) { vector v; v.push_back(1); v.push_back(2); v.push_back(3); // note that size_t is an unsigned type that is guaranteed to be large enough to hold the size of v.size(), determined by the compiler. for (size_t i = 0; i < v.size(); i++) { cout << v[i] << endl; } // this will print 1, 2, 3 return 0; } ``` ### Motivation to use vectors Vector do a lot of (often tricky) dynamic memory management. - use new[] and delete[] internally - resize, don't leak memory Easier to pass to functions - can tell you their size by `size()` - Don't have to pass a separate size argument - Don't need a pointer by reference in order to resize Still have to pay attention - `push_back` allocates more memory but `[]` does not - vectors copy and take ownership of elements ## IO classes ```cpp #include using namespace std; int main (int argc, char *argv[]) { int i; // cout == std::ostream cout << "Enter an integer: "; // cin == std::istream cin >> i; cout << "You entered: " << i << endl; return 0; } ``` `` provides classes for input and output. - Use `` for input - Use `` for output Overloaded operators - `<<` for insertion - `>>` for extraction (terminates on whitespace) Other methods - `ostream` - `write` - `put` - `istream` - `get` - `eof` - `good` - `clear` Stream manipulators - `ostream`: `flush`, `endl`, `setwidth`, `setprecision`, `hex`, `boolalpha` (boolalpha is a manipulator that changes the way bools are printed from 0/1 to true/false). ### File I/O ```cpp #include #include using namespace std; int main (int argc, char *argv[]) { ifstream ifs; ifs.open("input.txt", ios::in); ofstream ofs ("output.txt", ios::out); if (!ifs.is_open() && ofs.is_open()) { int i; ifs >> i; ofs << i; } ifs.close(); ofs.close(); return 0; } ``` `` provides classes for file input and output. - Use `` for input - Use `` for output Other methods - `open` - `close` - `is_open` - `getline` parses a line from the file, defaults to whitespace - `seekg` - `seekp` File modes: - `in` let you read from the file - `out` let you write to the file - `ate` let you write to the end of the file - `app` let you write to the end of the file - `trunc` let you truncate the file - `binary` let you read/write binary data ### String Streams Classes ```cpp #include #include #include using namespace std; int main (int argc, char *argv[]) { ifstream ifs("input.txt", ios::in); if (!ifs.is_open()) { string line_1, word_1; getline(ifs, line_1); istringstream iss(line_1); iss >> word_1; cout << word_1 << endl; } ifs.close(); return 0; } ``` `` provides classes for string streams. - Use `` for input - Use `` for output Useful for scanning input - Get a line form file into a string - Wrap a string into a stream - Pull words off the stream ```cpp #include #include using namespace std; int main (int argc, char *argv[]) { if (argc < 3) return 1; ostringstream argsout; argsout << argv[1] << " " << argv[2] << endl; istringstream argsin(argsout.str()); float f,g; argsin >> f; argsin >> g; cout << f << "/" << g << "is" << f/g << endl; return 0; } ``` Useful for formatting output - Using string as format buffer - Wrapping a string into a stream - Push formatted values into the stream - Output the stream to file Program gets arguments as C-style strings Formatting is tedious and error prone in C-style strings (`sprintf`, etc.) `iostream` formatting is friendly.