Please send questions to
st10@humboldt.edu .
CIS 130 - Week 14, Monday - April 26, 2010
* Sometimes people categorize parameters into the following 3 categories:
input parameters
...what almost all of our functions with parameters have
used this semester! They provide information INTO the
function from the caller;
C++ assumes that most (scalar) parameters are input parameters.
BUT there can be other categories as well:
output parameters
...these we haven't said much about yet!
These are parameters we intend to set within the
function, and we would LIKE the corresponding
argument to be changed accordingly;
You have to generally tell C++ if you want this...
input/output parameters
...we haven't said much about these, either, yet;
These are parameters that provide information INTO the
function, and ALSO may be modified by the function,
and we would LIKE the corresponding argument
to be changed accordingly;
...in general, you NEED to make sure that the user knows
if a parameter is an output or an input/output parameter,
as those are both more unusual AND they require more
careful action by the user;
FIRST: how C++ passes (scalar) input parameters
* it uses PASS-BY-VALUE (sometimes called CALL-BY-VALUE)
* int double_me(int amount)
{
return amount * 2;
}
for example,
double_me(3) == 6
double_me(2 + 7) == 18
double_me( double_me(5) ) == 20
* when you call double_me,
a memory location is set up for parameter amount,
and the value of the argument expression is COPIED
into that amount memory;
* to see if you're really getting this, consider this
UGLY function with POOR STYLE
int ugly(int value)
{
value += 30;
return value;
}
MAKE SURE YOU SEE:
if ugly is called as follows:
int quant;
quant = 4;
cout << ugly(quant) << endl;
cout << quant << endl;
...that this fragment would cause the
following to be printed to the screen:
34
4
...because, with pass-by-value, you CAN'T muck with the
argument even if you muck with the parameter;
it is "safe" for true input parameters;
(and because it is thus potentially misleading to
a casual user, it is considered POOR STYLE to muck
with a pass-by-value parameter -- it is intended
to be used just for input, after all;)
With scalar pass-by-value parameters, you cannot muck with the argument
by just mucking with the parameter;
* what do you do if you would like to change an input parameter
in a function?
...copy it into a local variable in that function,
and change that instead;
int less_ugly(int value)
{
int value_copy;
value_copy = value;
value_copy += 30;
return value_copy;
}
NOW -- why do I keep specifying SCALAR above?
* ...because, to avoid copying who-knows-how-many elements
that can be in an array when an array is a parameter,
C++ instead just copies over WHERE the array the starts;
(it copies the address of the array...)
(where to find it)
* It copies the array by value, but for an array, what
it copies is just the address of its first element!
Changing that address in the parameter won't where the
argument array starts --
BUT writing parameter array expressions that change the
array can really change the values AT that argument's
address;
...changing the parameter array DOES change the argument
array.
(arrays, in C++, are automatically input and output
and input/output parameters...!)
* (I think you can use const in a function header to indicate
to the C++ compiler that an array parameter must not be
changed... but that's kind of beyond the scope of the
course...)
That's still pass-by-value, though.
C++ has another passing parameters, too:
PASS-BY-REFERENCE (or call-by-reference)
* ...and with pass-by-reference, you can set up scalar
parameters to be output or input/output parameters, too;
* when you pass a parameter by reference,
you don't copy the value of the argument into the parameter,
you copy a REFERENCE to the argument -- or, its address!
(if you passed an array by reference, you would copy the
address of its address into the parameter...! but that's
also beyond the scope of CIS 130...)
* you have to TELL C++ when you want to pass by reference;
you do that with this syntax:
return_type funct_name(param_type& param_name, ...)
^ put this & after EACH parameter's
type for EACH pass-by-reference
parameter;
THAT tells C++ to pass THAT parameter by reference --
to copy over the argument's address into that parameter,
and when you change that parameter, to thus change
the value AT the argument's address -- to change the argument!!
* so, with pass-by-reference, changing the parameter DOES
change the argument!
...you use pass-by-reference for output and input/output
parameters, then;
THE classic pass-by-reference example:
swap!
/*
contract: swap: int& int& -> void
^ PUT that it is pass by reference in your contract
by putting & after that parameter's type!!
purpose: expects two integer arguments, and returns nothing,
but has the side effect that when it is done,
the first argument has the original value of the second
argument, and the second argument has the original value of the
first argument;
void swap(int& value1, int& value2)
examples:
int quant1 = 15;
int quant2 = 27;
swap(quant1, quant2);
...then, after this call:
quant1 == 27
quant2 == 15
void swap(int& value1, int& value2)
{
int temp;
temp = value1;
value1 = value2;
value2 = temp;
}
* this works!
...but note: pass-by-reference arguments are RESTRICTED, compared
to pass-by-value arguments;
...pass-by-reference arguments have to have addresses,
they have to be ABLE to be reasonably changed!
swap(3, 5); <--- ILLEGAL!
swap(a+1, b+2) <-- ILLEGAL!
const int NUM_THINGS = 7;
int quant = 15;
swap(NUM_THINGS, quant); <--- ILLEGAL!
(notice that you can pass two array references --
they have addresses...
swap(arr[1], arr[3]); <-- is legal...
* then, you should choose the right parameter-passing method
for your parameters!
a scalar input parameter? use pass-by-value
an array input parameter? figure out where that const goes...
a scalar output or input/output parameter? use pass-by-reference
an array output or input/output parameter, where the location of the array
won't change? pass-by-value of that array will work fine;
(OK, and if the location of the array MIGHT need to change?
THEN you'd pass the output or input/output array parameter
by reference...!)