By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
435,519 Members | 2,332 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 435,519 IT Pros & Developers. It's quick & easy.

create a dynamic array of pointers with initial values of NULL

P: n/a
I need (okay, I want) to make a dynamic array of my class 'Directory',
within my class Directory (Can you already smell disaster?)

Each Directory can have subdirectories so I thought to put these in an
array. The application compiles but aborts without giving me any useful
information.

What I suspect is happening is infinite recursion. Each Directory
object creates an array of Subdirectories each of which has an array of
sub-directorires...

I think it basically is recursively killing itself.

Is there some way to declare this array so that the values are NULL
initially? Thus (I think) doing away with the recursion problem. Then
as I add ACTUAL sub-directories it should work. As I delete
Sub-directories I take the array item and set it to NULL... or so my
theory goes.

currently in my header I declare my array like this:

Directory *Directories; // pointer to an array of Directories

and I had been instantiating it like this in my .cpp file:

Directories = new Directory[MaxSubDirs];

is there some way to automatically set the values to NULL? I can't loop
because it has already died by then. I need something in the order of
(of course this does not work)

Directories = new Directory[MaxSubDirs] = NULL;

I realize that I should be able to do the same thing with a linked
list, but I think that using the array will be faster (if it is
possible) due to the date the assignment is due.

Did I mention I am a student? I am a student.

Thanks.

Nov 28 '06 #1
Share this Question
Share on Google+
23 Replies


P: n/a
Oops. My subject is incorrect, I want to create a dynamic array of my
class Directory, within my class Directory.

Nov 28 '06 #2

P: n/a
sa***@murdocks.on.ca wrote:
I need (okay, I want) to make a dynamic array of my class 'Directory',
within my class Directory (Can you already smell disaster?)

Each Directory can have subdirectories so I thought to put these in an
array. The application compiles but aborts without giving me any useful
information.

What I suspect is happening is infinite recursion. Each Directory
object creates an array of Subdirectories each of which has an array of
sub-directorires...

I think it basically is recursively killing itself.

Is there some way to declare this array so that the values are NULL
initially? Thus (I think) doing away with the recursion problem. Then
as I add ACTUAL sub-directories it should work. As I delete
Sub-directories I take the array item and set it to NULL... or so my
theory goes.

currently in my header I declare my array like this:

Directory *Directories; // pointer to an array of Directories

and I had been instantiating it like this in my .cpp file:

Directories = new Directory[MaxSubDirs];

is there some way to automatically set the values to NULL? I can't loop
because it has already died by then. I need something in the order of
(of course this does not work)

Directories = new Directory[MaxSubDirs] = NULL;

I realize that I should be able to do the same thing with a linked
list, but I think that using the array will be faster (if it is
possible) due to the date the assignment is due.

Did I mention I am a student? I am a student.
Use std::vector, std::set or std::list:

class File;

class Directory
{
Directory& parent_;
std::string name_;
std::set<Filefiles_;
std::set<Directorysubdirs_;
public:
Directory( const Directory& parent, const std::string& name )
: parent_( parent )
, name_( name )
, files_()
, subdirs_()
{}

void AddDir( const std::string& name )
{
subdirs_.insert( Directory( *this, name ) );
}

// ...
};

Cheers! --M

Nov 28 '06 #3

P: n/a
sa***@murdocks.on.ca wrote:
I need (okay, I want) to make a dynamic array of my class 'Directory',
within my class Directory (Can you already smell disaster?)

Each Directory can have subdirectories so I thought to put these in an
array. The application compiles but aborts without giving me any
useful information.

What I suspect is happening is infinite recursion. Each Directory
object creates an array of Subdirectories each of which has an array
of sub-directorires...

I think it basically is recursively killing itself.

Is there some way to declare this array so that the values are NULL
initially? Thus (I think) doing away with the recursion problem. Then
as I add ACTUAL sub-directories it should work. As I delete
Sub-directories I take the array item and set it to NULL... or so my
theory goes.

currently in my header I declare my array like this:

Directory *Directories; // pointer to an array of Directories

and I had been instantiating it like this in my .cpp file:

Directories = new Directory[MaxSubDirs];

is there some way to automatically set the values to NULL? [..]
In the initialiser list:

... Directories(new Directory[MaxSubDirs]()) ...

And consider using std::vector instead, which can also be
initialised. Imagine that 'Directories' is declared as

std::vector<Directory*Directories;

then you do

... Directories(MaxSbDirs, (Directory*)NULL) ...

(although you don't really need that, vector can grow as
needed).

V
--
Please remove capital 'A's when replying by e-mail
I do not respond to top-posted replies, please don't ask
Nov 28 '06 #4

P: n/a
Thanks for the reply. I may have to try the vectors... we have only
discussed them in class, not used them.

Can you explain this a bit:

Directories(new Directory[MaxSubDirs]());

I tried it as is and got the error:
`((Directory*)this)->Directory::Directories' cannot be used as a
function

Obviously I don't understand what was meant.

Victor Bazarov wrote:
sa***@murdocks.on.ca wrote:
I need (okay, I want) to make a dynamic array of my class 'Directory',
within my class Directory (Can you already smell disaster?)

Each Directory can have subdirectories so I thought to put these in an
array. The application compiles but aborts without giving me any
useful information.

What I suspect is happening is infinite recursion. Each Directory
object creates an array of Subdirectories each of which has an array
of sub-directorires...

I think it basically is recursively killing itself.

Is there some way to declare this array so that the values are NULL
initially? Thus (I think) doing away with the recursion problem. Then
as I add ACTUAL sub-directories it should work. As I delete
Sub-directories I take the array item and set it to NULL... or so my
theory goes.

currently in my header I declare my array like this:

Directory *Directories; // pointer to an array of Directories

and I had been instantiating it like this in my .cpp file:

Directories = new Directory[MaxSubDirs];

is there some way to automatically set the values to NULL? [..]

In the initialiser list:

... Directories(new Directory[MaxSubDirs]()) ...

And consider using std::vector instead, which can also be
initialised. Imagine that 'Directories' is declared as

std::vector<Directory*Directories;

then you do

... Directories(MaxSbDirs, (Directory*)NULL) ...

(although you don't really need that, vector can grow as
needed).

V
--
Please remove capital 'A's when replying by e-mail
I do not respond to top-posted replies, please don't ask
Nov 29 '06 #5

P: n/a
* sa***@murdocks.on.ca:
[top-posting, overquoting]
Please don't -- read the FAQ -- corrected.
* sa***@murdocks.on.ca:
Thanks for the reply. I may have to try the vectors... we have only
discussed them in class, not used them.
Use them.

Can you explain this a bit:

Directories(new Directory[MaxSubDirs]());

I tried it as is and got the error:
`((Directory*)this)->Directory::Directories' cannot be used as a
function

Obviously I don't understand what was meant.
You have extranous parentheses, but don't try to correct this: use
std::vector.
--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
Nov 29 '06 #6

P: n/a

sa***@murdocks.on.ca wrote in message ...
>Thanks for the reply. I may have to try the vectors... we have only
discussed them in class, not used them.

Can you explain this a bit:

Directories(new Directory[MaxSubDirs]());

I tried it as is and got the error:
`((Directory*)this)->Directory::Directories' cannot be used as a
function

Obviously I don't understand what was meant.
I think Victor meant for you to use that *in* an initialiser list:

class Directory{
static const size_t MaxSubDirs = 5;
Directory *Directories; // pointer to an array of Directories
public:
// - like this -
Directory() : Directories( new Directory[ MaxSubDirs ]() ) {}

~Directory(){ delete[] Directories; }
};

Is that the way you tried it?

Go with the std::vector.

--
Bob R
POVrookie
Nov 29 '06 #7

P: n/a
Thanks for all your help.

I am still trying to figure this out... and maybe I will have to go
with a linked list. Hard to say.
Anyway:

In my header I have this in the private section:

vector<Directory*Directories; // pointer to an array of Directories

and in the cpp file I am trying this (and maybe I shouldn't... more to
follow):
Directories.resize[MaxSubDirs];

which will not compile:
invalid types `<unknown type>[unsigned int]' for array subscript

MaxSubDirs is an unsigned int in this case, but I have tried int as
well.

With regular arrays one of the issues is what to do when it gets full.
In order to save time, instead of adding one more slot at a time, we
use doubling. With Vector I have been reading and I am not clear.

When I push_back an item, it adds it to the vector and takes space from
the capacity. When capacity is reached does vector double itself? Add
1? Do I need to add functions to double the size of my vector the way I
do my arrays, not because it's the only way to make more space but
because it is more efficient (time wise) to add many slots at once?

Notice I have two questions there.

Thanks for your time.

Nov 29 '06 #8

P: n/a
* sa***@murdocks.on.ca:
Thanks for all your help.

I am still trying to figure this out... and maybe I will have to go
with a linked list. Hard to say.
Anyway:

In my header I have this in the private section:

vector<Directory*Directories; // pointer to an array of Directories
Make that

vector<Directorydirectories;

unless you're going to share those objects or use polymorphism.

But if you need pointers, use e.g.

typedef boost::shared_ptr<DirectoryDirectoryPtr;
typedef std::vector<DirectoryPtrDirectoryPtrs;

DirectoryPtrs directories;

so that object destruction is taken care of automatically.

and in the cpp file I am trying this (and maybe I shouldn't... more to
follow):
Directories.resize[MaxSubDirs];

which will not compile:
invalid types `<unknown type>[unsigned int]' for array subscript
Wrong kind of parenthesis.

MaxSubDirs is an unsigned int in this case, but I have tried int as
well.

With regular arrays one of the issues is what to do when it gets full.
In order to save time, instead of adding one more slot at a time, we
use doubling. With Vector I have been reading and I am not clear.
Guaranteed average O(1) for push_back, which essentially means (that
vector uses internal) doubling or some other factor to increase capacity
when exceeded.

--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
Nov 29 '06 #9

P: n/a

sa***@murdocks.on.ca wrote in message ...
>Thanks for all your help.

I am still trying to figure this out... and maybe I will have to go
with a linked list. Hard to say.
Anyway:
In my header I have this in the private section:

vector<Directory*Directories; // pointer to an array of Directories

and in the cpp file I am trying this (and maybe I shouldn't... more to
follow):
Directories.resize[MaxSubDirs];
What Alf said. Try this example, maybe it will clear some cobwebs.
( if it don't kill ya first.<G>).
[ BTW, please do not top-post. (ref: other posts of yours)]

// --------------------------
#include <iostream>
#include <ostream>
#include <vector>
// --------------------------
void PrintVec( std::vector<intconst &vec, std::ostream &sout){
sout<<" size="<<vec.size()<<" cap="<<vec.capacity()<<std::endl;
return;
} // PrintVec(vector<intconst&,ostream&)
// --------------------------
void VecIntSize( std::ostream &cout ){
cout<<"\n--- VecInt() size test ---"<<std::endl;
std::vector<intVecInt(10);
PrintVec( VecInt, cout);
VecInt.push_back( 1 );
PrintVec( VecInt, cout);
for(size_t i(0); i < 11; ++i){ VecInt.push_back( i );}
PrintVec( VecInt, cout);
VecInt.resize( 50 );
PrintVec( VecInt, cout);
VecInt.push_back( 1 );
PrintVec( VecInt, cout);
VecInt.resize( 40 );
PrintVec( VecInt, cout);
cout<<" std::vector<int>( ).swap( VecInt );"<<std::endl;
std::vector<int>( ).swap( VecInt );
PrintVec( VecInt, cout);
cout<<"--- VecInt() size test ---END"<<std::endl;
return;
}
// --------------------------

int main(){
VecIntSize( std::cout );

std::vector<doublevecD( 10, 3.14 ); // init 10 elements to 3.14.
for(size_t i(0); i < vecD.size(); ++i){
std::cout<<" vecD.at("<<i<<")= "
<<vecD.at( i )<<std::endl;
} // for(i)
vecD.clear();
std::cout<<" vecD.size()="<<vecD.size()<<std::endl;
std::cout<<" vecD.capacity()="<<vecD.capacity()<<std::endl;

{ // initialise with string array
std::string B[]={"001","2","we","the world"};
std::vector<std::stringvBstr( B, B+(sizeof B/sizeof *B) );
for(size_t i(0); i < vBstr.size(); ++i){
std::cout << vBstr.at( i ) <<std::endl;
}
} // initialise with string array - end

return 0;
} // main()

/* --- VecInt() size test --- (some output snipped)
size=10 cap=10
size=11 cap=20 // note cap doubled
size=22 cap=40 // note cap doubled
size=50 cap=50 // re-sized
size=51 cap=100 // note cap doubled.
size=40 cap=100 // note cap didn't shrink
size=0 cap=0 // a reset
--- VecInt() size test ---END
// run to see the other output.
*/
--
Bob R
POVrookie
Nov 29 '06 #10

P: n/a

BobR wrote:
sa***@murdocks.on.ca wrote in message ...
Thanks for all your help.

I am still trying to figure this out... and maybe I will have to go
with a linked list. Hard to say.
Anyway:
In my header I have this in the private section:

vector<Directory*Directories; // pointer to an array of Directories

and in the cpp file I am trying this (and maybe I shouldn't... more to
follow):
Directories.resize[MaxSubDirs];

What Alf said. Try this example, maybe it will clear some cobwebs.
( if it don't kill ya first.<G>).
[ BTW, please do not top-post. (ref: other posts of yours)]

// --------------------------
#include <iostream>
#include <ostream>
#include <vector>
// --------------------------
void PrintVec( std::vector<intconst &vec, std::ostream &sout){
sout<<" size="<<vec.size()<<" cap="<<vec.capacity()<<std::endl;
return;
} // PrintVec(vector<intconst&,ostream&)
// --------------------------
void VecIntSize( std::ostream &cout ){
cout<<"\n--- VecInt() size test ---"<<std::endl;
std::vector<intVecInt(10);
PrintVec( VecInt, cout);
VecInt.push_back( 1 );
PrintVec( VecInt, cout);
for(size_t i(0); i < 11; ++i){ VecInt.push_back( i );}
PrintVec( VecInt, cout);
VecInt.resize( 50 );
PrintVec( VecInt, cout);
VecInt.push_back( 1 );
PrintVec( VecInt, cout);
VecInt.resize( 40 );
PrintVec( VecInt, cout);
cout<<" std::vector<int>( ).swap( VecInt );"<<std::endl;
std::vector<int>( ).swap( VecInt );
PrintVec( VecInt, cout);
cout<<"--- VecInt() size test ---END"<<std::endl;
return;
}
// --------------------------

int main(){
VecIntSize( std::cout );

std::vector<doublevecD( 10, 3.14 ); // init 10 elements to 3.14.
for(size_t i(0); i < vecD.size(); ++i){
std::cout<<" vecD.at("<<i<<")= "
<<vecD.at( i )<<std::endl;
} // for(i)
vecD.clear();
std::cout<<" vecD.size()="<<vecD.size()<<std::endl;
std::cout<<" vecD.capacity()="<<vecD.capacity()<<std::endl;

{ // initialise with string array
std::string B[]={"001","2","we","the world"};
std::vector<std::stringvBstr( B, B+(sizeof B/sizeof *B) );
for(size_t i(0); i < vBstr.size(); ++i){
std::cout << vBstr.at( i ) <<std::endl;
}
} // initialise with string array - end

return 0;
} // main()

/* --- VecInt() size test --- (some output snipped)
size=10 cap=10
size=11 cap=20 // note cap doubled
size=22 cap=40 // note cap doubled
size=50 cap=50 // re-sized
size=51 cap=100 // note cap doubled.
size=40 cap=100 // note cap didn't shrink
size=0 cap=0 // a reset
--- VecInt() size test ---END
// run to see the other output.
*/
--
Bob R
POVrookie
I THINK I am inserting into my vector correctly; I am sure that I am
not getting back my data.

I did use a vector of pointers to my Directory class:

vector<Directory*Directories; // from my .h file

In my cpp I then had:
Directories.resize(0);

to insert into my vector I have this:

bool Directory::MKDir()
{
string DN; // directory name
int i; // a counter

//Get the name of the new file.
do
{
if(i 0)
{
cout << "Please enter a valid Directory name. No spaces and
must ";
cout << "not include a dot." << endl;
}

cout << "Enter directory name: ";
getline(cin, DN);

//Check to see if that Directory name is allowed
//ValidName = tmpFile->ValidName(FN);
i++;
}while(DN == "" ); //|| ValidName == false

Directory *ND = new Directory(NULL, DN);
Directories.push_back(ND);
NumSubDirs++;

}

I have tried the following to get access to the 'directory' after I
inserted it into my vector (I think)

/* for(int i = 0; i < Directories.size(); i++)
{
cout << Directories.at(i)->GetName() << " "; // << endl;
}
//Directory *D;
*/
/* for (vector<Directory*>::iterator i = Directories.begin(); i !=
Directories.end(); ++i)
{
D = new Directory *i
D.Print() << endl;
}*/

for(size_t i(0); i < Directories.size(); ++i){
std::cout<<" vecD.at("<<i<<")= "
<<Directories.at( i )->GetName()<<std::endl;
} // for(i)

they all compile, but they all crash when I try to use the loop to show
the names of the directories. I have two function associated that I
could use:
..Print() (which does a cout of the name)
..GetName() (which returns the name of the directory)

I am also going to need to sort this thing, so I really need access to
those data elements... well I guess that was a given! <g>.

Also about top-posting... do you mean typing my comments at the top of
the previous users comments? If so; I shall stop.

Thanks.

Nov 30 '06 #11

P: n/a

sa***@murdocks.on.ca wrote in message ...
>
I THINK I am inserting into my vector correctly; I am sure that I am
not getting back my data.
I did use a vector of pointers to my Directory class:

vector<Directory*Directories; // from my .h file
In your class, or at global scope?
>
In my cpp I then had:
Directories.resize(0);
You can just do:

Directories.clear();

.....to empty the vector. If you just created 'Directories', it isn't needed,
yet.
>
to insert into my vector I have this:

bool Directory::MKDir(){
string DN; // directory name
// int i; // a counter

Problem!! 'i' is not initialised, could be anything.
int i( 0 ); // a counter
// same result as int i = 0;
>
do{ //Get the name of the new file.
if( i 0 ){
// since 'i' was not initialised, it was more than likely
// not zero first pass thru loop.

// cout << "Please enter a valid Directory name."
// <<" No spaces and must "
// << "not include a dot." << endl;

cout << "Please enter a valid Directory name."
"\nNo spaces and must "
"not include a dot." <<std::endl;
// string literals concatenate. pretty trick, eh?

// You want this to print every loop except the first?
}

cout << "Enter directory name: ";
getline(cin, DN);

//Check to see if that Directory name is allowed
//ValidName = tmpFile->ValidName(FN);
i++;
}while(DN == "" ); //|| ValidName == false
// std::string.empty() returns true if the string is empty. So, you could do:

} while( DN.empty() ); //|| ValidName == false
>
Directory *ND = new Directory(NULL, DN);
Directories.push_back( ND );
// good.
NumSubDirs++;
} // Directory::MKDir()

I have tried the following to get access to the 'directory' after I
inserted it into my vector (I think)

/* for(int i = 0; i < Directories.size(); i++){
cout << Directories.at( i )->GetName() << " "; // << endl;
}
//Directory *D;
*/
/* for (vector<Directory*>::iterator i = Directories.begin(); i !=
Directories.end(); ++i ){
D = new Directory *i
D.Print() << endl;
}*/
/*
That last one is wrong. If you want to use iterators, do:
for( vector<Directory*>::iterator i = Directories.begin();
i != Directories.end(); ++i ){
(*i)->Print();
std::cout<<std::endl;
}
*/
>
for(size_t i(0); i < Directories.size(); ++i){
std::cout<<" Directories.at("<<i<<")= "
<<Directories.at( i )->GetName()<<std::endl;
} // for(i)
That should work. This is running inside the class (in a function), right?
(or is 'Directories' at global scope?)
>
they all compile, but they all crash when I try to use the loop to show
the names of the directories. I have two function associated that I
could use:
.Print() (which does a cout of the name)
.GetName() (which returns the name of the directory)
Lesson 83649: 'Crash' means many things. What was the last thing you saw? The
more information you give us, the quicker we can come up with a possible
solution.

Let's try something (I know you aren't ready, but, just copy/paste (delete
later)).

#include <stdexcept// for exception

{ // scope of your function (maybe in your class)/main()

try{
for(size_t i(0); i < Directories.size(); ++i){
std::cout<<" Directories.at("<<i<<")= "
<<Directories.at( i )->GetName()<<std::endl;
} // for(i)

} // try
catch( std::out_of_range &Oor ){
std::cerr<<" caught: "<<Oor.what()<<std::endl;
}
catch(...){
std::cerr<<" caught: some other error."<<std::endl;
}

} // scope of your function

Now, run your prog and see which "caught:" you get. This will help narrow
down the search for the bug.
May be a good idea to post your 'Directory' class (and the definitions for
'Print' and 'GetName', if not inline in the class).
>
I am also going to need to sort this thing, so I really need access to
those data elements... well I guess that was a given! <g>.
Piece of cake, but, one thing at a time. Find bug first<beats chest like
Tarzan>!!
>
Also about top-posting... do you mean typing my comments at the top of
the previous users comments? If so; I shall stop.
Thanks.
This post was better. Next, trim (delete) old post that you do not need for
your reply ( like notice that I cut out your text from prior post and my code
which we are done with).

--
Bob R
POVrookie
Nov 30 '06 #12

P: n/a
vector<Directory*Directories; // from my .h file
>
In your class, or at global scope?
I am doing this in the private section of my .h file
>

In my cpp I then had:
Directories.resize(0);

You can just do:

Directories.clear();
I have done that AND discovered that one of my constructors used 0 and
one used 1! I never (really) got to see your code work. When I ran it
here's what happened (some conjecture some fact).

My directory object was created, setting my vector resize (1) (two
slots) I added 1 directory. I then used my 'dir' command to list the
files and directories. The program immediately launched a popup asking
me to open my visual studio as a debugger (I am writing in Dev C++).

The first error I saw pop up was:
Unhandled exception at 0x00434b78 in COSC202H_Ass3.exe: 0xC0000005:
Access violation reading location 0x00000000.

when I pressed continue it would just keep popping back the same error.
(That isn't what your catch does is it? I expected a cout on the
screen.)

Eventually I hit break and this line was highlighted:
00434B78 mov eax,dword ptr [eax]
which of course means NOTHING to me. HOWEVER I did find that by fixing
my constructor using the method you suggested: Directories.clear(); the
problem was fixed.

DOH!
to insert into my vector I have this:

bool Directory::MKDir(){
string DN; // directory name
// int i; // a counter

Problem!! 'i' is not initialised, could be anything.
int i( 0 ); // a counter
// same result as int i = 0;
Thanks. Fixed it. It worked but at some point could have blown up I am
sure.
cout << "Please enter a valid Directory name."
"\nNo spaces and must "
"not include a dot." <<std::endl;
// string literals concatenate. pretty trick, eh?

// You want this to print every loop except the first?
Yes. The idea is you create one 'directory' at a time. If you want to
make more than one you (from the menu/screen) type mkdir again and go
through the process. If you are looping it means your first attempt did
not provide a valid name. (error checking is not in place yet).

cout << "Enter directory name: ";
getline(cin, DN);

//Check to see if that Directory name is allowed
//ValidName = tmpFile->ValidName(FN);
i++;
}while(DN == "" ); //|| ValidName == false

// std::string.empty() returns true if the string is empty. So, you could do:

} while( DN.empty() ); //|| ValidName == false
Thanks.
That last one is wrong. If you want to use iterators, do:
for( vector<Directory*>::iterator i = Directories.begin();
i != Directories.end(); ++i ){
(*i)->Print();
std::cout<<std::endl;
}
*/
That should work. This is running inside the class (in a function), right?
(or is 'Directories' at global scope?)
Believe it or not it's inside my directories class. From a directory
(object) you can create another directory (object) which is a child of
the creator (subdirectory). At this point it's all still theory. ;)
Lesson 83649: 'Crash' means many things. What was the last thing you saw? The
more information you give us, the quicker we can come up with a possible
solution.
It would list my files (from a prior loop listing files) then launch
visual studio to debug (see above).
>
Let's try something (I know you aren't ready, but, just copy/paste (delete
later)).

#include <stdexcept// for exception

{ // scope of your function (maybe in your class)/main()

try{
for(size_t i(0); i < Directories.size(); ++i){
std::cout<<" Directories.at("<<i<<")= "
<<Directories.at( i )->GetName()<<std::endl;
} // for(i)

} // try
catch( std::out_of_range &Oor ){
std::cerr<<" caught: "<<Oor.what()<<std::endl;
}
catch(...){
std::cerr<<" caught: some other error."<<std::endl;
}

} // scope of your function

Now, run your prog and see which "caught:" you get. This will help narrow
down the search for the bug.
May be a good idea to post your 'Directory' class (and the definitions for
'Print' and 'GetName', if not inline in the class).
okay, here is my .h file:

***************************************
#ifndef Directory_h
#define Directory_h

#include <cstdlib>
#include <iostream>
#include <string>
#include "File.h"
#include <vector>

//using namespace std;

class Directory
{
private:
string Name; // Name of the Directory
unsigned int NumSubDirs, NumFiles, MaxSubDirs, MaxFiles;
int Level;
File *Files; //Pointer to an array of Files
vector<Directory*Directories; // vector to pointers to
directories
//vector<Directory*>::iterator iter;

Directory *Parent; // pointer to this directories parent dir

/*
DoubleDirectories

Input: Directories (array)
Output: None

Note: Double the size of the Directories array. Initially all
arrays will start at 5 (just because).
*/
void DoubleDirectories();

/*
DoubleFiles

Input: Files (array)
Output: None

Note: Double the size of the Files Array. Initially all
arrays will start at 5 (just because).
*/
void DoubleFiles();

/*
ClearFiles

Input: None
Output: None

Note: Used to delete all Files from the directory.
*/
void ClearFiles();

/*
ClearDirectories

Input: None
Output: None

Note: Used to delete all sub-directories from this directory.
*/
void ClearDirectories();

/*
FindFile

Input: Array of Files, first position, last position key.
Output: Int (position in the array of the item if found,
otherwise
-1)
*/
int FindFile(File sortedArray[], int first, int last,
string key);

public:

/*
Constructor

Input: None
Output: None

Note: Create a new Directory object which is empty.
*/
Directory();

/*
Constructor

Input: N (directory name)
Output: None

Note: Creates a new empty Directory named Name
*/
Directory(Directory *Parent, string N);

/*
Empty

Input: None
Output: Bool

Note: Used to check to see if the directory is empty. A directory
is empty if it has no files and no subdirectories.
}
*/
bool Empty();

/*
Insert

Input: CF (Current file)
Output: bool

Note: Will return false if the file cannot be inserted into
the directory. This will occur if the filename is already
in
use.
*/
bool Insert(File CF);

/*
MKFile (make file)

Input: Filename
Output: bool

Note: Used to prompt for input to create a file, then uses
Insert
to insert the file into the files array.
*/
bool MKFile();

/*
Remove

Input: FN (File name)
Output: bool

Note: Will remove a file from the directory if it can be
found.
Will return false if the file was not found.
*/
bool Remove(string FN);

/*
Create

Input: Dir (Subdirectory)
Output: bool

Note: Will attempt to add a subdirectory to this directory.
Returns
false if this cannot be done (duplicate).
*/
bool Create(Directory Dir);

bool MKDir();

/*
Delete

Input: DN (Directory Name)
Output: None

Note: Used to delete a subdirectory and all of it's
contents.
*/
bool Delete(string DN);

bool Delete();

bool DeleteFile(int i);

/*
Move

Input: DN (Directory Name)
Output: bool

Note: Will move to the parent directory (..) or a
subdirectory
as required. Returns true or false for success. Asking
for
parent of the root will return false. Asking for a subdir
where it cannot be found will return false.
*/
bool Move(string DN);

/*
Print

Input: None
Output: bool

Note: Will print the contents of this directory(files) and ALL
SUBDIRECTORIES. Uses the property Level to determin how
many characters to indent before each line of output.

will return false if there is nothing to print.
*/
void Print();

/*
SMPrint (Small Print)

Input: None
Output: None

Note: Prints only the content of the current directory and
not
of any subdirectories.
*/
void SMPrint();

/*
GetNumFiles

Input: None
Output: None
*/
int GetNumFiles();
void insertionSort ( File A [ ], int low, int high );
inline void Directory::swap ( File & x, File & y );
/*
QuickSort

*/
void FilesQuickSort ( File A [ ], int low, int high );

/*
FindFile
*/
int FindFile(File sortedArray[], int first, int last, int
key);

/*
GetFileCount
*/
int FileCount();

/*
FindFile

Input: F (File)
Output: bool

Note: will find a file matching the file passed in will return
true if found.
*/
bool FileExists(File &F);

string GetName();

};

#endif
*********************************

here is my .cpp file:

#include "Directory.h"
#include <stdexcept// for exception

//#include <iostream>
//#include <cstdlib>
//#include <string>

/*
Constructor
*/
Directory::Directory()
{
Name = "";
NumSubDirs = 0;
NumFiles = 0;
MaxSubDirs = 5;
MaxFiles = 5;
Level = -1;

//Directories.resize(MaxSubDirs){NULL};
Directories.clear();
//Directories.push_back(new Directory);
Files = new File[MaxFiles];
}

Directory::Directory(Directory *Parent, string N)
{
Name = N;
NumSubDirs = 0;
NumFiles = 0;
MaxSubDirs = 5;
MaxFiles = 5;
Level = -1;

Directories.clear();
Files = new File[MaxFiles];
}

/*
DoubleFiles (Double array file size)
*/
void Directory::DoubleFiles()
{
File * OldArray = Files;
Files = new File[MaxFiles * 2];
for(int i = 0; i <= MaxFiles -1; i++)
{
Files[i] = new File(OldArray[i].GetFileName());
}

delete [] OldArray;

MaxFiles = MaxFiles * 2;
}

//Empty()
bool Directory::Empty()
{
if(NumSubDirs == 0 && NumFiles == 0)
return true;
else
return false;
}

//MKFile()
bool Directory::MKFile()
{
string FN; //File name
//system("cls"); // clear screen
int i = 0;
bool ValidName = false;
File *tmpFile = new File;

//Get the name of the new file.
do
{
if(i 0)
{
cout << "Please enter a valid file name. No spaces and must ";
cout << "include a dot." << endl;
}

cout << "Enter file name: ";
getline(cin, FN);

//Check to see if that file name is allowed
ValidName = tmpFile->ValidName(FN);
i++;
}while(FN.empty() || ValidName == false);

if(NumFiles 0 && FindFile(Files, 0, NumFiles, FN)< 0)
{
// this would be a unique file
Files[NumFiles] = tmpFile;
if(NumFiles == MaxFiles -1)
{
DoubleFiles(); // double the size of the files array
}
NumFiles++;
}
else if(NumFiles == 0)
{
// this would be a unique file
Files[NumFiles] = tmpFile;
if(NumFiles == MaxFiles -1)
{
DoubleFiles(); // double the size of the files array
}
NumFiles++;
}
else
{
// Error checking
//cout << "NumFiles: " << NumFiles << endl;
//cout << "FindFiles = " << FindFile(Files, 0, NumFiles, FN);
delete tmpFile;
cout << "** Error: File already exists. Aborted." << endl;
system("PAUSE");
}
}

bool Directory::MKDir()
{
string DN; // directory name
int i = 0; // a counter

//Get the name of the new file.
do
{
if(i 0)
{
cout << "Please enter a valid Directory name. No spaces and
must ";
cout << "not include a dot." << endl;
}

cout << "Enter directory name: ";
getline(cin, DN);

//Check to see if that Directory name is allowed
//ValidName = tmpFile->ValidName(FN);
i++;
}while(DN.empty()); //|| ValidName == false

Directory *ND = new Directory(NULL, DN);
Directories.push_back(ND);
NumSubDirs++;

}
bool Directory::Delete()
{
int index, i;
string Item;
bool result;

system("cls");

//SMPrint();

do
{
if(i 0)
{
cout << "Enter the name of the item you wish to delete: " <<
endl;
cout << "->";
}
getline(cin, Item);

i++;
}while(Item == "");

//search for a file with that name
index = FindFile(Files, 0, NumFiles, Item);

//cout << "FindFile index = " << index << endl;

if(index -1)
{
result = DeleteFile(index);
cout << "Deleted." << endl;
system("PAUSE");
}

}

bool Directory::DeleteFile(int i)
{
int j;

//create a new array and copy all elements to it except the one to be
// deleted
File * OldArray = Files;
*Files = new File[MaxFiles];
for(j = 0; j <= NumFiles -1; j++)
{
//cout << "j = " << j << endl;
if(j < i)
{
Files[j] = new File(OldArray[j].GetFileName());
//cout << "Moved " << OldArray[j].GetFileName() << " to Files"
<< endl;
}
else
{
Files[j] = new File(OldArray[j+1].GetFileName());
//cout << "Moved " << OldArray[j+1].GetFileName() << " to
Files" << endl;
}
}
NumFiles--; //decriment NumFiles
delete [] OldArray;

return true;
}
//GetNumFiles
int Directory::GetNumFiles()
{
return NumFiles;
}

//SMPrint (Small Print)
void Directory::SMPrint()
{
FilesQuickSort (Files, 0, NumFiles -1 );
for(int i = 0; i <= NumFiles -1; i++)
{
Files[i].Print();
cout << endl;
}

try{
for(size_t i(0); i < Directories.size(); ++i)
{
std::cout<<" Directories.at("<<i<<")= " <<Directories.at( i
)->GetName()<<std::endl;
} // for(i)
} // try
catch( std::out_of_range &Oor )
{
std::cerr<<" caught: "<<Oor.what()<<std::endl;
}
catch(...){
std::cerr<<" caught: some other error."<<std::endl;
}
}

void Directory::insertionSort ( File A [ ], int low, int high )
{
for ( int p = low+1; p <= high; p++ )
{
File tmp = A [ p ];
int j;

for ( j = p; j low && tmp < A [ j-1 ]; j-- )
A [ j ] = A [ j-1 ];

A [ j ] = tmp;
}
}

inline void Directory::swap ( File & x, File & y )
{
File temp = x;
x = y;
y = temp;
}

//QuickSort
// Best and average case time complexity of quickSort : O(n log n )
// Worst case time complexity of quickSort : O(n^2)
void Directory::FilesQuickSort ( File A [ ], int low, int high )
{
if ( low + 10 high )
insertionSort ( A, low, high );
else
{
// Sort low, middle and high
int middle = ( low + high ) / 2;
if ( A [ middle ] < A [ low ] )
swap ( A [ low ], A [ middle ] );

if ( A [ high ] < A [ low ] )
swap ( A [ low ], A [ high ] );

if ( A [ high ] < A [ middle ] )
swap ( A [ middle ], A [ high ] );

// Place pivot at position high - 1
File pivot = A [ middle ];
swap ( A [ middle ], A [ high-1 ] );

// Partition around the pivot
int i, j;
for ( i = low, j = high-1; ; )
{
while ( A [ ++i ] < pivot ) { }
while ( pivot < A [ --j ] ) { }
if ( i < j )
swap ( A [ i ], A [ j ] );
else
break;
}

swap ( A [ i ], A [ high-1 ] );

FilesQuickSort ( A, low, i-1 );
FilesQuickSort ( A, i+1, high );
}
}

/*
FindFile
*/

int Directory::FindFile(File sortedArray[], int first, int last, string
key)
{
while (first <= last) {
int mid = (first + last) / 2; // compute mid point.
if (sortedArray[mid] < key)
first = mid + 1; // repeat search in top half.
else if (sortedArray[mid] key)
last = mid - 1; // repeat search in bottom half.
else
return mid; // found it. return position /////
}
return -(first + 1); // failed to find key
}

int Directory::FileCount()
{
return NumFiles;
}

bool Directory::FileExists(File &F)
{
if(FindFile(Files, 0, NumFiles, F.GetFileName()) -1)
return true;
else
return false;
}

string Directory::GetName()
{
return Name;
}

void Directory::Print()
{
cout << Name;
}
*******************************************

I am also going to need to sort this thing, so I really need access to
those data elements... well I guess that was a given! <g>.

Piece of cake, but, one thing at a time. Find bug first<beats chest like
Tarzan>!!

Also about top-posting... do you mean typing my comments at the top of
the previous users comments? If so; I shall stop.
Thanks.

This post was better. Next, trim (delete) old post that you do not need for
your reply ( like notice that I cut out your text from prior post and my code
which we are done with).

--
Bob R
POVrookie
Thanks for all the time and effort.

I'd particularly like to get that try catch working. I asked about it
in class but was told that isn't taught in this class (or the one
prior). I'd like it not so much for throwing errors, but to catch all
the weird input that I didn't expect and be able to recover with a 'hey
dummy type something that makes sense' kind of message!

;) Thanks again.

Nov 30 '06 #13

P: n/a

sa***@murdocks.on.ca wrote in message ...
>Access violation reading location 0x00000000.
Look for a pointer that was never set to anything.
>
I'd particularly like to get that try catch working. I asked about it
in class but was told that isn't taught in this class (or the one
prior). I'd like it not so much for throwing errors, but to catch all
the weird input that I didn't expect and be able to recover with a 'hey
dummy type something that makes sense' kind of message!
I'll check out your code in a little bit[1]. Thought I'd throw(pun) you a
bone in the meantime.

Get "Thinking in C++", 2nd ed. Volume 1&2 by Bruce Eckel
(available for free here. You can buy it in hardcopy too.):
http://www.mindview.net/Books/TICPP/...ngInCPP2e.html

In Vol 2, Part 1, there is a chapter on 'Exception Handling'. Some of it may
be over your head, but, he gives enough examples that you should be able to
figure it out.

Be aware that the way you(we) want to use exceptions is a slightly improper
use. However, I have found it a useful tool for narrowing down a problem area
(bug hunting) while developing new code. Normally, you would only use
exceptions to handle situations that can't be delt with in normal program
flow.

At a top level, you can do:

int main(){
using std::cerr;
using std::endl;
try{
// your code here
if( true ){ throw "Help Me!!";}
} // try
catch( std::bad_alloc const &ba ){
cerr << "Out of memory! " << ba.what() << endl;
}
catch( std::runtime_error const &re ){
cerr << re.what() << endl;
}
catch( char const *r_e ){ // catch "Help Me!!"
cerr<<"error: " << r_e << endl;
}
// as many catch() clauses as you need
catch(...){ // a 'catch all'
cerr << "caught something not caught above" << endl;
}
return 0;
} // main()
Also, I noticed you said something about 'Dev-C++'. It defaults to
MinGW(GCC). If you build a debug version of your program (using -g switch, or
one of it's variants), and then jump to the ms debugger, you may get false
information. If you build with GCC, you should use 'gdb' (the GCC debugger).
I don't know if 'Insight' is still alive. It was a nice front-end for gdb and
worked nice wirh Dev-C++. Maybe 'Google' for it if interested (there was a
link on the Bloodshed site).

I'll get back to you on your Directory class (if one of the experts in this
NG don't 'correct' it first).

[1] - first pass through I think I spotted some potential problems. Need to
check it out more so I don't send you down the wrong path.
--
Bob R
POVrookie
Nov 30 '06 #14

P: n/a

sa***@murdocks.on.ca wrote in message ...
>
I never (really) got to see your code work. When I ran it
here's what happened (some conjecture some fact).

My directory object was created, setting my vector resize (1) (two
slots)
One 'slot', index 0. As soon as you push_back() once, the max valid index
goes to 1 ( so now you have 0 and 1).
I added 1 directory. I then used my 'dir' command to list the
files and directories. The program immediately launched a popup asking
me to open my visual studio as a debugger (I am writing in Dev C++).

OK, I can't be sure yet, but I think your one of your problems is with
'FilesQuickSort()'.
Comment that out of your program temporarily (read below first).

I don't know what is in your "File.h".

< just a thought >
Now, here is a bigger problem. You use a pointer to a dynamic allocated array
('*Files'). If you do anything that needs to copy the Directory class object
(std containers use copy constructor), the default copy constructor just
copies the pointer, no new allocation takes place. That's is a big problem,
all the copies are trying (could be) to work on the same realestate. That may
be the problem in 'FilesQuickSort()'.
Rule Of Three (or two, if you use smart pointers)!

Let's do a test:

class Directory{
private:

// Prevent assignment and copy-construction:
Directory( Directory const & ); // just this, don't define it.
void operator=( Directory const & );

// rest of your class
}; // class Directory

Now, try to compile it. Work? ( it should not ).

A little side note: a class defaults to 'private', so you don't need to put
'private:' at the very top of your class.
class Directory{
// this part is private
public:
// this part is public
private:
// this part is private again
}; // class Directory

Your class also needs a destructor that will clean up 'Files'. As is, you
have a memory leak.

Directory::~Directory(){
delete[] Files;
// and since your vector holds pointers to 'new' objects.
for( size_t i(0); i < Directories.size(); ++i ){
delete Directories.at( i );
}
} // Dtor

If the vector held actual objects, it would do all the cleanup for you.

Your book should have something on copy constructors and assignment
operators.
( If not, 'Thinking in C++' vol 1 does. )

>when I pressed continue it would just keep popping back the same error.
( ** That isn't what your catch does is it? ** I expected a cout on the
screen.)
No. If it got to 'catch(...)', it would have put a message on crt.
(but not everything gets caught by that)
If you had put the FilesQuickSort() call inside the try{}, you may have seen
a message. Try it and see (may give another clue).
>*********************************
here is my .cpp file:

#include "Directory.h"
#include <stdexcept// for exception

//#include <iostream>
//#include <cstdlib>
//#include <string>

/* Constructor */
Directory::Directory(){
Name = "";
NumSubDirs = 0;
NumFiles = 0;
MaxSubDirs = 5;
MaxFiles = 5;
Level = -1;

//Directories.resize(MaxSubDirs){NULL};
Directories.clear();
//Directories.push_back(new Directory);
Files = new File[MaxFiles];
}
Unless your instructor expressly prohibited it, you should learn to use
'initialiser lists'.

Directory::Directory() : // put a colon there
Name( "" ), // a coma after all but last
NumSubDirs( 0 ),
NumFiles( 0 ),
MaxSubDirs( 5 ),
MaxFiles( 5 ),
Level( -1 )// no coma
{
Directories.clear();
Files = new File[MaxFiles];
} // Directory Ctor default

>/* DoubleFiles (Double array file size) */
void Directory::DoubleFiles(){
File * OldArray = Files;
Files = new File[MaxFiles * 2];
for(int i = 0; i <= MaxFiles -1; i++){
Files[i] = new File(OldArray[i].GetFileName());
}
delete [] OldArray;
MaxFiles = MaxFiles * 2;
}
If you also make 'Files' a std::vector, you won't need things like
'DoubleFiles()'.
>//Empty()
If std::vector<FileFiles, just:
if( Files.empty() ){ /* do whatever */ }
>//GetNumFiles
Files.size()

std::sort( Files.begin(), Files.end() );
// but, you may need to write a 'predicate' to sort the way you want.
// dependes on what 'File' is.

std::unique( Files.begin(), Files.end() ); // remove dups.
// but, you may need to write a 'predicate'.
// dependes on what 'File' is.

Starting to see the value of the std containers and library?

>void Directory::insertionSort ( File A [ ], int low, int high ){
if( ( low < 0 ) || ( high MaxFiles ) ){ return; }

Murphy's laws: If more than one thing can go wrong, the one that will go
wrong is the one that will do the most damage!
for ( int p = low+1; p <= high; p++ ){
File tmp = A [ p ];
int j;

for ( j = p; j low && tmp < A [ j-1 ]; j-- )
A [ j ] = A [ j-1 ];

A [ j ] = tmp;
}
}
*******************************************
Work on those things a little, and come back.

Nobody ever said C++ was easy! Hang in there!
--
Bob R
POVrookie
Dec 1 '06 #15

P: n/a

BobR wrote:
sa***@murdocks.on.ca wrote in message ...

OK, I can't be sure yet, but I think your one of your problems is with
'FilesQuickSort()'.
Comment that out of your program temporarily (read below first).
Actually my QuickSort works. I had to overload operators for it to do
so, but it seems to be fine.
I don't know what is in your "File.h".

< just a thought >
Now, here is a bigger problem. You use a pointer to a dynamic allocated array
('*Files'). If you do anything that needs to copy the Directory class object
(std containers use copy constructor), the default copy constructor just
copies the pointer, no new allocation takes place. That's is a big problem,
all the copies are trying (could be) to work on the same realestate. That may
be the problem in 'FilesQuickSort()'.
Rule Of Three (or two, if you use smart pointers)!
I know. And I think the destructor is going to be a pain too. I think I
will have to loop through the array and delete each pointer to each
file.

The problem that this solves? is that I need to be able to 'loop' and
create a new object multiple times. I don't know how to do that except
with a pointer; as in
x = new file.

Also if I 'hard-coded' file x, then it would go out of scope and be
deleted at the end of the function even if I put it into a public array
would it not?
Let's do a test:

class Directory{
private:

// Prevent assignment and copy-construction:
Directory( Directory const & ); // just this, don't define it.
void operator=( Directory const & );

// rest of your class
}; // class Directory

Now, try to compile it. Work? ( it should not ).
Umm... it did work actually. Here is the 'new' header:
************************************************** *********

#ifndef Directory_h
#define Directory_h

#include <cstdlib>
#include <iostream>
#include <string>
#include "File.h"
#include <vector>

//using namespace std;
class Directory{
private:
// Prevent assignment and copy-construction:
Directory( Directory const & ); // just this, don't define it.
void operator=( Directory const & );

/*
class Directory
{
private: */
string Name; // Name of the Directory
unsigned int NumSubDirs, NumFiles, MaxSubDirs, MaxFiles;
int Level;
File *Files; //Pointer to an array of Files
vector<Directory*Directories; // vector to pointers to
directories
//vector<Directory*>::iterator iter;

Directory *Parent; // pointer to this directories parent dir

/*
DoubleDirectories

Input: Directories (array)
Output: None

Note: Double the size of the Directories array. Initially all
arrays will start at 5 (just because).
*/
void DoubleDirectories();

/*
DoubleFiles

Input: Files (array)
Output: None

Note: Double the size of the Files Array. Initially all
arrays will start at 5 (just because).
*/
void DoubleFiles();

/*
ClearFiles

Input: None
Output: None

Note: Used to delete all Files from the directory.
*/
void ClearFiles();

/*
ClearDirectories

Input: None
Output: None

Note: Used to delete all sub-directories from this directory.
*/
void ClearDirectories();

/*
FindFile

Input: Array of Files, first position, last position key.
Output: Int (position in the array of the item if found,
otherwise
-1)
*/
int FindFile(File sortedArray[], int first, int last,
string key);

public:

/*
Constructor

Input: None
Output: None

Note: Create a new Directory object which is empty.
*/
Directory();

/*
Constructor

Input: N (directory name)
Output: None

Note: Creates a new empty Directory named Name
*/
Directory(Directory *Parent, string N);

/*
Empty

Input: None
Output: Bool

Note: Used to check to see if the directory is empty. A directory
is empty if it has no files and no subdirectories.
}
*/
bool Empty();

/*
Operator ==

Inputs: string D (directory name)
Output: bool

Note: Used to detect if a directory name matches a string.
For example, two Directories of the same parent cannot
have the same name.
*/
bool operator==(const string &D);

/*
operator <

Inputs: Directory D
Outputs: bool

Notes: Used to determine if the NAME of the directory is
less than (before) the one compared.
*/
bool operator<(const Directory & D); //Note to self pointer to
D???

/*
operator <

Inputs: DN (Directory name)
Outputs: bool

Notes: If the Directory name is < the 'other' Directory name True.
*/
bool operator<(string DN);

/*
operator >

Inputs: Directory D
Outputs: bool

Note: Used to determine if the NAME of the directory is greater
than the other.
*/
bool operator>(const Directory & D);

/*
operator >

Inputs: DN (string file name)
Outputs: bool

Note: Uses a string value to compare a string to the NAME
of the directory.
*/
bool operator>(string DN);

/*
Insert

Input: CF (Current file)
Output: bool

Note: Will return false if the file cannot be inserted into
the directory. This will occur if the filename is already
in
use.
*/
bool Insert(File CF);

/*
MKFile (make file)

Input: Filename
Output: bool

Note: Used to prompt for input to create a file, then uses
Insert
to insert the file into the files array.
*/
bool MKFile();

/*
Remove

Input: FN (File name)
Output: bool

Note: Will remove a file from the directory if it can be
found.
Will return false if the file was not found.
*/
bool Remove(string FN);

/*
Create

Input: Dir (Subdirectory)
Output: bool

Note: Will attempt to add a subdirectory to this directory.
Returns
false if this cannot be done (duplicate).
*/
bool Create(string Dir);

bool MKDir();

/*
Delete

Input: DN (Directory Name)
Output: None

Note: Used to delete a subdirectory and all of it's
contents.
*/
bool Delete(string DN);

bool Delete();

bool DeleteFile(int i);

/*
Move

Input: DN (Directory Name)
Output: bool

Note: Will move to the parent directory (..) or a
subdirectory
as required. Returns true or false for success. Asking
for
parent of the root will return false. Asking for a subdir
where it cannot be found will return false.
*/
bool Move(string DN);

/*
Print

Input: None
Output: bool

Note: Will print the contents of this directory(files) and ALL
SUBDIRECTORIES. Uses the property Level to determin how
many characters to indent before each line of output.

will return false if there is nothing to print.
*/
void Print();

/*
SMPrint (Small Print)

Input: None
Output: None

Note: Prints only the content of the current directory and
not
of any subdirectories.
*/
void SMPrint();

/*
GetNumFiles

Input: None
Output: None
*/
int GetNumFiles();
void insertionSort ( File A [ ], int low, int high );
//void insertionSort (vector<Directory*A, int low, int
high);

inline void swap ( File & x, File & y );
//inline void swap (Directory & x, Directory & y);
/*
QuickSort

*/
void QuickSort ( File A [ ], int low, int high );
//void QuickSort (vector<DirectoryA, int low, int high);

/*
FindFile
*/
int FindFile(File sortedArray[], int first, int last, int
key);

/*
GetFileCount
*/
int FileCount();

/*
FindFile

Input: F (File)
Output: bool

Note: will find a file matching the file passed in will return
true if found.
*/
bool FileExists(File &F);

string GetName();

};

#endif

**********************************************
>
A little side note: a class defaults to 'private', so you don't need to put
'private:' at the very top of your class.
class Directory{
// this part is private
public:
// this part is public
private:
// this part is private again
}; // class Directory
The prof is big on seeing those words though. It does make it clearer
too.
Your class also needs a destructor that will clean up 'Files'. As is, you
have a memory leak.
Yup. A big nasty one. I will have to loop through and delete each File
from the array, then the array. Big pain, but I think that's the point.
;)
Directory::~Directory(){
delete[] Files;
// and since your vector holds pointers to 'new' objects.
for( size_t i(0); i < Directories.size(); ++i ){
delete Directories.at( i );
}
} // Dtor
If the vector held actual objects, it would do all the cleanup for you.
How can I dynamically create actual objects though? They do go out of
scope at the end of the function don't they?
If you had put the FilesQuickSort() call inside the try{}, you may have seen
a message. Try it and see (may give another clue).
I think the old bug is quite fixed. I have been using it for a while
with no problem, even adding subdirectories. The QuickSort works for my
Files (putting them in alphabetical order).

The sort for the vector however does not seem to. In fact I cannot see
it changing anything.

I added code to read a comma delimited file with a bunch of random
words in it. I use that to create directories (who wants to type all
that!) the vector sort is given at the end of each addition, I then
list the directory and the files come back out in the order they went
in.

My suspicion is that they are sorted by the pointer, not the thing
pointed to. I am looking at that but....
>
here is the new cpp file, it has changed a little to accomodate things
like automated directory addition.

*********************************
#include "Directory.h"
#include <stdexcept// for exception

//#include <iostream>
//#include <cstdlib>
//#include <string>

/*
Constructor
*/
Directory::Directory()
{
Name = "";
NumSubDirs = 0;
NumFiles = 0;
MaxSubDirs = 5;
MaxFiles = 5;
Level = -1;

//Directories.resize(MaxSubDirs){NULL};
Directories.clear();
//Directories.push_back(new Directory);
Files = new File[MaxFiles];
}

Directory::Directory(Directory *Parent, string N)
{
Name = N;
NumSubDirs = 0;
NumFiles = 0;
MaxSubDirs = 5;
MaxFiles = 5;
Level = -1;

Directories.clear();
Files = new File[MaxFiles];
}

/*
operator==
*/
bool Directory::operator==(const string & D)
{
if(Name != D)
return false;
else
return true;
}

bool Directory::operator<(const Directory & D)
{
// both names are strings so this should work.
//if the Directory Name is >, then false
if(Name D.Name)
return false;

//if the Directory Name is <, then true
if(Name < D.Name)
return true;
}

/*
operator>
*/
bool Directory::operator>(const Directory & D)
{
if(Name < D.Name)
return false;

if(Name D.Name)
return true;
}
/*
DoubleFiles (Double array file size)
*/
void Directory::DoubleFiles()
{
File * OldArray = Files;
Files = new File[MaxFiles * 2];
for(int i = 0; i <= MaxFiles -1; i++)
{
Files[i] = new File(OldArray[i].GetFileName());
}

delete [] OldArray;

MaxFiles = MaxFiles * 2;
}

//Empty()
bool Directory::Empty()
{
if(NumSubDirs == 0 && NumFiles == 0)
return true;
else
return false;
}

//MKFile()
bool Directory::MKFile()
{
string FN; //File name
//system("cls"); // clear screen
int i = 0;
bool ValidName = false;
File *tmpFile = new File;

//Get the name of the new file.
do
{
if(i 0)
{
cout << "Please enter a valid file name. No spaces and must ";
cout << "include a dot." << endl;
}

cout << "Enter file name: ";
getline(cin, FN);

//Check to see if that file name is allowed
ValidName = tmpFile->ValidName(FN);
i++;
}while(FN.empty() || ValidName == false);

if(NumFiles 0 && FindFile(Files, 0, NumFiles, FN)< 0)
{
// this would be a unique file
Files[NumFiles] = tmpFile;
if(NumFiles == MaxFiles -1)
{
DoubleFiles(); // double the size of the files array
}
NumFiles++;
QuickSort (Files, 0, NumFiles -1 );
}
else if(NumFiles == 0)
{
// this would be a unique file
Files[NumFiles] = tmpFile;
if(NumFiles == MaxFiles -1)
{
DoubleFiles(); // double the size of the files array
}
NumFiles++;
}
else
{
// Error checking
//cout << "NumFiles: " << NumFiles << endl;
//cout << "FindFiles = " << FindFile(Files, 0, NumFiles, FN);
delete tmpFile;
cout << "** Error: File already exists. Aborted." << endl;
system("PAUSE");
}
}

bool Directory::MKDir()
{
string DN; // directory name
int i = 0; // a counter
bool result;

//Get the name of the new file.
do
{
if(i 0)
{
cout << "Please enter a valid Directory name. No spaces and
must ";
cout << "not include a dot." << endl;
}

cout << "Enter directory name: ";
getline(cin, DN);

//Check to see if that Directory name is allowed
//ValidName = tmpFile->ValidName(FN);
i++;
}while(DN.empty()); //|| ValidName == false

//create the directory
result = Create(DN);
}

bool Directory::Create(string DN)
{
Directory *ND = new Directory(this, DN);
Directories.push_back(ND);
NumSubDirs++;

std::sort(Directories.begin(), Directories.end());
return true;
}

bool Directory::Delete()
{
int index, i;
string Item;
bool result;

system("cls");

//SMPrint();

do
{
if(i 0)
{
cout << "Enter the name of the item you wish to delete: " <<
endl;
cout << "->";
}
getline(cin, Item);

i++;
}while(Item == "");

//search for a file with that name
index = FindFile(Files, 0, NumFiles, Item);

//cout << "FindFile index = " << index << endl;

if(index -1)
{
result = DeleteFile(index);
cout << "Deleted." << endl;
system("PAUSE");
}

}

bool Directory::DeleteFile(int i)
{
int j;

//create a new array and copy all elements to it except the one to be
// deleted
File * OldArray = Files;
*Files = new File[MaxFiles];
for(j = 0; j <= NumFiles -1; j++)
{
//cout << "j = " << j << endl;
if(j < i)
{
Files[j] = new File(OldArray[j].GetFileName());
//cout << "Moved " << OldArray[j].GetFileName() << " to Files"
<< endl;
}
else
{
Files[j] = new File(OldArray[j+1].GetFileName());
//cout << "Moved " << OldArray[j+1].GetFileName() << " to
Files" << endl;
}
}
NumFiles--; //decriment NumFiles
delete [] OldArray;

return true;
}
//GetNumFiles
int Directory::GetNumFiles()
{
return NumFiles;
}

//SMPrint (Small Print)
void Directory::SMPrint()
{
//cout << NumFiles;
if( NumFiles 0)
{
for(int i = 0; i <= NumFiles -1; i++)
{
Files[i].Print();
cout << endl;
}
}

if(Directories.size() 0)
{
try
{
for(size_t i(0); i < Directories.size(); ++i)
{
cout << Directories.at( i )->GetName()<< endl;
} // for(i)
} // try
catch( std::out_of_range &Oor )
{
std::cerr<<" caught: "<<Oor.what()<<std::endl;
}
catch(...)
{
std::cerr<<" caught: some other error."<<std::endl;
}
}

cout << NumFiles << " Files and " << Directories.size() << "
Directories" << endl;
}

void Directory::insertionSort ( File A [ ], int low, int high )
{
for ( int p = low+1; p <= high; p++ )
{
File tmp = A [ p ];
int j;

for ( j = p; j low && tmp < A [ j-1 ]; j-- )
A [ j ] = A [ j-1 ];

A [ j ] = tmp;
}
}

/*
void Directory::insertionSort ( vector<Directory*A , int low, int
high )
{
for ( int p = low+1; p <= high; p++ )
{
Directory *tmp = A [ p ];
int j;

for ( j = p; j low && tmp < A [ j-1 ]; j-- )
A [ j ] = A [ j-1 ];

A [ j ] = tmp;
}
}
*/
inline void Directory::swap ( File & x, File & y )
{
File temp = x;
x = y;
y = temp;
}
/*
inline void Directory::swap (Directory &x, Directory &y)
{
Directory temp = x;
x = y;
y = temp;
}
*/

//QuickSort
// Best and average case time complexity of quickSort : O(n log n )
// Worst case time complexity of quickSort : O(n^2)
//QuickSort
// Best and average case time complexity of quickSort : O(n log n )
// Worst case time complexity of quickSort : O(n^2)
void Directory::QuickSort ( File A [ ], int low, int high )
{
if ( low + 10 high )
insertionSort ( A, low, high );
else
{
// Sort low, middle and high
int middle = ( low + high ) / 2;
if ( A [ middle ] < A [ low ] )
swap ( A [ low ], A [ middle ] );

if ( A [ high ] < A [ low ] )
swap ( A [ low ], A [ high ] );

if ( A [ high ] < A [ middle ] )
swap ( A [ middle ], A [ high ] );

// Place pivot at position high - 1
File pivot = A [ middle ];
swap ( A [ middle ], A [ high-1 ] );

// Partition around the pivot
int i, j;
for ( i = low, j = high-1; ; )
{
while ( A [ ++i ] < pivot ) { }
while ( pivot < A [ --j ] ) { }
if ( i < j )
swap ( A [ i ], A [ j ] );
else
break;
}

swap ( A [ i ], A [ high-1 ] );

QuickSort ( A, low, i-1 );
QuickSort ( A, i+1, high );
}
}

/*
FindFile
*/

int Directory::FindFile(File sortedArray[], int first, int last, string
key)
{
while (first <= last) {
int mid = (first + last) / 2; // compute mid point.
if (sortedArray[mid] < key)
first = mid + 1; // repeat search in top half.
else if (sortedArray[mid] key)
last = mid - 1; // repeat search in bottom half.
else
return mid; // found it. return position /////
}
return -(first + 1); // failed to find key
}

int Directory::FileCount()
{
return NumFiles;
}

bool Directory::FileExists(File &F)
{
if(FindFile(Files, 0, NumFiles, F.GetFileName()) -1)
return true;
else
return false;
}

string Directory::GetName()
{
return Name;
}

void Directory::Print()
{
cout << Name;
}

************************************************

Not that I want to over do it, but here's the 'controlling' app called
FileSystem:

header:
************************************************
#ifndef FileSystem_h
#define FileSystem_h

#include <cstdlib>
#include <iostream>
#include <string>
#include "Directory.h"

using namespace std;

class FileSystem
{
private:
Directory *CurrentDir, *RootDir;

public:

/*
constructor
*/
FileSystem();

/*
Destructor
*/
~FileSystem();

/*
main

inputs: none
outputs: none

Note: used start the application process.
*/
void main();

/*
mkdir

inputs: none
output: none

Note: used to make a new sub-directory of the current directory.
*/
void mkdir();

/*
mkfile

input: none
output: none

Note: used to make a new file
*/
void mkfile();

/*
del

input: none
output: none

Note: used to delete BOTH files and directories. Will search for a

matching file, if none is found will search for a directory
to delete.
*/
void del();

/*
dir

input: none
output: none

Note: used to list the contents of the current directory.
*/
void dir();

/*
move

input: none
output: none

Note: used to either move to the parent directory or to a subdir.
*/
void move();

/*
print

input: none
output: none

Note: used to list the contents of the current directory and
subdirectories.
*/
void print();

/*
count

intput: none
output: none

Note: used to return a count of all of the files in the system
from the current directory to it's lowest child.
*/
void count();

/*
help

input: none
output: none

Note: Help
*/
void help();

/*
ShowCursor

input: none
output: none

Note: creates the cursor (->) on the screen.
*/
void ShowCursor();

/*
toupper

input: string
output: string

Note: I found that toupper only works for characters, so I wrote
one for strings. (WHY ISN"T THERE ONE???)
*/
string toupper(string S);
/******************** used for testing ********/
// loads an array from a text file
void openInFile();

// list test array contents
void ListTestArray();

void FileSystem::TestMakeDirs()

};

#endif
******************************************

Code:

*******************************************

#include "FileSystem.h"
#include <iostream>
#include <cstdlib>
#include <string>
#include <iomanip>
#include <fstream>
// An array used for testing only
int AS = 50; //Size of Array, Array Size
int CS = 0; // current size (in use)
string Words[50];
using namespace std;

FileSystem::FileSystem()
{
RootDir = new Directory(NULL, "/");
CurrentDir = RootDir;
}

FileSystem::~FileSystem()
{

}
void FileSystem::ShowCursor()
{
cout << "-";
}

void FileSystem::help()
{
cout << "The following commands are available." << endl;

cout << "COUNT";
cout.width(10);
cout << "DEL";
cout.width(10);
cout << "DIR";
cout.width(10);
cout << "HELP";
cout << endl;
cout << "MKDIR";
cout.width(10);
cout << "MKFILE";
cout.width(10);
cout << "MOVE";
cout.width(10);
cout << "PRINT";
cout << endl;
cout << "QUIT" << endl << "Type 'HELP' to see this list again.";
cout << endl;
}

void FileSystem::main()
{
string command;
help();
//ShowCursor();
//getline(cin, command);

do
{
ShowCursor();
getline(cin, command);
command = toupper(command);

//Can't use switch with a string... if then else I guess...
// help menu
if(command == "HELP")
{
system("cls");
help();
} // make a file
else if(command == "MKFILE")
{
system("cls");
CurrentDir->MKFile();
} // make a directory
else if(command == "MKDIR")
{
system("cls");
CurrentDir->MKDir();
} // show files and subdirs for current directory
else if(command == "DIR")
{
system("cls");
CurrentDir->SMPrint();
} // delete (a file or directory)
else if(command == "DEL")
{
system("cls");
CurrentDir->Delete();
} // Quit
else if(command == "QUIT")
{
system("cls");
cout << "Quiting" << endl;
}
else if (command == "LOADARRAY")
{
openInFile();
}
else if(command == "SHOWARRAY")
{
ListTestArray();
}
else if(command == "TESTMKDIR")
{
TestMakeDirs();
}
else
{
cout << "Un-recognized command" << endl;
}

}while(command != "QUIT");
}
string FileSystem::toupper(string S)
{
for (int j=0; j<S.length(); ++j)
{
S[j]=std::toupper(S[j]);
}

return S;
}
/************************ Code for Testing only ********/
void FileSystem::openInFile()
{
int charLoc;

string currentWords;
CS = 0;
//bool newLine = false;

// open the input file Input.txt
ifstream inFile("Input.txt");
// if the file failed to open, notify the user.
if(inFile.is_open())
{
getline(inFile, currentWords);
if(currentWords.empty() == false)
{
do
{
charLoc = currentWords.find(",");
Words[CS] = currentWords.substr(0, charLoc);
currentWords = currentWords.substr(charLoc + 1,
currentWords.length());
CS++;
}while(CS < AS && currentWords.length() 3);

}
/* // as long as there is a 'word' to read from the file, loop.
while(inFile >currentWord && CS < AS -1)
{

cout << currentWord;
CS++;
} */

// Close the input file
inFile.close();
}
else //if the file did open, process the file.
{
cout << "error opening file";
}
}

void FileSystem::ListTestArray()
{
system("cls");
for(int i = 0; i < CS; i++)
{
cout << i << " " << Words[i] << endl;
}
system("PAUSE");
system("cls");
}

void FileSystem::TestMakeDirs()
{
//load the array with random words
openInFile();
if(CS 0)
{
// make a directory for each random word
for(int i = 0; i <=CS; i++)
{
cout << "Creating dir: " << Words[i] << endl;
CurrentDir->Create(Words[i]);
}
}
// display the directories and files
CurrentDir->SMPrint();
}

************************************

File header:

**************************************

#ifndef File_h
#define File_h

#include <cstdlib>
#include <iostream>
#include <string>

//using namespace std;

class File
{

private:
std::string Name, Extension;

/*
SplitName

Inputs: FN (String)
Output: None

Notes: Used to split a string based on the '.' character. This
allows the Name and Extension to be found.
*/
void SplitName(string FN);

public:

/*
Constructor

Inputs: FullName
Outputs: None

Notes: Takes in the full name (name + extension) splits it.
*/
File(string FullName);

/*
Constructor

Inputs: FullName
Outputs: None

Notes: Takes in the full name (name + extension) splits it.
*/
File();

/*
Copy Constructor
Due to the requirement that no files in the same directory can
have
the same name, and the fact there is no copy required for this
assignment the copy constructor is not required.
*/

/*
Copy Assignment

Inputs: F (file)
Outputs: bool
*/
bool operator=(const File *F);
File & File::operator=(const File & F);

/*
Destructor
Because there are no pointers used the default destructor is
fine.
No destructor was created for 'file'
*/

/*
GetName

Inputs: None
Outputs Name (minus extension)
*/
string GetName();

/*
GetExtension

Inputs: None
Outputs: File Extension
*/
string GetExtension();

/*
GetFileName

Inputs: None
Output: full file name (name and extension)
*/
string GetFileName();

/*
Print

Inputs: None
Outputs: prints to screen full file name (name and extension)
*/
void Print();

/*
operator ==

Inputs: File F
Outputs: bool

Notes: If the file.Name and file.Extension are equal the files
are equal if either is not equal, the files are not equal.
*/
bool operator==(const File & F);

/*
operator==

Input: FN (string file name)
Output: bool

Notes: returns true if the file uses the same name as FN
*/
bool operator==(string FN);

/*
operator <

Inputs: File F
Outputs: bool

Notes: If the full file name is < the 'other' file name True.
*/
bool operator<(const File & F);

/*
operator <

Inputs: FN (string file name)
Outputs: bool

Notes: If the full file name is < the 'other' file name True.
*/
bool operator<(string FN);

/*
operator >

Inputs: File F
Outputs: bool
*/
bool operator>(const File & F);

/*
operator >

Inputs: FN (string file name)
Outputs: bool
*/
bool operator>(string FN);

/*
ValidName

Input: N (name)
Output: bool

Note: used to determine if a name is valid for a file.
No spaces and a dot.
*/
bool ValidName(string &N);
};

#endif
************************

File Code:

****************************

#include "File.h"
#include <iostream>
#include <cstdlib>
#include <string>

//using namespace std;

/*
Constructor
*/
File::File(string FullName)
{
SplitName(FullName);
}

File::File()
{
Name = "";
Extension = "";
}

//GetFileName
string File::GetFileName()
{
return (Name + "." + Extension);
}

// Copy Assignment
bool File::operator=(const File *F)
{
if(F->Name != "" && F->Extension != "")
{
Name = F->Name;
Extension = F->Extension;

return true;
}
else
return false;
}

File & File::operator=(const File & F)
{
if(F.Name != "" && F.Extension != "")
{
Name = F.Name;
Extension = F.Extension;
}
}

/*
SplitName
*/
void File::SplitName(string FN)
{
int charLoc; // character location
charLoc = FN.find('.');

// if there is no 'dot' then the Name is the Fullname (no extension)
if(charLoc == -1)
{
Name = FN;
Extension = "";
}
else //There is a dot so set the Name and Extension values
{
Name = FN.substr(0, charLoc);
Extension = FN.substr(charLoc + 1, FN.length());
}
}

bool File::ValidName(string &N)
{
int charLoc; // character location
SplitName(N);

// there must be a 'name' portion
if(Name == "")
return false;

if(Extension == "")
return false;

charLoc = N.find(' '); // search for a space in the name anywhere
if(charLoc == -1) // no spaces
return true;
else
return false;
}

/*
GetName
*/
string File::GetName()
{
return Name;
}

/*
GetExtension
*/
string File::GetExtension()
{
return Extension;
}

/*
Print
*/
void File::Print()
{
cout << Name << '.' << Extension;
}

/*
operator==
*/
bool File::operator==(const File & F)
{
if(Name != F.Name)
return false;

if(Extension != F.Extension)
{
return false;
}
else
{
return true;
}
}
/*
operator<
*/
bool File::operator<(const File & F)
{

//if the file Name is >, then false
if(Name F.Name)
return false;

//if the file Name is <, then true
if(Name < F.Name)
return true;

//if we got to here then the file Name properties are equal
if(Extension < F.Extension) // this extension is < other, then
true
{
return true;
}
else // this extension is NOT < other, then false
{
return false;
}
}

bool File::operator<(string FN)
{
if(GetFileName() FN)
return false;

if(GetFileName() == FN)
return false;

if(GetFileName() < FN)
return true;
}
/*
operator>
*/
bool File::operator>(const File & F)
{
if(Name < F.Name)
return false;

if(Name F.Name)
return true;

// if we got to here the names are equal
if(Extension F.Extension)
return true;
else
return false;
}

bool File::operator>(string FN)
{
if(GetFileName() < FN)
return false;

if(GetFileName() == FN)
return false;

if(GetFileName() FN)
return true;
}
**************************

Main:

******************************

#include <cstdlib>
#include <iostream>
//#include "File.h"
//#include "Directory.h"
#include "FileSystem.h"

using namespace std;

int main(int argc, char *argv[])
{
/*string FN;
Directory dir("/");
bool result;

for(int i = 0; i <= 6; i++)
{
result = dir.MKFile();
}
dir.SMPrint();
*/
FileSystem FS;
FS.main();

// cout << "Find a file position; enter file name: ";
//getline(cin, FN);
//dir.FindFile(dir.Files, 0, dir.FileCount -1);
system("PAUSE");
return EXIT_SUCCESS;
}
**************************

Oh; a comment on the std:: - the teaching assistant seems to favour NOT
using std:: so that's the way I will go for now. He's got to mark it.
Best to keep it to what he likes.

By the way... are you independantly wealthy or just very generous with
your time?? ;)

Also; is there a way to get the system to email me if there is a reply?
Work on those things a little, and come back.

Nobody ever said C++ was easy! Hang in there!
--
Bob R
POVrookie
Dec 1 '06 #16

P: n/a

sa***@murdocks.on.ca wrote:
BobR wrote:
Directory::~Directory(){
delete[] Files;
// and since your vector holds pointers to 'new' objects.
for( size_t i(0); i < Directories.size(); ++i ){
delete Directories.at( i );
}
} // Dtor
This one is much shorter.

I have noticed in code on the net a lot of people use 'size_t' with
their vector. Is that a specific command or is it the same as: for(int
i = 0; i < Directories.size(); i++)

if so, why do people use the size_t?

(I used int i and it SEEMS to work)

Dec 1 '06 #17

P: n/a

sa***@murdocks.on.ca wrote in message ...
>
>BobR wrote:
Directory::~Directory(){
delete[] Files;
// and since your vector holds pointers to 'new' objects.
for( size_t i(0); i < Directories.size(); ++i ){
delete Directories.at( i );
}
} // Dtor

This one is much shorter.
Checking out your other post. It'll get shorter. Post later.
>
I have noticed in code on the net a lot of people use 'size_t' with
their vector. Is that a specific command or is it the same as: for(int
i = 0; i < Directories.size(); i++)

if so, why do people use the size_t?
std::size_t is a typedef of an unsigned integral. std::vector::size_type
(returned by .size() ) is also an unsigned type.
>
(I used int i and it SEEMS to work)
You don't have your compiler warning level up high enough or you would be
seeing warnings like "comparing signed with unsigned". Why compare red dogs
with blue dogs?
If you are using Dev-C++(MinGW), put -Wall -W in the compiler flags.
(many more in the GCC docs "GCC Command Options" sub"Options to Request or
Suppress Warnings".).

Are you brave?
{
int sz(-1);
std::vector<intBigV( sz );

std::cout<<BigV.size();
} // don't want to keep that puppy around long!

--
Bob R
POVrookie
Dec 1 '06 #18

P: n/a

BobR wrote:
sa***@murdocks.on.ca wrote in message ...
BobR wrote:
Directory::~Directory(){
delete[] Files;
// and since your vector holds pointers to 'new' objects.
for( size_t i(0); i < Directories.size(); ++i ){
delete Directories.at( i );
}
} // Dtor
Actually I had envisioned having to write something that would make
calls on each sub-directory and it's subdirectories etc. to cascade
through calling the destructor; but of course I don't. Since this
destroys an instance of a Directory, that destruction calls that
instance's destructor. It is pretty simple. (much better than what I
had thought.)

I tend to try to get my code working first, then try to figure out the
destructors etc. I sort of 'build as I need' for things like copy
constructors etc. Then if I run out of time I can hand in a working
program with problems, not a non-working program.

This one is much shorter.
Yes; I have started some of that myself already. My overloaded
operators are now shorter, those based on string compares are now just
like this:

bool Directory::operator<(const Directory & D)
{
return Name < D.Name;

}

rather than with if then statements etc.
>
Checking out your other post. It'll get shorter. Post later.

I have noticed in code on the net a lot of people use 'size_t' with
their vector. Is that a specific command or is it the same as: for(int
i = 0; i < Directories.size(); i++)

if so, why do people use the size_t?

std::size_t is a typedef of an unsigned integral. std::vector::size_type
(returned by .size() ) is also an unsigned type.
Hmmm... Okay. I will stick with the convention.

(I used int i and it SEEMS to work)

You don't have your compiler warning level up high enough or you would be
seeing warnings like "comparing signed with unsigned". Why compare red dogs
with blue dogs?
If you are using Dev-C++(MinGW), put -Wall -W in the compiler flags.
(many more in the GCC docs "GCC Command Options" sub"Options to Request or
Suppress Warnings".).

Are you brave?
{
int sz(-1);
std::vector<intBigV( sz );

std::cout<<BigV.size();
} // don't want to keep that puppy around long!

--
Bob R
POVrookie
Dec 1 '06 #19

P: n/a

Just wanted to let you know that I created a new, shorter specific
posting about sorting the vector elsewhere.

Sort a Vector of Pointers to an object, based on objects properties

It wasn't really this topic/thread even though it's still my problem.

I think that was the correct thing to do!

Dec 1 '06 #20

P: n/a

sa***@murdocks.on.ca wrote in message ...
>
BobR wrote:
>>
Actually my QuickSort works. I had to overload operators for it to do
so, but it seems to be fine.
OK. Eliminated another 'possible'.

I'll snip most of your code below to reduce bandwith, but, I'll check it out
later.

>>
< just a thought >
ref: copy constructor
Rule Of Three (or two, if you use smart pointers)!

I know. And I think the destructor is going to be a pain too. I think I
will have to loop through the array and delete each pointer to each
file.
I don't think it will be too bad. I'll show you a little 'helper' further
down.
>
The problem that this solves? is that I need to be able to 'loop' and
create a new object multiple times. I don't know how to do that except
with a pointer; as in
x = new file.

Also if I 'hard-coded' file x, then it would go out of scope and be
deleted at the end of the function even if I put it into a public array
would it not?
That's what I was drifting toward. A std::vector can hold objects, but then
you would definitely need a proper copy constructor (assuming you are still
using (an array of) pointers.

>
>Let's do a test:

class Directory{
private:
// Prevent assignment and copy-construction:
Directory( Directory const & ); // just this, don't define it.
void operator=( Directory const & );
// rest of your class
}; // class Directory
Now, try to compile it. Work? ( it should not ).

Umm... it did work actually. Here is the 'new' header:
OK, nothing so far requires the copy constructor or assignment. Clean.
>************************************************* **********
#ifndef Directory_h
class Directory{ private:
// Prevent assignment and copy-construction:
Directory( Directory const & ); // just this, don't define it.
void operator=( Directory const & );

string Name; // Name of the Directory
unsigned int NumSubDirs, NumFiles, MaxSubDirs, MaxFiles;
int Level;
File *Files; //Pointer to an array of Files
vector<File*vFiles;

If you do it like this (different name), you can develop it in parallel with
your existing code (just an idea).
vector<Directory*Directories; // vector to pointers to directories

Directory *Parent; // pointer to this directories parent dir
I haven't finished reviewing your code, but I don't remember seeing this
used.
Directory(Directory *Parent, string N);
Parent?
>};
#endif
**********************************************
>>
A little side note: a class defaults to 'private', so you don't need to
put 'private:' at the very top of your class.
class Directory{
// this part is private
public:
// this part is public
private:
// this part is private again
}; // class Directory

The prof is big on seeing those words though. It does make it clearer too.
So it's your(his) 'style' choice. That's fine. I'd say 'documentation', but
that
would be more typeing, and save nothing. Just so you know it.
>
>Your class also needs a destructor that will clean up 'Files'. As is, you
have a memory leak.

Yup. A big nasty one. I will have to loop through and delete each File
from the array, then the array. Big pain, but I think that's the point.
;)
Here's that 'helper' I mentioned.

template<class Seqvoid EmptyThis( Seq &con ){
for( class Seq::iterator i( con.begin() ); i != con.end(); ++i ){
delete *i;
*i = 0; // in case it gets called again
}
} //template<class Seqvoid EmptyThis(Seq&)
>Directory::~Directory(){
delete[] Files;
// and since your vector holds pointers to 'new' objects.
// > for( size_t i(0); i < Directories.size(); ++i ){
// > delete Directories.at( i );
// > }

EmptyThis( Directories );
> } // Dtor
Yeah, I know, "I can't use templates!!". Well, your stuck using 'concrete'
functions then.

void EmptyThis( std::vector<Directory*&con ){
for( std::vector<Directory*>::iterator i( con.begin() );
i != con.end(); ++i ){
delete *i;
*i = 0; // in case it gets called again
}
} // EmptyThis( std::vector<Directory*&)

If you put that in class, you won't need the '*i=0' since you will call it
from the destructor, and when the destructor us done the object no longer
exists.
Using the template version, and vector vFiles, you could have used it like:

EmptyThis( vFiles );
EmptyThis( Directories );

No biggie, what ever you choose to use.

>
>If the vector held actual objects, it would do all the cleanup for you.
How can I dynamically create actual objects though? They do go out of
scope at the end of the function don't they?
That's where the copy constructor comes into play. When you push_back(), it
makes a copy of the object. So, there's no problem when the temp disappears.

>
The sort for the vector however does not seem to. In fact I cannot see
it changing anything.
I added code to read a comma delimited file with a bunch of random
words in it. I use that to create directories (who wants to type all
that!) the vector sort is given at the end of each addition, I then
list the directory and the files come back out in the order they went
in.
Good. You could also use an std::istringstream to simulate input.

std::istringstream scin("word word2 morewords etc.\n anotherword\n");
std::string temp;
scin >temp;

Your way is fine, just pointing out another option.
(would save a file open)
>
My suspicion is that they are sorted by the pointer, not the thing
pointed to. I am looking at that but....
Correct. I forgot for a minute (good excuse, eh.) that it was a container of
pointers. But, I did mention that 'predicate' may be needed (nice save, eh?
<G>).

That might look something like:
bool predicate(const Directory *X, const Directory *Y)
{ return ( (*X)->name < (*Y)->name); }

std::sort( Directories.begin(), Directories.end(), predicate);

[ I don't have much practice with 'predicates', so, that may need some
adjustments. <G]
If you want to go that way, and have trouble, just start a new thread on that
subject. Some of the experts in this NG are really good at that (predicates).
>
here is the new cpp file, it has changed a little to accomodate things
like automated directory addition.
*********************************
[snip]
>
Directory::Directory(Directory *Parent, string N){
Directory *Parent?
Name = N;
NumSubDirs = 0;
NumFiles = 0;
MaxSubDirs = 5;
MaxFiles = 5;
Level = -1;
Directories.clear();
Files = new File[MaxFiles];
}

/* operator== */
bool Directory::operator==(const string & D){
if(Name != D)
return false;
else
return true;
}
bool Directory::operator==(const string &D){
return ( Name == D );
}
Another point, It could have been:
bool Directory::operator==(const string & D){
if(Name != D)
return false; // it leaves the function.
return true;
}

>
bool Directory::operator<(const Directory & D){
// both names are strings so this should work.
//if the Directory Name is >, then false
if(Name D.Name)
return false;
//if the Directory Name is <, then true
if(Name < D.Name)
return true;
}
You could simplify it:

bool Directory::operator<( Directory const &D ){
// both names are strings so this should work.
return ( Name < D.Name );
}

Inside the if()s, you are resolving an expression to a bool, and then
returning true or false upon the condition. Eliminate the middle man
( if() ).
>
//Empty()
bool Directory::Empty(){
if(NumSubDirs == 0 && NumFiles == 0)
return true;
else
return false;
}
bool Directory::Empty(){
return ( (NumSubDirs == 0) && (NumFiles == 0) );
}
// etc.
>*********************************************** *

Oh; a comment on the std:: - the teaching assistant seems to favour NOT
using std:: so that's the way I will go for now. He's got to mark it.
Best to keep it to what he likes.
Well, ya gotta kiss-up or lose the grade! The more you code, the more you'll
develop your own style. Hopefully you'll lose the bad habits, and develop
good ones after you *pass* the course.
>
By the way... are you independantly wealthy or just very generous with
your time?? ;)
Neither! Unemployed (due to partial disability, and staying off welfare
(anybody out there have a home freelance C++ programming job for me? <G$1 a
kloc?)). My favorite computer games are Adventure. C++ is like playing them,
I like problem solving/puzzles.
>
Also; is there a way to get the system to email me if there is a reply?
I've seen things like that in GNU/Linux, but never been interested enough to
investigate. win98 is the last ms thing I'll use, If my next machine build
won't run win98, I'll go pure Debian GNU/Linux. Maybe ask on an ms NG.
[ anybody else out there hard core enough to do a Linux kernel using g++
3.x.x (4.x?) ?]
[ ...and yeah, it works.]
--
Bob R
POVrookie
Dec 1 '06 #21

P: n/a

sa***@murdocks.on.ca wrote in message ...
>
Just wanted to let you know that I created a new, shorter specific
posting about sorting the vector elsewhere.

Sort a Vector of Pointers to an object, based on objects properties

It wasn't really this topic/thread even though it's still my problem.

I think that was the correct thing to do!
Yeah, I just saw that thread when I posted a reply to your other post. I even
suggested that in the post. I'll check it out now.

--
Bob R
POVrookie
Dec 1 '06 #22

P: n/a

BobR wrote:
The problem that this solves? is that I need to be able to 'loop' and
create a new object multiple times. I don't know how to do that except
with a pointer; as in
x = new file.

Also if I 'hard-coded' file x, then it would go out of scope and be
deleted at the end of the function even if I put it into a public array
would it not?

That's what I was drifting toward. A std::vector can hold objects, but then
you would definitely need a proper copy constructor (assuming you are still
using (an array of) pointers.
The copy constructor (I think) would be difficult. I'd have to be able
to copy the object (directory) and all the sub-directories in the
Vector which as directory objects, could have directory Vectors which
could have...

Oh man. My brain is going to explode!
vector<File*vFiles;
I'd prefer to leave my files alone for now. They seem to work. It's
just that vector that's driving me nuts now.
>
Directory(Directory *Parent, string N);

Parent?
I haven't used it yet. 'Above' my directory class is a 'FileSystem'
class. It doesn't do much right now. It has the menu that calls the
functions in Directory and it has a pointer to the root (the first
directory) and the current directory.

My theory is that as I create new directory objects I store the address
of the parent. Then when I need to do: cd.. to go up a level, from the
FileSystem class I can access the Parent address of the current
directory and re-set my FileSystem current directory to that. Then all
calls from the FileSystem will go to the new 'Current' directory which
was the parent of old 'Current' directory.

Here's that 'helper' I mentioned.

template<class Seqvoid EmptyThis( Seq &con ){
for( class Seq::iterator i( con.begin() ); i != con.end(); ++i ){
delete *i;
*i = 0; // in case it gets called again
}
} //template<class Seqvoid EmptyThis(Seq&)
Directory::~Directory(){
delete[] Files;
// and since your vector holds pointers to 'new' objects.
// > for( size_t i(0); i < Directories.size(); ++i ){
// > delete Directories.at( i );
// > }

EmptyThis( Directories );
} // Dtor

Yeah, I know, "I can't use templates!!". Well, your stuck using 'concrete'
functions then.
Actually I didn't know I couldn't use templates. I would have had
problems and just figured it was me not using correct syntax. (Which I
guess it would be).
void EmptyThis( std::vector<Directory*&con ){
for( std::vector<Directory*>::iterator i( con.begin() );
i != con.end(); ++i ){
delete *i;
*i = 0; // in case it gets called again
}
} // EmptyThis( std::vector<Directory*&)
This doesn't do it??

Directory::~Directory()
{
//delete the array of files
delete Files;
// delete each directory pointer from the vector
for(size_t i(0) ; i < Directories.size(); ++i )
{
delete Directories.at( i );
}
}
If you put that in class, you won't need the '*i=0' since you will call it
from the destructor, and when the destructor us done the object no longer
exists.
Using the template version, and vector vFiles, you could have used it like:

EmptyThis( vFiles );
EmptyThis( Directories );

No biggie, what ever you choose to use.

If the vector held actual objects, it would do all the cleanup for you.
How can I dynamically create actual objects though? They do go out of
scope at the end of the function don't they?

That's where the copy constructor comes into play. When you push_back(), it
makes a copy of the object. So, there's no problem when the temp disappears.


The sort for the vector however does not seem to. In fact I cannot see
it changing anything.
I added code to read a comma delimited file with a bunch of random
words in it. I use that to create directories (who wants to type all
that!) the vector sort is given at the end of each addition, I then
list the directory and the files come back out in the order they went
in.

Good. You could also use an std::istringstream to simulate input.

std::istringstream scin("word word2 morewords etc.\n anotherword\n");
std::string temp;
scin >temp;

Your way is fine, just pointing out another option.
(would save a file open)

My suspicion is that they are sorted by the pointer, not the thing
pointed to. I am looking at that but....

Correct. I forgot for a minute (good excuse, eh.) that it was a container of
pointers. But, I did mention that 'predicate' may be needed (nice save, eh?
<G>).

That might look something like:
bool predicate(const Directory *X, const Directory *Y)
{ return ( (*X)->name < (*Y)->name); }

std::sort( Directories.begin(), Directories.end(), predicate);

[ I don't have much practice with 'predicates', so, that may need some
adjustments. <G]
If you want to go that way, and have trouble, just start a new thread on that
subject. Some of the experts in this NG are really good at that (predicates).
Thanks I did. I tried something that looked like what you have but got
errors... It wasn't exact though...

It was a struct.

your line: return ( (*X)->name < (*Y)->name);
I converted to this: return ( *X->GetName() < *Y->GetName());
because name is private.

It gives the error:
passing `const Directory' as `this' argument of `std::string
Directory::GetName()' discards qualifiers

so I tried this:
return ( X->GetName() < Y->GetName());
to get this
passing `const Directory' as `this' argument of `std::string
Directory::GetName()' discards qualifiers

and this:
return ( (*X)->GetName() < (*Y)->GetName());
which resulted in this
base operand of `->' has non-pointer type `const Directory'

I have posted it in a smaller posting in the group for that one
problem. Hopefully someone gets back to me.

bool Directory::Empty(){
return ( (NumSubDirs == 0) && (NumFiles == 0) );
}
// etc.
Bob R
POVrookie
Thanks for all your help. Believe it or not I am learning a lot from
this assignment and the pain it is causing me! ;)

I have to continue and get this thing working even if it doesn't sort
properly but if I complete the rest in time and still can't do it any
otherway I may try to convert a quick sort for the vector.

It's all about time. Due date is am Monday so I can only do what I can
do! ;)

Dec 1 '06 #23

P: n/a

sa***@murdocks.on.ca wrote in message ...
>
BobR wrote:
>
Also if I 'hard-coded' file x, then it would go out of scope and be
deleted at the end of the function even if I put it into a public array
would it not?

That's what I was drifting toward. A std::vector can hold objects, but
then
>you would definitely need a proper copy constructor (assuming you are
still
>using (an array of) pointers.

The copy constructor (I think) would be difficult. I'd have to be able
to copy the object (directory) and all the sub-directories in the
Vector which as directory objects, could have directory Vectors which
could have...

Oh man. My brain is going to explode!
DO NOT EXPLODE!! You'd get guts all over this beautiful NG. :-}

Keep in mind that *each instance* object of your class has only one set of
'things'. The class instance(object) is not responsible for things in another
instance (object).

Your copy-constructor won't be as complex as you think.
For one thing, std::vector has an operator=(), so:

vector<Directory*A(10);
vector<Directory*B;
B = A;
cout<<"A.size()="<<A.size()
<<" B.size()="<<B.size()<<endl;

// out: A.size()=10 B.size()=10

Now, your 'File *Files' is a whole other thing. You have to 'new' some more
memory, and copy to that.

When you see 'array', you need to start thinking 'vector'. A vector is so
much like an array that it is almost a drop-in-replacement (it is even
guaranteed (std) to be continuous in memory).

With arrays, you always need to pass the size into a function (or otherwise
keep track of it, like you do in your class):

void MyFunc( File *file, int size){....}

But, vectors know their size:

void MyFunc( vFiles &file{ /* file.size() */ ....}
> vector<File*vFiles;

I'd prefer to leave my files alone for now. They seem to work. It's
just that vector that's driving me nuts now.
>Here's that 'helper' I mentioned.

template<class Seqvoid EmptyThis( Seq &con ){
for( class Seq::iterator i( con.begin() ); i != con.end(); ++i ){
delete *i;
*i = 0; // in case it gets called again
}
} //template<class Seqvoid EmptyThis(Seq&)
>Directory::~Directory(){
delete[] Files;
// and since your vector holds pointers to 'new' objects.
EmptyThis( Directories );
> } // Dtor
Yeah, I know, "I can't use templates!!". Well, your stuck using 'concrete'
functions then.

Actually I didn't know I couldn't use templates. I would have had
problems and just figured it was me not using correct syntax. (Which I
guess it would be).
Well, if templates are not forbidden, put that one above your class. It won't
hurt anything. A template does not create any code until you actually use it.
Easy enough to delete it (if not used) when you turn in your project.
>
This doesn't do it??
Yes, it does. Use one or the other, just don't use both!<G>
>Directory::~Directory()
{
//delete the array of files
delete Files;
// delete each directory pointer from the vector
for(size_t i(0) ; i < Directories.size(); ++i )
{
delete Directories.at( i );
}
}
>ref: 'predicates'
If you want to go that way, and have trouble, just start a new thread on
that
>subject. Some of the experts in this NG are really good at that
(predicates).
>
Thanks I did. I tried something that looked like what you have but got
errors... It wasn't exact though...
It was a struct.
your line: return ( (*X)->name < (*Y)->name);
I converted to this: return ( *X->GetName() < *Y->GetName());
because name is private.

It gives the error:
passing `const Directory' as `this' argument of `std::string
Directory::GetName()' discards qualifiers

I have posted it in a smaller posting in the group for that one
problem. Hopefully someone gets back to me.
I'm sure you've seen my 'fix' in the other thread by now.
>
Thanks for all your help. Believe it or not I am learning a lot from
this assignment and the pain it is causing me! ;)
I once spent three days looking for a bug that turned out to be a single
missing semicolon on one line!! Boy, did I learn! <G>

Like I've said before:
"Don't chase the rainbow looking for the pot of gold, just pick up the
diamonds along the way.".
Learning C++ is one small step at a time.
I think you are doing very well.
>
It's all about time. Due date is am Monday so I can only do what I can
do! ;)
Well then quit shootin' the breeze with idiots like me, and get to work! <G>

Git 'er done!
--
Bob R
POVrookie
Dec 1 '06 #24

This discussion thread is closed

Replies have been disabled for this discussion.