Arrays of Variable Sizes

S

- Steve -

For a school assignment I need to write a class to work with the
following code. The IntArray b(-3, 6) basically means that I need to
produce an array of integer values that has an index going from -3 to
6. I'm completely lost on how I should create that array. Any shoves
in the right direction would be appreciated.

void test2()
{
system("cls");
cout << "2. Array declared with two integers: IntArray b(-3, 6);" <<
endl << endl;
csis << "2. Array declared with two integers: IntArray b(-3, 6);" <<
endl << endl;
IntArray b(-3, 6);
for(int i = b.low(); i <= b.high(); i++)
b = i * 10;
b.setName('b');
cout << b << endl;
csis << b << endl;
wait();
}
 
G

Gianni Mariani

- Steve - said:
For a school assignment I need to write a class to work with the
following code. The IntArray b(-3, 6) basically means that I need to
produce an array of integer values that has an index going from -3 to
6. I'm completely lost on how I should create that array. Any shoves
in the right direction would be appreciated.

void test2()
{
system("cls");
cout << "2. Array declared with two integers: IntArray b(-3, 6);" <<
endl << endl;
csis << "2. Array declared with two integers: IntArray b(-3, 6);" <<
endl << endl;
IntArray b(-3, 6);
for(int i = b.low(); i <= b.high(); i++)
b = i * 10;
b.setName('b');
cout << b << endl;
csis << b << endl;
wait();
}


your IntArray class needs to overload operator [] ... ?

Try creating a class and post the results ....
 
A

Alf P. Steinbach

For a school assignment I need to write a class to work with the
following code. The IntArray b(-3, 6) basically means that I need to
produce an array of integer values that has an index going from -3 to
6. I'm completely lost on how I should create that array. Any shoves
in the right direction would be appreciated.

(0)
A std::vector be a good idea for representing the storage.
Wrap that in a class.


void test2()
{
system("cls");

(1)
Not a good idea. Only works on a system with cls command.
Cannot be redirected to a file.

cout << "2. Array declared with two integers: IntArray b(-3, 6);" <<
endl << endl;
csis << "2. Array declared with two integers: IntArray b(-3, 6);" <<

(2)
What's "csis"?
Presumably some log file.
Why not just redirect standard output?

(3)
Duplicated literal text, use a named constant.

endl << endl;
IntArray b(-3, 6);

(4)
This tells you that you need a constructor with two arguments.

for(int i = b.low(); i <= b.high(); i++)

(5)
This tells you that you need accessor methods called "low" and
"high".

b = i * 10;


(6)
This tells you that you need an operator[]. See TCPPPL for an
example. For example.

b.setName('b');

(7)
This tells you that you need a modifier method called "setName".

cout << b << endl;

(8)
This tells you that you need something that makes it possible
to use an IntArray as an argument to an output stream. It
could be a custom operator<<. It could be an operator const char*.

csis << b << endl;
wait();

(9)
Assuming "wait" waits for user input that is ABSOLUTELY NOT a good
idea because it means you cannot automate the testing.
 
C

Clive

A std::vector be a good idea for representing the storage.
Wrap that in a class.

Isn't that a bit of overkill? From what i understand, the arrays created
don't have to be variable themselves. Just the index which created them.

Could you just create a class, that has a int start, and and int end, an int
a[end-start] and then a function, getInt(arrayIndex) which would presumably
be between the start and end (i'm sure you could also do checks for this).

so then you would go

MyClass m = myClass(-3, 6);
m.getInt(-1)

Alf P. Steinbach said:
For a school assignment I need to write a class to work with the
following code. The IntArray b(-3, 6) basically means that I need to
produce an array of integer values that has an index going from -3 to
6. I'm completely lost on how I should create that array. Any shoves
in the right direction would be appreciated.
(0)
void test2()
{
system("cls");

(1)
Not a good idea. Only works on a system with cls command.
Cannot be redirected to a file.

cout << "2. Array declared with two integers: IntArray b(-3, 6);" <<
endl << endl;
csis << "2. Array declared with two integers: IntArray b(-3, 6);" <<

(2)
What's "csis"?
Presumably some log file.
Why not just redirect standard output?

(3)
Duplicated literal text, use a named constant.

endl << endl;
IntArray b(-3, 6);

(4)
This tells you that you need a constructor with two arguments.

for(int i = b.low(); i <= b.high(); i++)

(5)
This tells you that you need accessor methods called "low" and
"high".

b = i * 10;


(6)
This tells you that you need an operator[]. See TCPPPL for an
example. For example.

b.setName('b');

(7)
This tells you that you need a modifier method called "setName".

cout << b << endl;

(8)
This tells you that you need something that makes it possible
to use an IntArray as an argument to an output stream. It
could be a custom operator<<. It could be an operator const char*.

csis << b << endl;
wait();

(9)
Assuming "wait" waits for user input that is ABSOLUTELY NOT a good
idea because it means you cannot automate the testing.
 
C

Clive

MyClass m = myClass(-3, 6);
That wouldn't satisfy the OP's requirements.

Yes, after reading the testing thing, i realise that this is wrong :(
The requirements would inspire me to learn how to do operator overloading.
Up until now... i just cant be bothered.
No. An array's size is a compile-time constant. A std::vector member is
just right for this; the alternative is explicitly memory-managing a
dynamic array. And vector will check your subscripts for you if you ask
it nicely.

i mean more like int* array = new int[end-start]

I got the impression that if it's a high school assignment. They wouldn't
need to jump right into vectors quite yet. Maybe i'm wrong though..

I guess i'm a fan of doing things your own way, doing as much stuff for
yourself instead of using someone elses stuff. the vector would do a fine
job of it, i just dont like thinking of all the extra resources and space
that they might use :) but on computers these days.. who cares right?
 
J

John Harrison

- Steve - said:
For a school assignment I need to write a class to work with the
following code. The IntArray b(-3, 6) basically means that I need to
produce an array of integer values that has an index going from -3 to
6. I'm completely lost on how I should create that array. Any shoves
in the right direction would be appreciated.

void test2()
{
system("cls");
cout << "2. Array declared with two integers: IntArray b(-3, 6);" <<
endl << endl;
csis << "2. Array declared with two integers: IntArray b(-3, 6);" <<
endl << endl;
IntArray b(-3, 6);
for(int i = b.low(); i <= b.high(); i++)
b = i * 10;
b.setName('b');
cout << b << endl;
csis << b << endl;
wait();
}


The difficulty in answering this question is that you've given no clue as to
your level of ability. Do you know how to create a class for instance?

If yes then have a go and post the resulting code, it doesn't matter if bits
are missing, it doesn't even matter if it doesn't compile. When we see how
good (or bad!) your coding is we'll be able to give appropriate advice.

If you don't know how to write a class then you've got a lot of catching up
to do.

john
 
P

Peter van Merkerk

Clive said:
That wouldn't satisfy the OP's requirements.

Yes, after reading the testing thing, i realise that this is wrong :(
The requirements would inspire me to learn how to do operator overloading.
Up until now... i just cant be bothered.
No. An array's size is a compile-time constant. A std::vector member is
just right for this; the alternative is explicitly memory-managing a
dynamic array. And vector will check your subscripts for you if you ask
it nicely.

i mean more like int* array = new int[end-start]

I got the impression that if it's a high school assignment. They wouldn't
need to jump right into vectors quite yet. Maybe i'm wrong though..

If you look at it another way it might actually make sense to learn simple
things like std::vector first and learn the low level stuff (which needed to
implement a vector class) later.
I guess i'm a fan of doing things your own way, doing as much stuff for
yourself instead of using someone elses stuff.

That is a great approach if the goal is to expand your knowledge and to get
a better insight how things work. On the other hand there is much to be said
for not reinventing the wheel every time and using the tools you have
already at your disposal. Spending some time in getting familiar with the
standard library is an investment that will pay itself back in no time. For
serious projects your approach is hardly practial; writing everything from
scratch takes a lot of time and for most projects time is a rather scarce
and expensive commodity.
the vector would do a fine
job of it, i just dont like thinking of all the extra resources and space
that they might use :) but on computers these days.. who cares right?

The amount of extra space required when using std::vector compared to your
own homebuild equivalent may very well be close to zero. Optimization based
on presumptions is a bad thing and more importantly a waste of time. Get the
code right and as clear as possible first (the standard library can help a
lot here), if and only if the perfomance/memory usage is not acceptable,
find the bottleneck(s) and optimize the relevant parts of your code.
 
S

- Steve -

Okay here's my class I'm working on right now, plus all the info I
think is needed to see what I'm trying to do. Basically I need the
following three lines of code to run

IntArray a(10);
for(int i=a.low();i<=a.high();i++)
a=i*10;

I'm trying to overload the [] operator. The function ARRAYSTRUCT
IntArray::eek:perator[] (int forLocation) is where things are starting to
fall apart I believe.





//My Class and such

typedef struct { //Array structure
int location;
int value;
} ARRAYSTRUCT;

class IntArray
{
private:
int arrayLow, arrayHigh; //low & high index of array
char name; //name of object
ARRAYSTRUCT *array; //pointer to beggining of array

public:
IntArray(int); //Constructor for arrays starting at 0
// IntArray(int, int); //Constructor for arrays not starting at 0

ARRAYSTRUCT IntArray::eek:perator[](int); //Overload [] - Pass location,
assign value

int low() {return arrayLow;} //Returns lowest index of array
int high() {return arrayHigh;} //Returns highest index of array

void setName(char myName) {name=myName;} //Sets name of object
};

IntArray::IntArray(int size)
{
arrayLow=0; //array starts at 0
arrayHigh=size-1; //highest index of array based on given size

array=new ARRAYSTRUCT[size]; //create array memory locations

for(int i=arrayLow;i<=arrayHigh;i++)
{
array->location=i; //Sets index of array
array->value=NULL; //Sets value of array to NULL
}
}

ARRAYSTRUCT IntArray::eek:perator[] (int forLocation)
{
ARRAYSTRUCT *myLocation=array;

for(int i=0;i<(arrayLow+forLocation);i++) //get myLocation to
correct spot
myLocation++;

return *myLocation;
}



John Harrison said:
- Steve - said:
For a school assignment I need to write a class to work with the
following code. The IntArray b(-3, 6) basically means that I need to
produce an array of integer values that has an index going from -3 to
6. I'm completely lost on how I should create that array. Any shoves
in the right direction would be appreciated.

void test2()
{
system("cls");
cout << "2. Array declared with two integers: IntArray b(-3, 6);" <<
endl << endl;
csis << "2. Array declared with two integers: IntArray b(-3, 6);" <<
endl << endl;
IntArray b(-3, 6);
for(int i = b.low(); i <= b.high(); i++)
b = i * 10;
b.setName('b');
cout << b << endl;
csis << b << endl;
wait();
}


The difficulty in answering this question is that you've given no clue as to
your level of ability. Do you know how to create a class for instance?

If yes then have a go and post the resulting code, it doesn't matter if bits
are missing, it doesn't even matter if it doesn't compile. When we see how
good (or bad!) your coding is we'll be able to give appropriate advice.

If you don't know how to write a class then you've got a lot of catching up
to do.

john
 
S

- Steve -

Okay Scratch all that, I've made some major progress. Take a look at this.

class IntArray
{
private:
int arrayLow, arrayHigh; //low & high index of array
char name; //name of object
int *array; //pointer to beggining of array

public:
IntArray(); //Constructor - create array index 0-9
IntArray(int); //Constructor for arrays starting at 0
IntArray(int, int); //Constructor for arrays not starting at 0
IntArray(IntArray*); //Constructor for making copy of another IntArray object

~IntArray(); //Default Deconstructor

int& IntArray::eek:perator[](int); //Overload [] for Assigning Values

int low() {return arrayLow;} //Returns lowest index of array
int high() {return arrayHigh;} //Returns highest index of array

void setName(char myName) {name=myName;} //Sets name of object
};

#include "intarray.h"

IntArray::IntArray()
{
arrayLow=0;
arrayHigh=9;

array=new int[arrayHigh-arrayLow];
}

IntArray::IntArray(int size)
{
arrayLow=0; //array starts at 0
arrayHigh=size-1; //highest index of array based on given size

array=new int[size]; //create array memory locations
}

IntArray::IntArray(int low, int high)
{
arrayLow=low; //start of array index
arrayHigh=high; //end of array index

if(arrayLow==arrayHigh)
array=new int[1]; //if high and low are equal create an array 1 unit long
else
array=new int[arrayHigh-arrayLow]; //create array memory locations
}

IntArray::IntArray(IntArray* copyThis)
{
arrayLow=copyThis->low();
arrayHigh=copyThis->high();

if(arrayLow==arrayHigh)
array=new int[1]; //if high and low are equal create an array 1 unit long
else
array=new int[arrayHigh-arrayLow]; //create array memory locations

for(int i=arrayLow;i<=arrayHigh;i++)
array=copyThis->array;
}

IntArray::~IntArray()
{
//for(int i=arrayLow;i<=arrayHigh;i++)
// delete [] array;
//delete [] array;
}

int& IntArray::eek:perator[] (int forLocation)
{
return array[arrayLow+forLocation];
}

Also some quick requirments:

IntArray a(10), w(10); // Ten elements, indexed 0 to 9
IntArray b(-3, 6); // Ten elements, indexed -3 to 6
IntArray c(6, 8); // Three elements, indexed 6 to 8
IntArray d(5, 5); // Single element array, indexed at 5
IntArray z; // Ten elements, indexed 0 to 9



Okay here's my class I'm working on right now, plus all the info I
think is needed to see what I'm trying to do. Basically I need the
following three lines of code to run

IntArray a(10);
for(int i=a.low();i<=a.high();i++)
a=i*10;

I'm trying to overload the [] operator. The function ARRAYSTRUCT
IntArray::eek:perator[] (int forLocation) is where things are starting to
fall apart I believe.





//My Class and such

typedef struct { //Array structure
int location;
int value;
} ARRAYSTRUCT;

class IntArray
{
private:
int arrayLow, arrayHigh; //low & high index of array
char name; //name of object
ARRAYSTRUCT *array; //pointer to beggining of array

public:
IntArray(int); //Constructor for arrays starting at 0
// IntArray(int, int); //Constructor for arrays not starting at 0

ARRAYSTRUCT IntArray::eek:perator[](int); //Overload [] - Pass location,
assign value

int low() {return arrayLow;} //Returns lowest index of array
int high() {return arrayHigh;} //Returns highest index of array

void setName(char myName) {name=myName;} //Sets name of object
};

IntArray::IntArray(int size)
{
arrayLow=0; //array starts at 0
arrayHigh=size-1; //highest index of array based on given size

array=new ARRAYSTRUCT[size]; //create array memory locations

for(int i=arrayLow;i<=arrayHigh;i++)
{
array->location=i; //Sets index of array
array->value=NULL; //Sets value of array to NULL
}
}

ARRAYSTRUCT IntArray::eek:perator[] (int forLocation)
{
ARRAYSTRUCT *myLocation=array;

for(int i=0;i<(arrayLow+forLocation);i++) //get myLocation to
correct spot
myLocation++;

return *myLocation;
}



John Harrison said:
- Steve - said:
For a school assignment I need to write a class to work with the
following code. The IntArray b(-3, 6) basically means that I need to
produce an array of integer values that has an index going from -3 to
6. I'm completely lost on how I should create that array. Any shoves
in the right direction would be appreciated.

void test2()
{
system("cls");
cout << "2. Array declared with two integers: IntArray b(-3, 6);" <<
endl << endl;
csis << "2. Array declared with two integers: IntArray b(-3, 6);" <<
endl << endl;
IntArray b(-3, 6);
for(int i = b.low(); i <= b.high(); i++)
b = i * 10;
b.setName('b');
cout << b << endl;
csis << b << endl;
wait();
}


The difficulty in answering this question is that you've given no clue as to
your level of ability. Do you know how to create a class for instance?

If yes then have a go and post the resulting code, it doesn't matter if bits
are missing, it doesn't even matter if it doesn't compile. When we see how
good (or bad!) your coding is we'll be able to give appropriate advice.

If you don't know how to write a class then you've got a lot of catching up
to do.

john
 
A

Alf P. Steinbach

Okay Scratch all that, I've made some major progress. Take a look at this.

Progress, very good.


class IntArray
{
private:
int arrayLow, arrayHigh; //low & high index of array
char name; //name of object
int *array; //pointer to beggining of array

public:
IntArray(); //Constructor - create array index 0-9
IntArray(int); //Constructor for arrays starting at 0
IntArray(int, int); //Constructor for arrays not starting at 0
IntArray(IntArray*); //Constructor for making copy of another IntArray object

The copy constructor has a standard signature,


IntArray( IntArray const& another )


which allows you to write e.g.


IntArray a;
IntArray b = a; // Copy constructor invoked.


When you define a copy constructor you should -- usually -- also
define an assignment operator,


IntArray& operator=( IntArray const& rhs )


which allows you to write


b = a;


Generally when one form of copying is needed the other one is also
needed.

~IntArray(); //Default Deconstructor

int& IntArray::eek:perator[](int); //Overload [] for Assigning Values

int low() {return arrayLow;} //Returns lowest index of array
int high() {return arrayHigh;} //Returns highest index of array

void setName(char myName) {name=myName;} //Sets name of object
};

#include "intarray.h"

IntArray::IntArray()
{
arrayLow=0;
arrayHigh=9;

array=new int[arrayHigh-arrayLow];
}

Is it meaningful to have a default constructor?

If you choose to have an assignment operator (see above comments),
then a default constructor can make practical sense.

But is it then meaningful to have it create anything other than
a _zero size_ array? I see further down that you list that as
a requirement. If it is a requirement then it seems to be a
requirement (analysis/design-level) bug, to be reported.


IntArray::IntArray(int size)
{
arrayLow=0; //array starts at 0
arrayHigh=size-1; //highest index of array based on given size

array=new int[size]; //create array memory locations
}

The 'name' member is not initialized.

Tip: look up constructor initializer lists.



IntArray::IntArray(int low, int high)
{
arrayLow=low; //start of array index
arrayHigh=high; //end of array index

if(arrayLow==arrayHigh)
array=new int[1]; //if high and low are equal create an array 1 unit long
else
array=new int[arrayHigh-arrayLow]; //create array memory locations
}

Here is an additional bug. When bug-free all cases except
arrayHigh<arrayLow-1 should be treated the same. Assuming the
requirements you list further down.

IntArray::IntArray(IntArray* copyThis)
{
arrayLow=copyThis->low();
arrayHigh=copyThis->high();

if(arrayLow==arrayHigh)
array=new int[1]; //if high and low are equal create an array 1 unit long
else
array=new int[arrayHigh-arrayLow]; //create array memory locations

Now here's that bug again.


for(int i=arrayLow;i<=arrayHigh;i++)
array=copyThis->array;
}


Just a stylistic hint. For various reasons old-timers prefer
to write "++i" instead of "i++". One reason is that this _can_
be more efficient, another is that when you have a general
iterator instead of an integer or pointer the iterator may only
support the prefix form, so that form is more general.

IntArray::~IntArray()
{
//for(int i=arrayLow;i<=arrayHigh;i++)
// delete [] array;
//delete [] array;
}


I assume this is work in progress.


int& IntArray::eek:perator[] (int forLocation)
{
return array[arrayLow+forLocation];
}

Works, but isn't the point of having specified bounds to also
have bounds-checking?


Also some quick requirments:

IntArray a(10), w(10); // Ten elements, indexed 0 to 9
IntArray b(-3, 6); // Ten elements, indexed -3 to 6
IntArray c(6, 8); // Three elements, indexed 6 to 8
IntArray d(5, 5); // Single element array, indexed at 5
IntArray z; // Ten elements, indexed 0 to 9

Possibly the last one should be reported as impractical, and in general,
when a requirement introduces arbitrariness it's probably a screw-up.

Okay, that's my comments.

Great work, keep that up!
 
J

John Harrison

Comments below.

- Steve - said:
Okay Scratch all that, I've made some major progress. Take a look at this.

class IntArray
{
private:
int arrayLow, arrayHigh; //low & high index of array
char name; //name of object

Do arrays really need names? And why only a single char for the name?
int *array; //pointer to beggining of array

public:
IntArray(); //Constructor - create array index 0-9
IntArray(int); //Constructor for arrays starting at 0
IntArray(int, int); //Constructor for arrays not starting at 0
IntArray(IntArray*); //Constructor for making copy of another IntArray
object

Not correct. For a copy constructor you (almost) always write

IntArray(const IntArray&);

then you also need assignment operator

IntArray& operator=(const IntArray&);

Without these two you program will crash, because the copielr will generate
these for you, if you haven't written then yourself. But the compiler
generated version will be incorrect because it will copy your array pointer
instead of allocating more memory.
~IntArray(); //Default Deconstructor

int& IntArray::eek:perator[](int); //Overload [] for Assigning Values

IntArray:: is incorrect (but some compilers allow it)

int& operator[](int); //Overload [] for Assigning Values

You also need an overload for accessing values from a const array

int operator[](int) const;
int low() {return arrayLow;} //Returns lowest index of array
int high() {return arrayHigh;} //Returns highest index of array

These should be const, its very important in C++ to mark methods as const if
that is what they are

int low() const {return arrayLow;} //Returns lowest index of array
int high() const {return arrayHigh;} //Returns highest index of array

Without the const methods I've described above, this code would not compile

int print_array(const IntArray& a)
{
for (int i = a.low(); i <=a.high(); ++i)
cout << a;
}

because a is a const.
void setName(char myName) {name=myName;} //Sets name of object
};

#include "intarray.h"

IntArray::IntArray()
{
arrayLow=0;
arrayHigh=9;

array=new int[arrayHigh-arrayLow];
}

IntArray::IntArray(int size)
{
arrayLow=0; //array starts at 0
arrayHigh=size-1; //highest index of array based on given size

array=new int[size]; //create array memory locations
}

IntArray::IntArray(int low, int high)
{
arrayLow=low; //start of array index
arrayHigh=high; //end of array index

if(arrayLow==arrayHigh)
array=new int[1]; //if high and low are equal create an array 1 unit long
else
array=new int[arrayHigh-arrayLow]; //create array memory locations

The math is wrong

array=new int[(arrayHigh - arrayLow) + 1];

No need to treat low == high as a special case (this should have been a
warning that you'd got something wrong, specail cases are to be avoided if
possible).
}

IntArray::IntArray(IntArray* copyThis)
{
arrayLow=copyThis->low();
arrayHigh=copyThis->high();

if(arrayLow==arrayHigh)
array=new int[1]; //if high and low are equal create an array 1 unit long
else
array=new int[arrayHigh-arrayLow]; //create array memory locations

Again the math is wrong, but the basic idea is right. Now rewrite this to
use the proper method of writing a copy constructor. The don't forget to add
an assignment operator.
for(int i=arrayLow;i<=arrayHigh;i++)
array=copyThis->array;
}

IntArray::~IntArray()
{
//for(int i=arrayLow;i<=arrayHigh;i++)
// delete [] array;
//delete [] array;


delete[] array; is correct.
}

int& IntArray::eek:perator[] (int forLocation)
{
return array[arrayLow+forLocation];
}

Also some quick requirments:

IntArray a(10), w(10); // Ten elements, indexed 0 to 9
IntArray b(-3, 6); // Ten elements, indexed -3 to 6
IntArray c(6, 8); // Three elements, indexed 6 to 8
IntArray d(5, 5); // Single element array, indexed at 5
IntArray z; // Ten elements, indexed 0 to 9

Looks pretty good. You've made the common newbie mistakes, ignoring the
issue of const, and being unsure about copying, but you're not far away from
finishing this.

john
 
J

John Harrison

Another math error
IntArray::IntArray()
{
arrayLow=0;
arrayHigh=9;

array=new int[arrayHigh-arrayLow];

array = new[(arrayHigh-arrayLow)+1];

or rether more simply

array = new[10];

BTW you obviously haven't heard of initaliser lists. Really all your
constructors should be written like this

IntArray::IntArray() : arrayLow(0), arrayHigh(9), array(new int[10])
{
}

Look them up in your favourite C++ book.

john
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,579
Members
45,053
Latest member
BrodieSola

Latest Threads

Top