600 likes | 735 Views
C++ crash course. Class 7 more operators, expressions, statements. Agenda. More operators! getting values from combining operands Expressions strings of tokens that return a value Statements a line of code in C++. Assignment Operators. Assignment operators
E N D
C++ crash course Class 7 more operators, expressions, statements
Agenda • More operators! • getting values from combining operands • Expressions • strings of tokens that return a value • Statements • a line of code in C++
Assignment Operators • Assignment operators • An assignment is when we put a value in a variable • Left-hand operand must be a non-constlvalue inti, j, ival; constint ci = i; // alright; initializing 1024 = ival; // bad i + j = ival; // bad ci = ival; // bad
Assignment Operators • Array names are nonmodifiable: you can use subscript and dereference, but you can’t change the array itself int ia[10]; ia[0] = 0; // OK *ia = 0; // OK ia = ???; // bad!
Assignment Operator • Result of an assignment is the left-hand operand; type is the type of the left-hand operand ival = 0; // result: type int value 0 ival = 3.14159; // result: type int value 3 What happens here? inti = 10, j = 5; i = j = 4;
Assignment Operator • Result of an assignment is the left-hand operand; type is the type of the left-hand operand ival = 0; // result: type int value 0 ival = 3.14159; // result: type int value 3 What happens here? inti = 10, j = 5; i = j = 4; // assignment is right-associative
Assignment Operators • Assignment is right-associative; other binary operators are left associative Result of the rightmost assignment is assigned going left int ival; int *pval; ival = pval = 0; // error: can’t assign the val of a pointer to an int string s1, s2; s1 = s2 = “OK”; // alright; “OK” the char * literal gets converted to a string
Assignment Operators • Assignment has low precedence (happens last) inti = get_value(); while(i != 42) { i = get_value(); } How can we do this in one line?
Assignment Operators inti; while ((i = get_value()) != 42) { // do something } Without the parentheses, what happens? while (i = get_value() != 42) { // do something weird... }
Assignment Operators • That means BE CAREFUL whether you are using the comparison operator == or the assignment operator =! if (i = 42) if (i == 42) What’s the difference?
Assignment Operators What are i and d after each assignment? int i; double d; d = i = 3.5; i = d = 3.5;
Assignment Operators • What’s the difference here? if (42 = i) // ... if (i = 42) // ...
Compound Assignment Operators += -= *= /= %= // arithmetic operators (there are also bitwise operators, but we’re not going to talk about those) a = a op b; is the same as op= But the left-hand operand gets evaluated only once – mostly this doesn’t matter, except when it does (we might see cases of this later)
Assignment Operators • This is illegal. Why? double dval; intival; int *pi; dval = ival = pi = 0;
Assignment Operators • These are legal, but they’re not going to do what you might expect them to... • What should’ve been written? • if (ptr = retrieve_pointer() != 0) • if (ival = 1024) • ival += ival + 1;
Assignment Operators • Increment and decrement ++, -- inti = 0, j; j = ++i; // prefix j = i++; // postfix Note: prefix operator does less work! (Why?)
Assignment Operators • Combining dereference and increment... vector<int>::iterator iter = ivec.begin(); while (iter != ivec.end()) cout << *iter++ << endl; // iterator postfix increment What gets printed out? Why?
Assignment Operators • *iter++ : precedence of postfix increment is higher than the dereference operator *iter++ is the same as *(iter++)
Assignment Operators • Even though it’s a little confusing, experienced C++ programmers are more likely to use this kind of expression (*iter++) • so if you see C++ code, this is probably what you’ll see!
Assignment Operators • What would change if the while loop was written like so? vector<int>::iterator iter = ivec.begin(); while(iter != ivec.end()) cout << *++iter << endl;
Arrow Operator • You’ve seen the dot operator... item1.same_isbn(item2); // run the same_isbn function of item1 anim1.same_animal(anim2); // run the same_animal function of anim1
Arrow Operator • What if instead of having an explicit Animal_type, we instead have a pointer? Animal_type *ap = &anim1; (*ap).same_animal(anim2); But you have to be careful – what does this do? *ap.same_animal(anim2);
Arrow Operator • Thus we have the arrow operator -> ap->same_animal(anim2); It’s just syntactic sugar, but makes it much easier not to make mistakes!
Arrow Operator • Let’s write code: Define a vector of pointers to strings Read the vector, printing each string and its corresponding size
Arrow Operator • Assume iter is a vector<string>::iterator • Which of the following are legal? • What do they do? • *iter++; • *iter.empty(); • ++*iter; • (*iter)++; • iter->empty(); • iter++->empty();
Conditional Operator • Ternary operator – takes 3 arguments cond ? expr1 : expr2; equivalent to if(cond) { expr1; } else { expr2; }
Conditional Operator int i = 10, j = 20, k = 30; int maxVal = i > j ? i : j; What’s maxVal after this?
Conditional Operator • It’s a useful convention, but don’t abuse it int max = i > j ? i > k ? i : k : j > k ? j : k; What does the above do?
Conditional Operator • Equivalent to this... int max = i; if (j > max) max = j; if (k > max) max = k;
Conditional Operator • Fairly low precedence • In an output expression: cout << (i < j ? i : j); // works as expected cout << (i < j) ? i : j; // prints 1 or 0 – why? cout << i < j ? i : j; // error – why?
Conditional Operator • Writing code: Prompt the user for a pair of numbers, say which is smaller
Conditional Operator • Write code Process elements in a vector<int>, replacing any value that’s odd with twice its value
sizeof Operator • Returns a value of type size_t • Size in bytes of an object or type name – how much space it’s taking up in memory sizeof (type name); sizeof (expr); sizeof expr; (Remember when I said that doing ptr++ will cause it to move forward by a certain amount in memory?)
sizeof Operator • Can be used in multiple ways... Animal_typeanim, *pa; sizeof(Animal_type); sizeofanim; sizeof *pa;
sizeof Operator • Evaluating sizeofexprdoes not evaluate the expression sizeof *p; // will work even if p is a null pointer or invalid address!
sizeof Operator • Result of sizeof depends on the type involved • sizeof char or an expression of type char is 1 • sizeof a reference type returns the size of the memory necessary to contain an object of the referenced type • sizeof a pointer returns the size needed to hold a pointer; to obtain the size of the object, the pointer must be dereferenced • sizeof an array is equivalent to taking sizeof the element type, times the number of elements in the array
sizeof Operator • We can figure out the number of elements in an array this way! • (since there’s no array.size()) How?
sizeof Operator • What’s the output of this program going to be? [[ size of an int: 4 bytes; size of an int *: 8 bytes ]] int x[10]; int *p = x; cout << sizeof(x) / sizeof(*x) << endl; cout << sizeof(p) / sizeof(*p) << endl;
Compound Expressions • An expression with two or more operators is a compound expression • Must understand how precedence and associativity work in order to evaluate expressions • Precedence doesn’t necessarily specify order of evaluation, but it does determine what the answer will be
Precedence • We saw this yesterday: • How does this get evaluated? 6 + 3 * 4 / 2 + 2; Parentheses can override precedence ((6 + ((3 * 4) / 2) + 2) vs ((6 + 3) * 4) / 2 + 2
Associativity • Specifies how to group operators at the same precedence level Assignment is right associative Arithmetic is left associative
Associativity • Parenthesize these: ival = jval = kval = lval; ival * jval / kval * lval;
Precedence • When you know what the precedence is, it’s okay not to parenthesize – when you’re not sure, parenthesizing can help make sure that the program does what you want it to • Helpful in debugging: getting a weird result? Add parentheses around the things you thought were getting evaluated first • You can also look up the precedence for all the operators, but unless you’re an expert C++ programmer, it’s unlikely that you’ll be able to remember all of them • Useful to know for any programming language
new and delete • Has to do with allocating memory • We talked about this with dynamic arrays • We can also use it for single objects inti; // named, unitializedint int *pi = new int; // pi points to a dynamically allocated, unnamed, uninitialized int
new and delete • We need to initialize dynamically allocated objects too, even if they’re not named int i(1024); int *pi = new int(1024); string s(10, ‘9’); string *ps = new string(10, ‘9’); Must use direct-initialization syntax, rather than copy-initialization, to initialize dynamically allocated objects
new and delete • Without an explicit initializer, a dynamically allocated object is initialized in the same way as a variable inside a function • If there’s a default constructor, uses that; if it’s built-in, it’s uninitialized After each line, which is / are initialized? string *ps = new string; int *pi = new int;
new and delete • We can also value-initialize a dynamically allocated object • Default constructor, or basic type to 0 string *ps = new string(); int *pi = new int(); cls *pc = new cls();
new and delete • So that’s new... • ...why do we have delete? • Back in the day using new too many times could easily exhaust all your memory, causing a bad_allocexception • In order not to have our memory used up, we should free it using the delete expression delete pi; This will ONLY WORK for dynamically allocated variables; for all others it’s illegal – the behavior is undefined
new and delete int i; int *pi = &i; string str = “dwarves”; double *pd = new double(33); Which of these is safe? delete str; delete pi; delete pd;
new and delete int i; int *pi = &i; string str = “dwarves”; double *pd = new double(33); Which of these is safe? delete str; delete pi; // Watch out: some compilers will accept this even though it’s illegal! delete pd;