CS62 - Spring 2011 - Lecture 33
Admin
- Computer science pre-registration pizza, Thursday at 5pm in Edmunds lobby
- If you're interested in TAing next semester, I forwarded the application (Due: April 24th)
- Prof. Kauchak's Thursday office hours move: 10-11am => 1-3pm
- will update reading for C++ book
- I will post practice problems (with solutions) on the same page as the lectures. You will be responsible for any of the problems for prior classes. I WILL give a quiz on one of these at some point. The quiz will consist of exactly one of the problems.
Pointers revisited
- what will be printed out by the precedence method?
- be careful with the precedence of '*'
- in general, you should just point parenthesis when dereferencing a pointer
- here, we end up incrementing the memory address of the pointer
- we don't change the value of x
- and now xPtr points to a random location in memory
- what does twoPointers print out?
- 20
- both xPtr and x2Ptr point to the same location in memory
- just like for built-in type, the = operator copies the memory address for pointers
- NULL
- like Java, we can talk about a pointer being null
- in C++, it's capital NULL
- you need to #include <cstdlib> to use NULL (I know, it's annoying)
- unlike in Java, pointers do are not initialized to NULL, so be careful
- pointers can be tricky. Think carefully about what you're doing!
parameter passing: look at
parameters.cpp code
- what will happen if we call swapAttempt?
- x and y will remain the same
- why?
- Java and C++ use what's called "call-by-value" parameter passing
- when a method is called, the value of the actual parameter is copied to the value of the formal parameters
- x and y outside the swapAttempt method reference different variables than those inside swapAttempt
- could we do what we want to do using pointers?
- look at swapWithPointers method
- rather than passing ints, we can pass int pointers (i.e. addresses to ints)
- we can then use '*' to get at the values stored at those memory address and swap the actual values
- how should we call swapWithPointers?
- need to provide an address:
swapWithPointers(&x, &y)
- notice that this is still call by value
- the value of &x (i.e. the memory address of x) is copied to the variable int* x
- C++ also provides another parameter passing mechanism called "call-by-reference"
- in call by reference, the formal parameters are the same thing as the actual parameters (there is no copying)
- they "reference" the same things/memory addresses
- in C++, you can denote that a parameter for a method should be passed as call-by-reference using the '&'
- NOTE: this is not the same as the unary operator for getting the address of a variable
- look at swapWithReference method
- notice that we use the variables normally (in particular, they are NOT pointers)
- however, because we passed them by reference, the x and y passed in are the SAME as the x and y used in the method. If we swap x and y in the method, we swap the parameters passed in as well
- look at binarySearch method and the testBinarySearch method
- binarySearch is just the C++ version of iterative binary search like we saw in the first few weeks of class
- testBinarySearch just generates some random numbers between 0 and 9 (inclusive), sorts them and then tries to find 7
- srand seeds the random number generator (here, based on the current time)
- sort, sorts the vector
- as we increase the "size" parameter of testBinarySearch, how would you expect to see the running times grow, that is, what is the run-time of the binarySearch method?
- we saw before that binarySearch is O(log n)
- however, the running times would actually scale roughly linearly
- why? what type of parameter passing mechanism are we using?
- the problem is that it's call by value, which means we have to copy the value over, which is linear
- why doesn't Java have this problem?
- all non-built-in variables are references, so while we do copy the values, it's only the value of the reference
- solutions?
- we could use pointers, but we'd have to modify the code
- an easier way is just to use call-by-reference
- just change the parameter passing mechanism by adding an '&' in the formal parameters
- any downside?
- what would happen if in binary search somebody typed:
nums = NULL;
- when we returned, we'd find our vector variable was now NULL :( Remember, when using call by reference the actual and formal parameters are one and the same
- call-by-constant reference
- in C++, the keyword "const" refers to something as being constant (like "final" in Java)
- something that is declared const cannot be changed in the code
- where have we seen const used before?
- in declaring a method to be an accessor method
- Another way const is used is to define call-by-constant reference, add "const" before the variable type and also include the '&' for call-by reference
int binarySearch(const vector<int>& nums, int findeMe
- you then cannot modify the variable nums (either directly or via mutator methods)
- another good reason to use const appropriately when declaring accessor and mutator methods
- as an aside, if you haven't noticed, C++ is famous for reusing different keywords in many different contexts (though usually related). Why did they do this?
- C++, was built on top of C and was tried to be made to be backwards compatible
- they wanted to avoid introducing new keywords and then having to modify existing C code
Look at Simple.java in
big3.cpp code
- what does this print out? why?
- 0
- if an object is used in the context of a String, it's toString method is implicitly called and that value is used.
- this always works, why?
- the Object class has a toString method defined for it
- why does this compile even though we never specified a constructor?
- the Java compiler implicitly defines the default constructor for you if you don't provide one!
- it would be the same as putting in a constructor with no code in it
Look at intcellexamples.cpp in
big3.cpp code
- Take a quick look at intcell.h to remind ourselves of the IntCell class (it's like a stripped down version of Integer in Java)
- We've created 4 different IntCell variables
- 'a' was created with the constructor
- 'b' was created by assigning it to 'a' in the constructor statement
- 'c' was created by passing 'a' as a parameter to the constructor
- 'd' was created with the constructor and then assigned later on to 'a'
- Where is the constructor used to create 'c' come from?
- this is called the "copy constructor" and is implicitly provided by the compiler if we don't explicitly define one
- What will be the output?
- interestingly enough, 1, 2, 3, 4!
- What does this imply?
- a, b, c, and d all are separate objects.
- Is this surprising?
- the output should not be that surprising
- we've not declared any of these variables as pointers, so we know they're independent objects on the stack
- the surprising thing is that this somehow works as we expect it should work
The C++ compiler provides two default functions for you: copy constructor and the = operator
- copy constructor
- the copy constructor is called for both 'b' and 'c'
- 'c' is not surprising since it looks like a constructor
- 'b' is just another way of writing it, but the copy constructor is still called
- by default, the copy constructor
- for objects: apply copy constructor calls to each of the member variables
- for built-in types (e.g. int, double and pointers!): simple assignment is done, that is, copy the value
- = operator
- called when the = operator is used and the left hand side is NOT a new variable definition (that is, when we have two already constructed objects)
- d = a
- by default, the = operator
- for object: apply the = operator on each of the member variables
- for built-in type: again, simple assignment
- default behavior
- is intuitive: to copy an object, you simply copy all of the member variables
- works in many situations (like our IntCell example above)
Look at IntCell2 class definition in
big3.cpp code
- What has changed from IntCell?
- instead of storing the value as an int, we're storying it as int* and keeping the value on the heap
- again, do as I say, not as I do :)
- there are rarely situations when you would actually need/want an int pointer or storing an int on the heap, but it makes the examples simpler
- another difference with C++, we can store built-in types on the heap! (that is, without wrapping them in an object)
- What class does this look like in Java?
- similar to the Integer class
- What would happen if in intcellexamples.cpp we changed the variables to be of type IntCell rather than IntCell2?
- we now get 4, 4, 4, 4 as a result. Why?
- a, b, c and d still are 4 separate objects on the call-stack
- the problem is that their private member "value" all point to the same thing. why?
- when 'b' and 'c' are constucted the default copy constructor is called
- the default behavior for pointers is to copy the value over
- this is called a "shallow" copy of the data structure
- similarly, when we set 'd = c' the default = operator is a shallow copy