C++ crash course Class 7 more operators, expressions, statements.
-
Upload
peter-townsend -
Category
Documents
-
view
225 -
download
0
Transcript of 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-const lvalue
int i, j, ival;const int ci = i; // alright; initializing1024 = ival; // badi + j = ival; // badci = 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; // OKia = ???; // 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 0ival = 3.14159; // result: type int value 3
What happens here?
int i = 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 0ival = 3.14159; // result: type int value 3
What happens here?
int i = 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 intstring s1, s2;s1 = s2 = “OK”; // alright; “OK” the char * literal gets converted to a string
Assignment Operators
• Assignment has low precedence (happens last)
int i = get_value();while(i != 42) {
i = get_value();}
How can we do this in one line?
Assignment Operators
int i;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;
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
• These are legal, but they’re not going to do what you might expect them to...
• What should’ve been written?
a)if (ptr = retrieve_pointer() != 0)b)if (ival = 1024)c) ival += ival + 1;
Assignment Operators• Increment and decrement
++, --
int i = 0, j;j = ++i; // prefixj = 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 stringsRead 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?
a) *iter++;b) *iter.empty();c) ++*iter;d) (*iter)++;e) iter->empty();f) 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
• Fairly low precedence• In an output expression:
cout << (i < j ? i : j); // works as expectedcout << (i < j) ? i : j; // prints 1 or 0 – why?cout << i < j ? i : j; // error – why?
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_type anim, *pa;
sizeof(Animal_type);sizeof anim;sizeof *pa;
sizeof Operator
• Evaluating sizeof expr does 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
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
int i; // named, unitialized intint *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_alloc exception
• 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;
new and delete
• Once you delete a pointer to an object, you’ve deleted the object, but the pointer still hangs around, pointing to that spot in memory
• Called a dangling pointer• Watch out for these!– Best to set any pointers you’ve deleted to 0 (null
pointer)
new and deleteWhich of these are okay? Which are illegal / error-producing?
a)vector<string> svec(10);b)vector<string> *pvec1 = new vector<string>(10);c)vector<string> **pvec2 = new vector<string>[10];d)vector<string> *pv1 = &svec;e)vector<string> *pv2 = pvec1;
f)delete svec;g)delete pvec1;h)delete [] pvec2;i)delete pv1;j)delete pv2;
Type Conversions
• We discussed these a little bit yesterday: typecasting
• Types of operands determine whether an expression is legal– if the types are related in C++, then there’s a
conversion
int ival = 0;ival = 3.541 + 3; // compiles, sometimes gives warning
Type Conversions
• C++ has a set of conversions that make the operands the same before doing the arithmetic
• These conversions are done automatically by the compiler, called implicit type conversions
• Built-in conversions preserve precision if possible
Type Conversions• When is an implicit type conversion going to occur?
– Expressions with mixed-type operands:
int ival;double dval;ival >= dval; // ival converted to double
– Expression used as a condition goes to boolint ival;if (ival)while (cin)
– An expression used to initialize or assign to a variable is converted to the type of the variableint ival = 3.14;int *ip;ip = 0;
Type Conversions• Simplest conversion: integral promotions
char, signed char, unsigned char, short, and unsigned short can all get promoted to int
If the values don’t fit, promoted to unsigned int
For bools:false -> 0true -> 1
Type Conversions
• Pointer conversionsWhen we use an array, the array is converted to a pointer to the first element:
int ia[10];int * ip = ia;
Type Conversions• Enumeration conversions:
// point2d is 2, point2w is 3, point3d is 3, point3w is 4
enum Points { point2d = 2, point2w,point3d = 3, point3w };
const size_t array_size = 1024;int chunk_size = array_size * point2w;int array_3d = array_size * point3d;
Type Conversions• What conversions are happening here?
float fval;double dval;int ival;
a) if (fval)b)dval = fval + ival;c) dval + ival + cval;