C++ crash course
Class 7more 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;
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; int ival; 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?
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
• 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 expectedcout << (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_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
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
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 deleteint 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;
Type Conversions
• We can also explicitly cast one type to another• This is necessary sometimes, but dangerous– part of memory is suddenly being re-interpreted!
• Really useful in terms of arithmetic, which is pretty much the only time you’ll need it
How can we make integer division work?
Top Related