Please send questions to
st10@humboldt.edu .
dynamically-allocated ARRAYS
int *quant_array_ptr;
int num_quants;
cout << "how many quantities are there? ";
cin >> num_quants;
// now I want to dynamically allocate an array of ints
// of that size
quant_array_ptr = new int[num_quants];
// and now, I can STILL use the array notation I'm used to!
for (int i=0; i<num_quants; i++)
{
cout << "what is the next quantity? ";
cin >> quant_array_ptr[i];
}
// do other stuff
for (int i=0; i < num_quants; i++)
{
cout << quant_array_ptr[i] << endl;
}
// but BE CAREFUL!!! to FREE the dynamically-allocated
// array, you need to use SPECIAL SYNTAX!!!!!
// (compiler needs to know -- pointer is pointing to
// an ARRAY of dynamically-allocated memory, not just
// the FIRST element;)
delete [ ] quant_array_ptr;
// it OUGHTA be a syntax error if you don't free it this way --
// but that's not guaranteed!!
// ...so that you deallocate the ENTIRE array!
************************************
* NOTE: the above can be seen in-action in:
dyn_arr_ex.cpp
************************************
QUICK NOTE -- an array of objects is just fine!
*****NOTE!!!*******
I MIS-SPOKE in lab!!
You CANNOT use the [] notation WITHOUT giving a size!
(so -- for dynamic allocation later in the program,
you MUST use the pointer notation INSTEAD!!!)
*****************
/* this IS OKAY */
const int BOA_QUANT = 4;
boa my_boas1[BOA_QUANT];
// this is NOT OK
boa my_boas1[]; // NO NO NO NO NO
// and the following IS okay for dynamic allocation!!
boa *my_boas2;
int num_boas;
cout << "how many boas do you have? ";
cin >> num_boas;
my_boas2 = new boa[num_boas];
...my_boas2[0] ...
...
cout << my_boas2[5].get_color() << endl;
* remember to DEALLOCATE this dynamically-allocated array
when we are done...!
delete [ ] my_boas2;
************************************
* see example:
boa_array_play.cpp
....to see dynamic allocation of
an array of boas in action...
************************************
QUICK INTRO to C++ FILE I/O (note that Savitch Section 6.1 also
discusses this)
...because, now that we have dynamically-allocated arrays,
we'd love to be able to read huge quantities o'stuff from a
file into an array!
cout: output stream to the screen (to standard output)
cin: intput stream from the keyboard (from standard input)
iostream sets these two streams up for us;
for file i/o, YOU set up the streams, and then use them quite like
cout and cin;
for THIS kind of file i/o, you use the fstream library:
#include <fstream>
* decide if you want an input stream (of type ifstream)
or an output stream (of type ofstream)
and declare each that you desire:
ifstream my_in_stream;
ofstream my_out_stream;
* ifstream and ofstream are classes with a variety of methods!
one of these is an open method, to connect to, say, a file
to open a stream to that file for input or output;
...you give open a string (is it a char*?) argument, the NAME
of the file according to your operating system in the form
of a string;
* YES -- sadly, it DOES have to be an old-style char* string,
NOT a modern string type instance;
WORKAROUND: if you HAVE a string variable, and you'd like to
use it, call its c_str method -- it returns an old-style
char* version of the calling string instance!
string a_name;
a_name // has type string
a_name.c_str() // has type char* (c_str returns a char*
// version of the calling string, here a_name
// but these literals below ARE char* ...
my_in_stream.open("infile.txt");
my_out_stream.open("outfile.txt");
* when you open an input stream, the stream is now ready to
read the FIRST thing in that file;
* and how do you read it? just like reading from
the keyboard!
double weight;
my_in_stream >> weight;
...the next thing from infile.txt is converted to
double and read into weight;
* and how do you write to it? just like writing to
the screen!
my_out_stream << "howdy!" << endl;
* when you are done with a stream, it is GOOD PRACTICE
(and yes, a class coding standard) to CLOSE it:
my_in_stream.close();
my_out_stream.close();
* one more method, before we go on:
method fail() is true if a stream could NOT be opened --
if gives you a chance to bail out gracefully!
my_in_stream.open("blah.txt");
if (my_in_stream.fail())
{
cout << " OH NO!!! couldn't open blah.txt!" << endl;
return;
}
************************************
* these are demonstrated in the posted example:
file_io_ex.cpp
************************************
QUICK POINT: you CAN have pointers to objects;
boa *boa_ptr1;
boa *boa_ptr2;
...and you can dynamically allocate a boa for boa_ptr to point to:
boa_ptr1 = new boa;
boa_ptr2= new boa("red", 15, "pizza");
...you can then call the methods of the pointed-to boas using one
of two different notations: (EITHER of these is acceptable!)
boa_ptr1->set_color("purple");
(*boa_ptr1).set_weight(113);
you STILL should free these boas when done:
delete boa_ptr1;
delete boa_ptr2;
************************************
* you can see an example of a pointer to a boa
in the posted function:
display_boa.cpp (and in its testing main, display_boa_test.cpp)
************************************
PASS-BY-REFERENCE (call-by-reference)
* this is an ALTERNATIVE means of passing parameters!
* reminder: in pass-by-value, the argument's value is COPIED
into the parameter's memory;
* pass-by-reference is different:
...C++ passes the ADDRESS of the argument, not a copy of the
argument's value;
SO: when you change such a parameter in a function,
it CHANGES the corresponding argument!
* you use pass-by-reference, typically,
when you might want to change the corresponding argument!
* has nice "syntactic sugar" -- you still use the
pass-by-reference int parameter like a regular int,
the pass-by-reference double parameter list a regular
double, etc.
* the CLASSIC first example of this:
you want a function that SWAPS the values of its two arguments!
* you CAN'T do this with pass-by-value (without using explicit pointers)
* you CAN with pass-by-reference;
* so HOW do you tell C++ you want this pass-by-reference?
...you put an AMPERSAND & after the parameter type:
// I want val1 and val2 to be pass-by-reference parameters:
void swap(int& val1, int& val2)
* once you've declared the parameters this way, just
use val1 and val2 as normal! BUT if the function CHANGES
these, be aware that the calling arguments are ALSO changed;
* BECAUSE they MIGHT be changed -- only variables and things
that can be set (lvalues) can be pass-by-reference ARGUMENTS
/*
signature: swap: int& int& -> void
purpose: expects two pass-by-reference integer variables,
and produces nothing, but AFTERWARDS has the side-effect
that the value in the 1st will become the new value of
the 2nd, and the value in the 2nd will be the original
value of the 1st
examples:
int length1 = 5;
int length2 = 7;
swap(length1, length2);
afterwards:
length1 == 7
length2 == 5
void swap(int& val1, int& val2)
{
int temp;
temp = val1;
val1 = val2;
val2 = temp;
}
*****************************************
* see swap.cpp and swap_ck_expect.cpp
*****************************************
* people talk about INPUT PARAMETERS -- these are JUST to be used
and not to be set;
(typically, you use pass-by-value for these...)
people talk about OUTPUT PARAMETERS -- these are MEANT to be
changed by the function;
(typically, you use pass-by-reference for these...)
people talk about INPUT/OUTPUT parameters -- these are
meant to be used AND changed by the function;
(swap's parameters are input/output parameters...)
(typically, you use pass-by-reference for these...)