create a dynamic array of pointers with initial values of NULL

S

sandy

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.
 
S

sandy

Oops. My subject is incorrect, I want to create a dynamic array of my
class Directory, within my class Directory.
 
M

mlimber

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<File> files_;
std::set<Directory> subdirs_;
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
 
V

Victor Bazarov

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
 
S

sandy

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 said:
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
 
A

Alf P. Steinbach

* (e-mail address removed):
[top-posting, overquoting]

Please don't -- read the FAQ -- corrected.


* (e-mail address removed):
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.
 
B

BobR

(e-mail address removed) 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.
 
S

sandy

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.
 
A

Alf P. Steinbach

* (e-mail address removed):
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<Directory> directories;

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

But if you need pointers, use e.g.

typedef boost::shared_ptr<Directory> DirectoryPtr;
typedef std::vector<DirectoryPtr> DirectoryPtrs;

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.
 
B

BobR

(e-mail address removed) 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<int> const &vec, std::eek:stream &sout){
sout<<" size="<<vec.size()<<" cap="<<vec.capacity()<<std::endl;
return;
} // PrintVec(vector<int> const&,ostream&)
// --------------------------
void VecIntSize( std::eek:stream &cout ){
cout<<"\n--- VecInt() size test ---"<<std::endl;
std::vector<int> VecInt(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<double> vecD( 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::string> vBstr( 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.
*/
 
S

sandy

BobR said:
(e-mail address removed) 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<int> const &vec, std::eek:stream &sout){
sout<<" size="<<vec.size()<<" cap="<<vec.capacity()<<std::endl;
return;
} // PrintVec(vector<int> const&,ostream&)
// --------------------------
void VecIntSize( std::eek:stream &cout ){
cout<<"\n--- VecInt() size test ---"<<std::endl;
std::vector<int> VecInt(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<double> vecD( 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::string> vBstr( 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.
*/

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.
 
B

BobR

(e-mail address removed) 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::eek:ut_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).
 
S

sandy

vector said:
In your class, or at global scope?

I am doing this in the private section of my .h file
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!
// > 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).
// 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::eek:ut_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 = new File(OldArray.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.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::eek:ut_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;
}
*******************************************
Piece of cake, but, one thing at a time. Find bug first<beats chest like
Tarzan>!!


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).

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.
 
B

BobR

(e-mail address removed) 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/ThinkingInCPP2e.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.
 
B

BobR

(e-mail address removed) 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 = new File(OldArray.GetFileName());
}
delete [] OldArray;
MaxFiles = MaxFiles * 2;
}


If you also make 'Files' a std::vector, you won't need things like
'DoubleFiles()'.
//Empty()

//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!
 
S

sandy

BobR said:
(e-mail address removed) 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<Directory> 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

**********************************************
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::eek:perator==(const string & D)
{
if(Name != D)
return false;
else
return true;
}

bool Directory::eek:perator<(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::eek:perator>(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 = new File(OldArray.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.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::eek:ut_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::eek:penInFile()
{
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 << 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 << endl;
CurrentDir->Create(Words);
}
}
// 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::eek:perator=(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::eek:perator=(const File *F)
{
if(F->Name != "" && F->Extension != "")
{
Name = F->Name;
Extension = F->Extension;

return true;
}
else
return false;
}

File & File::eek:perator=(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::eek:perator==(const File & F)
{
if(Name != F.Name)
return false;

if(Extension != F.Extension)
{
return false;
}
else
{
return true;
}
}


/*
operator<
*/
bool File::eek:perator<(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::eek:perator<(string FN)
{
if(GetFileName() > FN)
return false;

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

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


/*
operator>
*/
bool File::eek:perator>(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::eek:perator>(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?
 
S

sandy

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)
 
B

BobR

(e-mail address removed) 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<int> BigV( sz );

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

sandy

BobR said:
(e-mail address removed) 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.


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::eek:perator<(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.


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.
 
S

sandy

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!
 

Ask a Question

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

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

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top