Thread: tree container

  1. #16
    Registered User
    Join Date
    Oct 2008
    Posts
    19
    OK, so I'll follow #1 and maybe after finishing the whole project I will try to change it with using #2. Is it the proper way? (I've got a problem with destructing these children)

    Code:
    #include <iostream>
    #include <vector>
    #include <fstream>
    using namespace std;
    
    class Directory
    {
     private:
        Directory(const Directory& dir);
        void operator=(const Directory& dir);
     public:
        string name;
        vector<Directory*> children;
    
        Directory(string name_) : name(name_) { };
        ~Directory() {delete children;} ; //I guess it's not a proper way of destructing
    };
    
    //what should I write inside constructor and operator?
    Directory::Directory(const Directory& dir)
    {}
    void Directory::operator=(const Directory& dir);
    {}
    
    int nesting = 0;
    
    void print(Directory &dir) { //"Your print function needs to take a reference, not a pointer"...
     for (int i = 0; i < nesting; ++i) cout << ' ';
     cout << dir.name << endl; //...so I had to change this...
     ++nesting;
     for_each(dir.children.begin(), dir.children.end(), print); //...and this.
     --nesting;
    }
    
    int main(void) {
     /*
      - root
       - sub1
        - sub1.1
       - sub2
       - sub3
        - sub3.1
         - sub3.1.1
      */
     Directory root("root");//   = new Directory("root"); //"you'd want to leave root as an object"
     
     Directory *sub1   = new Directory("sub1");
     Directory *sub11  = new Directory("sub1.1");
     Directory *sub2   = new Directory("sub2");
     Directory *sub3   = new Directory("sub3");
     Directory *sub31  = new Directory("sub3.1");
     Directory *sub311 = new Directory("sub3.1.1");
     
     root->children.push_back(sub1);
     sub1->children.push_back(sub11);
     root->children.push_back(sub2);
     root->children.push_back(sub3);
     sub3->children.push_back(sub31);
     sub31->children.push_back(sub311);
     
     //print(root);
     system("pause");
     return 0;
    }
    Greetings!

  2. #17
    Registered User
    Join Date
    Jan 2005
    Posts
    7,366
    >> {delete children;} ; //I guess it's not a proper way of destructing
    "In the Directory destructor loop through the vector and delete each pointer."

    >> //"Your print function needs to take a reference, not a pointer"
    Sorry for the confusion, but your print function can take a pointer again. When I said it should take a reference that was before I realized that option #1 might be your best bet.

    >> //what should I write inside constructor and operator?
    Just remove that code. You don't actually have to implement those two functions. Just declaring them as private is enough to make sure they don't get called.

    >> root->children.push_back(sub1);
    Since root is an object you would not use -> there.

    >> //print(root);
    If print takes a pointer and root is an object, then you'd use print(&root) to pass an address to the print function.

  3. #18
    Registered User
    Join Date
    Oct 2008
    Posts
    19
    Thanks!
    My new code:

    Code:
    #include <iostream>
    #include <vector>
    #include <fstream>
    using namespace std;
    
    class Directory
    {
     private:
        Directory(const Directory& dir); //copying constructor
        void operator=(const Directory& dir); //overloading the operator=
     public:
        string name; //name of the directory
        vector<Directory*> children; //children directories
    
        Directory(string name_ = "No Name") : name(name_) { }; //default constructor
        ~Directory()
        {
           //delete children;
           for (int i = 0; i<children.size(); i++)
           {
               delete children[i]; //I hope it is the proper way
           }
           //example of how we can check size of vector:
           //vector <int> vi_Tab(100);
           //int i_Rozmiar = vi_Tab.size();
        } ;
    };
    
    //I don't need to implement constructor and operator.
    //Just declaring them is enough.
    /*Directory::Directory(const Directory& dir)
    {}
    void Directory::operator=(const Directory& dir);
    {}*/
    //But if I'd like to use copying constructor, it can look like this:
    /*Directory::Directory(const Directory &dir)
    {
       Directory(dir.name);
       children = vector<Directory>(dir.children);//??
    }*/
    
    int nesting = 0;
    
    void print(Directory *dir) { //my print function needs to take a pointer...
       for (int i = 0; i < nesting; ++i) cout << ' ';
       cout << dir->name << endl; //...so I've got this...
       ++nesting;
       for_each(dir->children.begin(), dir->children.end(), print); //...and this.
       --nesting;
    }
    
    int main(void) {
       /*
        - root
         - sub1
          - sub1.1
         - sub2
         - sub3
          - sub3.1
           - sub3.1.1
        */
       Directory root("root"); //= new Directory("root"); //I'd want to leave root as an object
     
       Directory *sub1   = new Directory("sub1");
       Directory *sub11  = new Directory("sub1.1");
       Directory *sub2   = new Directory("sub2");
       Directory *sub3   = new Directory("sub3");
       Directory *sub31  = new Directory("sub3.1");
       Directory *sub311 = new Directory("sub3.1.1");
     
       //NOW I'VE GOT A PROBLEM WITH PUSHING BACK SUBDIRECTORIES
       root.children.push_back(sub1);
       //sub1.children.push_back(sub11);
       root.children.push_back(sub2);
       root.children.push_back(sub3);
       //sub3.children.push_back(sub31);
       //sub31.children.push_back(sub311);
     
       //If print takes a pointer and root is an object, then
       //I'd use print(&root) to pass an address to the print function,
       //not print(root).
       print(&root);
       system("pause");
       return 0;
    }
    I don't know how to push back subdirectories.

  4. #19
    Registered User
    Join Date
    Jan 2005
    Posts
    7,366
    >> delete children[i]; //I hope it is the proper way
    That should work.

    >> //But if I'd like to use copying constructor, it can look like this:
    Nope, you have to have a loop (like in your destructor) that loops through the children of the dir parameter. It should call new to create a new Directory and pass *(children[i]) to copy it. I wouldn't worry about this right now, though. Hopefully it's not necessary for you.

    >> //NOW I'VE GOT A PROBLEM WITH PUSHING BACK SUBDIRECTORIES
    This looks like a simple problem. Remember root is an object, so you are using root.children. But sub1, sub3, and the rest are pointers, so you can't use the . syntax.

  5. #20
    Registered User
    Join Date
    Oct 2008
    Posts
    19
    About pushing back subdirectories:
    I know that root is an object and sub1, sub11, ..., sub311 are pointers. I create object root and I add sub1, sub2, sub3 to children vector of root by pushing them back. Now I see I can't push back sub11 to sub1 because sub1 isn't object (as root) but it is a pointer. So I need to add sub11 to children vector of sub1 but I don't know how to access this vector. What should I write to put sub11 to sub1? (Because sub1.children.push_back(sub11); is wrong way to do it).

  6. #21
    Registered User
    Join Date
    Jan 2005
    Posts
    7,366
    Don't use the . syntax. What's the syntax to call a function from a pointer? You did it earlier in the thread.

  7. #22
    Registered User
    Join Date
    Oct 2008
    Posts
    19
    Thanks!
    I've got two other questions - they are written inside the code.
    Thanks in advance

    Code:
    /*
    Program of navigating the directory tree, displaying subdirectories and
    files in current directory. The program uses output of the dir/s command.
    It calculates total space occupied by files in subdirectories of selected
    directory and calculates estimated disk space occupied by the files
    considering the cluster size. The configuration data permitting the program
    to determine the format of dir/s output (dos and windows, a few versions)
    is stored in an external text file. The program should keep in RAM the
    directory structure and the file names of files in current directory.
    */
    
    #include <iostream>
    #include <vector>
    #include <fstream>
    using namespace std;
    
    class Directory
    {
     private:
        Directory(const Directory& dir); //copying constructor
        void operator=(const Directory& dir); //overloading the operator=
     public:
        string name; //name of the directory
        vector<Directory*> children; //children directories
    
    //MY FIRST QUESTION: I'VE GOT STRUCTURE OF DIRECTORIES BUT THERE ARE ALSO FILES
    //IN THE DIRECTORY. I CAN STORE DIRECTORIES IN RAM MEMORY BUT I WANT TO STORE FILES
    //ON THE DISK IN TXT FILE. I WANT TO CREATE TXT FILE IN WHICH THERE IS THE FOLLOWING
    //STRUCTURE:
    //1
    //asdsf.txt
    //sfsdfs.exe
    //2
    //fsdfsd.doc
    //IN OTHER WORDS IT CONTAINS NUMBER OF DIRECTORY AND LIST OF ITS FILES. TO BE ABLE TO
    //READ FROM THIS FILE, EVERY DIRECTORY NEEDS TO HAVE OTHER PARAMETER - THAT IS ITS NUMBER.
    //AND MY FIRST QUESTION IS - WHERE AND HOW SHOULD I PUT THIS NUMBER AS PARAMETER LONG INT
    //INSIDE THIS CLASS DIRECTORY? SHOULD IT BE SIMILAR TO VECTOR<DIRECTORY*> CHILDREN,
    //FOR EXAMPLE VECTOR<LONG INT CHILDRENNUMBER*> CHILDRENNUMBER OR SOMETHING LIKE THIS?
    
        Directory(string name_ = "No Name") : name(name_) { }; //default constructor
        ~Directory()
        {
           //delete children;
           for (int i = 0; i<children.size(); i++)
           {
               delete children[i]; //I hope it is the proper way
           }
           //example of how we can check size of vector:
           //vector <int> vi_Tab(100);
           //int i_Rozmiar = vi_Tab.size();
        } ;
    };
    
    //I don't need to implement constructor and operator.
    //Just declaring them is enough.
    /*Directory::Directory(const Directory& dir)
    {}
    void Directory::operator=(const Directory& dir);
    {}*/
    //But if I'd like to use copying constructor, it would look similar to this:
    /*Directory::Directory(const Directory &dir)
    {
       Directory(dir.name);
       children = vector<Directory>(dir.children);//??
    }*/
    //To create working copying constructor:
    //I need to have a loop (like in destructor) that loops through the
    //children of the dir parameter. It should call new to create
    //a new Directory and pass *(children[i]) to copy it.
    
    int nesting = 0;
    
    void print(Directory *dir) { //my print function needs to take a pointer...
       for (int i = 0; i < nesting; ++i) cout << ' ';
       cout << dir->name << endl; //...so I've got this...
       ++nesting;
       for_each(dir->children.begin(), dir->children.end(), print); //...and this.
       --nesting;
    }
    
    int main()
    {
       ifstream fin("myfile.txt");
       string line;
       int counter=0;
    
       string nameMainDir; //it contains line " Directory: C:\root"
       //where 'Directory' is word dependent on language version of dir/s
       //and 'myRoot' is the name of main directory in our tree
       size_t lengthOfNameMainDir; //I use it during next iterations
       string myRoot; //it contains only name 'root'
       vector<string> nameUpperChildren; //we've got root and its children UpperChildren
       int whereInBlock=0; //inside the file there are blocks
       //(every block begins with " Directory: " C:\root[...]")
       //0 - it is new block, 1 - first line of new block, 2 - second,
       //3 - third, 4 - it is inside this block, 5 - last line
       string rhsDir; //name of the most RHS directory in the line
       string actualName; //name of file or directory which I'm reading at this moment
       int howManySlash; //it contains number of '/' symbols to know level of depth
       long int numberOfDirInClass = 0; //actual number of directory in our tree class
    
       //don't read first three lines
       for (int i=0; i<3; i++) {getline(fin,line);}
        
       while(getline(fin, line))
       { 
          //-----------------------------------------------------------------------
          //first iteration - it checks version of dir/s and reads name of main dir
          //-----------------------------------------------------------------------   
    
          if (counter==0) //if it is first iteration, it reads nameMainDir
          {
             nameMainDir = line; //it reads first line
             lengthOfNameMainDir=line.size(); //here I check size of the line
             int i=lengthOfNameMainDir;
             do { i--; } while (line[i]!=(char)92); //it counts from end of line
                                                    //to first use of symbol char(92)=='\'
             myRoot=line.substr((i+1),(lengthOfNameMainDir-i)); //if writes name of root 
                                                                //directory                                      
             counter++; //it disables entering this if any more
             
             //Directory *root = new Directory(myRoot); //it creates root
             Directory root(myRoot); //it creates object root
             cout<<"myRoot      :["<<myRoot<<"]"<<endl;
             cout<<"nameMainDir :["<<nameMainDir<<"]"<<endl;
             whereInBlock = 0; //because it's first line of the block
          }
          
          //----------------------------------------------------
          //main part of this while - it reads tree of directory
          //----------------------------------------------------
      
          //if the line begins with nameDir, then it contains name of new directory
    
          if (counter != 0) //I don't use else because it won't work for the very first line
          {  
             //whereInBlock (the same comment is after declaration of whereInBlock):
             //(every block begins with " Directory: " C:\root[...]")
             //0 - it is new block, 1 - first line of new block, 2 - second,
             //3 - third, 4 - it is inside this block, 5 - last                  
             switch (whereInBlock)
             { //I haven't designed this switch yet :)
                case 0: //it reads name of the RHS directory
                   //line - it is my line, nameMainDir - we need to erase it from rhs
                   //lengthOfNameMainDir - lenght
                   rhsDir = line.substr(lengthOfNameMainDir);
                   cout<<"rhsDir      :["<<rhsDir<<"]"<<endl;
                   //now we need to calculate how many '/' there are in name
                   //so that we know level of depth in our directories tree
                   howManySlash = 0;
                   for (int i = 0; i<rhsDir.size(); i++)
                   { if (rhsDir[i] == '\\') howManySlash++; } 
                   whereInBlock++;
                   break;
                case 1: whereInBlock++; break; //empty line
                case 2: whereInBlock++; break; //line with .
                case 3: whereInBlock++; break; //line with ..
                case 4:
                   if (line[0] != ' ')
                   { //case 4a - main body of the block
                      actualName = line.substr(36); //name of new file or directory
                      if (line[21] == '<') //it is directory
                      {
                         //SECOND QUESTION:
                         //Here I need to create new directory and I don't know how !!!!!!!!!!!
                         //At first time it is something like sub1, which is subdirectory of
                         //root. It should be something similar to:
                         //Directory *sub1   = new Directory("sub1");
                         //root.children.push_back(sub1);
                         //but for next cases similar to:
                         //Directory *sub11  = new Directory("sub1.1");
                         //sub1->children.push_back(sub11);
                         //and I should be able to access it later.
                      }
                      else
                      {
                         //Here I want to write code which writes list of files into the txt file.
                         //(I will do it later).
                      }
                   }
                   else
                   { //case 4b - line before the last one
                      whereInBlock++;
                   }
                   break;
                case 5: //again empty line
                   whereInBlock = 0;
                   break;
             }
          }
       }
       
       cout<<"::End of file::\n";
       fin.close();
     
       system("pause");
       return 0;
    }

  8. #23
    Student legit's Avatar
    Join Date
    Aug 2008
    Location
    UK -> Newcastle
    Posts
    156
    Quote Originally Posted by Daved View Post
    Don't use the . syntax. What's the syntax to call a function from a pointer? You did it earlier in the thread.
    Ooo Ooo Pick me!

    Sorry bout that, had to be done.

  9. #24
    Registered User
    Join Date
    Oct 2008
    Posts
    19
    About my second question:

    I think I have done it. I used:
    sub1.children.push_back(sub11);
    And now I use:
    sub1->children.push_back(sub11);

    This is code about using tree structure:
    Code:
    int main(void) {
       /*
        - root
         - sub1
          - sub1.1
         - sub2
         - sub3
          - sub3.1
           - sub3.1.1
        */
       Directory root("root"); //= new Directory("root");
       //I want to leave root as an object
     
       Directory *sub1   = new Directory("sub1");
       Directory *sub11  = new Directory("sub1.1");
       Directory *sub2   = new Directory("sub2");
       Directory *sub3   = new Directory("sub3");
       Directory *sub31  = new Directory("sub3.1");
       Directory *sub311 = new Directory("sub3.1.1");
     
       //Root is an object, so I am using root.children. But sub1, sub3, and
       //the rest are pointers, so I can't use the . syntax, but -> syntax.
       root.children.push_back(sub1);
       sub1->children.push_back(sub11);
       root.children.push_back(sub2);
       root.children.push_back(sub3);
       sub3->children.push_back(sub31);
       sub31->children.push_back(sub311);
     
       //If print takes a pointer and root is an object, then
       //I'd use print(&root) to pass an address to the print function,
       //not print(root).
       print(&root);
       system("pause");
       return 0;
    }
    But in above code I know the structure of the tree before creating the tree (it is written in lines 3-9 between /* and */). And in my case (my previous post) I don't know the structure before creating the tree (I create that structure based on the input file).

    And what about my first question ?
    Greetings!

  10. #25
    Registered User
    Join Date
    Jan 2005
    Posts
    7,366
    >> And what about my first question ?

    I've been really busy this week. If you've still got the same question (or others) reply again on Tuesday-ish to remind me of this thread.

  11. #26
    Registered User
    Join Date
    Oct 2008
    Posts
    19
    I've got still some problems.
    It is my actual code:

    Code:
    /*
    Program of navigating the directory tree, displaying subdirectories and
    files in current directory. The program uses output of the dir/s command.
    It calculates total space occupied by files in subdirectories of selected
    directory and calculates estimated disk space occupied by the files
    considering the cluster size. The configuration data permitting the program
    to determine the format of dir/s output (dos and windows, a few versions)
    is stored in an external text file. The program should keep in RAM the
    directory structure and the file names of files in current directory.
    */
    
    #include <iostream>
    #include <vector>
    #include <fstream>
    using namespace std;
    
    class Directory
    {
     private:
        Directory(const Directory& dir); //copying constructor
        void operator=(const Directory& dir); //overloading the operator=
     public:
        string name; //name of the directory
        vector<Directory*> children; //children directories
    //  static long int numberOfDirInClass; //actual number of directory in our tree class
    
    /*
    FIRST QUESTION: I've got structure of directories but there are also files in the
    directory. I can store directories in RAM memory but I want to store files on the disk
    in txt file. I want to create txt file with following content:
    1
    asdsf.txt
    sfsdfs.exe
    2
    fsdfsd.doc
    In other words it contains number of directory and list of its files. To be able to
    read from this file, every drectory needs to have other parameter - that is its number.
    I use variable numberOfDirInClass but to have only this variable is not enough.
    And my first question is - where and how should I put this number as parameter long int
    inside this class directory? Should it be similar to vector<directory*> children,
    for example vector<long int childrenNumber*> childrenNumber or something like this?
    */
    
        Directory(string name_ = "No Name") : name(name_) { }; //default constructor
    //  Directory(string name_ = "No Name") : name(name_) { numberOfDirInClass++; }; //default constructor
        ~Directory()
        {
           //delete children;
           for (int i = 0; i<children.size(); i++)
           {
               delete children[i]; //I hope it is the proper way
           }
           //example of how we can check size of vector:
           //vector <int> vi_Tab(100);
           //int i_Rozmiar = vi_Tab.size();
        } ;
    };
    
    //I don't need to implement constructor and operator.
    //Just declaring them is enough.
    /*Directory::Directory(const Directory& dir)
    {}
    void Directory::operator=(const Directory& dir);
    {}*/
    //But if I'd like to use copying constructor, it would look similar to this:
    /*Directory::Directory(const Directory &dir)
    {
       Directory(dir.name);
       children = vector<Directory>(dir.children);//??
    }*/
    //To create working copying constructor:
    //I need to have a loop (like in destructor) that loops through the
    //children of the dir parameter. It should call new to create
    //a new Directory and pass *(children[i]) to copy it.
    
    int nesting = 0; //I consider moving "int nesting" into "int main()"
    
    void print(Directory *dir) { //my print function needs to take a pointer...
       for (int i = 0; i < nesting; ++i) cout << ' ';
       cout << dir->name << endl; //...so I've got this...
       ++nesting;
       for_each(dir->children.begin(), dir->children.end(), print); //...and this.
       --nesting;
    }
    
    //long int Directory::numberOfDirInClass = 0;
    
    int main()
    {
       ifstream fin("myfile.txt"); //to read list of directories
       string line;
       int counter=0;
    
       ofstream fout("temp.txt"); //to write list of files
    
       string nameMainDir; //it contains line " Directory: C:\root"
       //where 'Directory' is word dependent on language version of dir/s
       //and 'myRoot' is the name of main directory in our tree
       size_t lengthOfNameMainDir; //I use it during next iterations
       string myRoot; //it contains only name 'root'
       vector<string> nameUpperChildren; //we've got root and its children UpperChildren
       int whereInBlock=0; //inside the file there are blocks
       //(every block begins with " Directory: " C:\root[...]")
       //0 - it is new block, 1 - first line of new block, 2 - second,
       //3 - third, 4 - it is inside this block, 5 - last line
       string rhsDir; //name of the most RHS directory in the line
       string actualName; //name of file or directory which I'm reading at this moment
       int howManySlash; //it contains number of '/' symbols to know level of depth
       bool isFirstFile = 1; //is it first file for the given numberOfDirInClass
       long int numberOfDirInClass = 0; //actual number of directory in our tree class
       string sizeInBytesString;
       long int sizeInBytes; //read size of the file
    
       //don't read first three lines
       for (int i=0; i<3; i++) {getline(fin,line);}
        
       while(getline(fin, line))
       { 
          //-----------------------------------------------------------------------
          //first iteration - it checks version of dir/s and reads name of main dir
          //-----------------------------------------------------------------------   
    
          if (counter==0) //if it is first iteration, it reads nameMainDir
          {
             nameMainDir = line; //it reads first line
             lengthOfNameMainDir=line.size(); //here I check size of the line
             int i=lengthOfNameMainDir;
             do { i--; } while (line[i]!=(char)92); //it counts from end of line
                                                    //to first use of symbol char(92)=='\'
             myRoot=line.substr((i+1),(lengthOfNameMainDir-i)); //if writes name of root 
                                                                //directory                                      
             counter++; //it disables entering this if any more
             
             //Directory *root = new Directory(myRoot); //it creates root
             Directory root(myRoot); //it creates object root
             cout<<"myRoot      :["<<myRoot<<"]"<<endl;
             cout<<"nameMainDir :["<<nameMainDir<<"]"<<endl;
             whereInBlock = 0; //because it's first line of the block
          }
          
          //----------------------------------------------------
          //main part of this while - it reads tree of directory
          //----------------------------------------------------
      
          //if the line begins with nameDir, then it contains name of new directory
    
          if (counter == 1) //I don't use else because it won't work for the very first line
          {  
             //whereInBlock (the same comment is after declaration of whereInBlock):
             //(every block begins with " Directory: " C:\root[...]")
             //0 - it is new block, 1 - first line of new block, 2 - second,
             //3 - third, 4 - it is inside this block, 5 - last
             switch (whereInBlock)
             { //I haven't designed this switch yet :)
                case 0: //it reads name of the RHS directory
                   if (line[2] == nameMainDir[2]) 
                   { //if it is not one of last lines in the file (" Katalog" or "     Razem")
                      numberOfDirInClass++;
                      //line - it is my line, nameMainDir - we need to erase it from rhs
                      //lengthOfNameMainDir - lenght
                      rhsDir = line.substr(lengthOfNameMainDir);
                      cout<<"rhsDir      :["<<rhsDir<<"]"<<endl;
                      //now we need to calculate how many '/' there are in name
                      //so that we know level of depth in our directories tree
                      howManySlash = 0;
                      for (int i = 0; i<rhsDir.size(); i++)
                      { if (rhsDir[i] == '\\') howManySlash++; } 
                      whereInBlock++;
                   }
                   else
                   { counter++; }
                   break;
                case 1: whereInBlock++; break; //empty line
                case 2: whereInBlock++; break; //line with .
                case 3: whereInBlock++; isFirstFile = 1; break; //line with ..
                case 4:
                   if (line[0] != ' ')
                   { //case 4a - main body of the block
                      actualName = line.substr(36); //name of new file or directory
                      if (line[21] == '<') //it is directory
                      {
                         //SECOND QUESTION:
                         //Here I need to create new directory and I don't know how!
                         //At first time it is something like sub1, which is subdirectory of
                         //root. It should be something similar to:
                         //Directory *sub1   = new Directory("sub1");
                         //root.children.push_back(sub1);
                         //but for next cases similar to:
                         //Directory *sub11  = new Directory("sub1.1");
                         //sub1->children.push_back(sub11);
                         //and I should be able to access it later.
                      }
                      else
                      {
                         //Here I want to write code which writes list of files into the txt file.
                         //(I will do it later).
                         if (isFirstFile == 1) //write number of this directory
                         {
                            isFirstFile = 0;
    //                      fout<<Directory::numberOfDirInClass<<endl;
                            fout<<numberOfDirInClass<<endl;
                         }
                         //write both name of file and its size
                         sizeInBytesString = line.substr(27,8); 
                         sizeInBytes = atoi(sizeInBytesString.c_str());
                         fout<<actualName<<"\t"<<sizeInBytes<<endl;
                      }
                   }
                   else
                   { //case 4b - line before the last one
                      whereInBlock++;
                   }
                   break;
                case 5: //again empty line
                   whereInBlock = 0;
                   break;
             } //end of "switch"
          } //end of "if (counter == 1)"
       } //end of "while(getline(fin, line))"
    
       cout<<"::End of file::\n";
       fin.close();
       fout.close();
       system("pause");
       system("cls");
       
       //I finished reading tree from the file. I've got tree structure in RAM
       //and files in txt file. Now I can allow the user to navigate the tree.
       //User can see the list of directories and write commands ".." for the
       //previous directory or "[name]" to enter the directory given by [name].
       //There may be "." for entering main directory.
       //There should be key shortcut (e.g. ctrl+esc or ctrl+Q) to exit
       //(by the way I don't know how to implement it). I need to implement
       //here "while(key_is_not_pressed) { let_user_explore_the_structure; }".
       
       //THIRD QUESTION: I want to show directories and files in the actual directory
       //(at the beginning it is root directory). I don't want to show the whole
       //structure by "print(&root);" but e.g. "print(7)" to show directory indicated
       //by number 7 (look at my first question). For root directory it would be
       //"print(0)". My question is how to change print function to be able to do it.
       //It is also dependent on the answer to question number one :-).
       
       //Here I need to delete fout from the hard disc.
       system("pause");
       return 0;
    }
    I went for consulting hours at the university and I heard some advices from my teacher about this code. He didn't have a time to read it from the beginning to the end so he didn't see the reason for just declaring constructor and overloaded operator - in fact I don't see it as well. He said I don't need these two declarations or I should both declare and implement both of them.

    About first question he suggested "rather offsets of dir stored in the dir item n tree (in memory) structure". I guess it means that I don't use any kind of a number but I use pointer (?) or just variables which contains where in the input file I've got beginning of lines for the given directory. But I need some more advices how to implement it.

    About second question he said that I should use "two stages: 1. create object, 2. insert into tree (in right place)". Unfortunately still I don't know how to do it.

    And third question is still unknown for me because it depends on how I implement those other things. I guess I won't be using output txt file but just input file and variables with indication where I've got files for the given directory in the input file.

    Thanks for help in advance .

  12. #27
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by kawafis44
    He didn't have a time to read it from the beginning to the end so he didn't see the reason for just declaring constructor and overloaded operator - in fact I don't see it as well. He said I don't need these two declarations or I should both declare and implement both of them.
    That is correct. However, in this case you need them (along with the destructor) since you need to perform deep copying. If not, then you should declare them private and not implement them (i.e., disable copying).
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  13. #28
    Registered User
    Join Date
    Jan 2005
    Posts
    7,366
    Yes, the reason for declaring the copy constructor and copy assignment operator without implementing them is to disable copying by making those functions private. This way the compiler doesn't allow you to copy a directory object (which would be bad unless you implement copying correctly).

    You could actually implement those, in which case you would declare them as public instead of private. But I don't think it's necessary for this code. If you do want to implement them then the notes in your commented out sections should help you.

    Note that the difference between privately declaring them without an implementation and declaring and implementing them publicly is that the first does not allow you to copy a Directory object and the second does.

    There is a third option, which is remove all declarations and definitions of the copy functions. This is the worst because the compiler generated versions will be used and the compiler generated versions do the wrong thing which can lead to a crash. Unfortunately, this is the most common solution which is why I made it a point to warn you about it.

  14. #29
    Registered User
    Join Date
    Jan 2005
    Posts
    7,366
    First question:

    I think your teacher is suggesting that you use the index in the vector. That leads me to this question: Will there be one text file per directory, or one file total with all file names in it?

    For example, let's say your hierarchy looks like this (directories underlined):
    Code:
    root
    -- sub1
    ---- asdf.txt
    ---- hjkl.txt
    ---- sub11
    ------ bar.ini
    ------ baz.exe
    ------ foo.ini
    -- sub2
    ---- jack.doc
    ---- jill.doc
    Would you have a separate text file for Root like this:
    Code:
    1
    asdf.txt
    hjkl.txt
    2
    jack.doc
    jill.doc
    and another for Sub1 like this:
    Code:
    1
    bar.ini
    baz.exe
    foo.ini
    Or would you have one big text file with all directories in it:
    Code:
    1
    asdf.txt
    hjkl.txt
    2
    jack.doc
    jill.doc
    3
    bar.ini
    baz.exe
    foo.ini
    ?

    Basically, how are you indicating where in the tree hierarchy the directory is?

    I'll try to look at the other questions a little later if I have time.
    Last edited by Daved; 12-03-2008 at 06:50 PM.

  15. #30
    Registered User
    Join Date
    Oct 2008
    Posts
    19
    I changed this code a little. Now question one is answered - I won't be using integer number to indicate directories but lineInFile to indicate line of input file where I've got information about files stored in this directory. It also means that I don't create any temporary output file. But there are still questions number two and three. Second question is about creating tree structure. Third question is about showing list of directories and files from the actual directory (I don't know how to indicate actual directory and how to show it).

    Code:
    /*
    Program of navigating the directory tree, displaying subdirectories and
    files in current directory. The program uses output of the dir/s command.
    It calculates total space occupied by files in subdirectories of selected
    directory and calculates estimated disk space occupied by the files
    considering the cluster size. The configuration data permitting the program
    to determine the format of dir/s output (dos and windows, a few versions)
    is stored in an external text file. The program should keep in RAM the
    directory structure and the file names of files in current directory.
    */
    
    #include <iostream>
    #include <vector>
    #include <fstream>
    using namespace std;
    
    class Directory
    {
     private:
        //I don't use copy constructor and overloaded operator=. This is why I
        //declare them here (in private) with no implementing - to prevent using them.
        Directory::Directory(const Directory& dir)
        {}
        void Directory::operator=(const Directory& dir)
        {}
     public:
        //Should I put name and lineInFile into private section?
        string name;                 //name of the directory
        vector<Directory*> children; //children directories
        long int lineInFile;         //What is the number of line in the file
                                     //where list of files in this directory begins
                                     //(don't mistake it with whereInFile)
    
        Directory(string name_ = "No Name", long int lineInFile_ = -1) :
           name(name_), lineInFile(lineInFile_) { }; //default constructor
           //lineInFile == -1 means error
        ~Directory()
        {
           //delete children;
           for (int i = 0; i<children.size(); i++)
           { delete children[i]; }
           //example of how we can check size of vector:
           //vector <int> vi_Tab(100);
           //int i_Rozmiar = vi_Tab.size();
        };
    };
    
    int nesting = 0;
    
    void print(Directory *dir) { //my print function needs to take a pointer...
       for (int i = 0; i < nesting; ++i) cout << ' ';
       cout << dir->name << endl; //...so I've got this...
       ++nesting;
       for_each(dir->children.begin(), dir->children.end(), print); //...and this.
       --nesting;
    }
    
    int main()
    {
       ifstream fin("myfile.txt"); //to read list of directories
       string line;
       int counter=0;
    
       long int whereInFile = 0; //what number of line in the file is the actual one
       string nameMainDir; //it contains line " Directory: C:\root"
       //where 'Directory' is word dependent on language version of dir/s
       //and 'myRoot' is the name of main directory in our tree
       size_t lengthOfNameMainDir; //I use it during next iterations
       string myRoot; //it contains only name 'root'
       vector<string> nameUpperChildren; //we've got root and its children UpperChildren
       int whereInBlock=0; //inside the file there are blocks
       //(every block begins with " Directory: " C:\root[...]")
       //0 - it is new block, 1 - first line of new block, 2 - second,
       //3 - third, 4 - it is inside this block, 5 - last line
       string rhsDir; //name of the most RHS directory in the line
       string actualName; //name of file or directory which I'm reading at this moment
       int howManySlash; //it contains number of '/' symbols to know level of depth
       string sizeInBytesString;                       //???????? I will take care of
       long int sizeInBytes; //read size of the file   //???????? these variables later.
    
       //don't read first three lines
       for (int i=0; i<3; i++) {getline(fin,line);}
    
       //===========================================================================
        
       while(getline(fin, line))
       { 
          //-----------------------------------------------------------------------
          //first iteration - it checks version of dir/s and reads name of main dir
          //-----------------------------------------------------------------------   
    
          if (counter==0) //if it is first iteration, it reads nameMainDir
          {
             nameMainDir = line; //it reads first line
             lengthOfNameMainDir=line.size(); //here I check size of the line
             int i=lengthOfNameMainDir;
             do { i--; } while (line[i]!=(char)92); //it counts from end of line
                                                    //to first use of symbol char(92)=='\'
             myRoot=line.substr((i+1),(lengthOfNameMainDir-i)); //if writes name of root 
                                                                //directory                                      
             counter++; //it disables entering this if any more
             
             //Directory *root = new Directory(myRoot); //it creates root
             Directory root(myRoot, whereInFile); //it creates object root
             cout<<"myRoot      :["<<myRoot<<"]"<<endl;
             cout<<"nameMainDir :["<<nameMainDir<<"]"<<endl;
             whereInBlock = 0; //because it's first line of the block
          }
          
          //----------------------------------------------------
          //main part of this while - it reads tree of directory
          //----------------------------------------------------
      
          //if the line begins with nameDir, then it contains name of new directory
    
          if (counter == 1) //I don't use else because it won't work for the very first line
          {  
             //whereInBlock (the same comment is after declaration of whereInBlock):
             //(every block begins with " Directory: " C:\root[...]")
             //0 - it is new block, 1 - first line of new block, 2 - second,
             //3 - third, 4 - it is inside this block, 5 - last
             switch (whereInBlock)
             { //I haven't designed this switch yet :)
                case 0: //it reads name of the RHS directory
                   if (line[2] == nameMainDir[2]) 
                   { //if it is not one of last lines in the file (" Katalog" or "     Razem")
                      //line - it is my line, nameMainDir - we need to erase it from rhs
                      //lengthOfNameMainDir - lenght
                      rhsDir = line.substr(lengthOfNameMainDir);
                      cout<<"rhsDir      :["<<rhsDir<<"]"<<endl;
                      //now we need to calculate how many '/' there are in name
                      //so that we know level of depth in our directories tree
                      howManySlash = 0;
                      for (int i = 0; i<rhsDir.size(); i++)
                      { if (rhsDir[i] == '\\') howManySlash++; } 
                      whereInBlock++;
                   }
                   else
                   { counter++; }
                   break;
                case 1: whereInBlock++; break; //empty line
                case 2: whereInBlock++; break; //line with .
                case 3: whereInBlock++; break; //line with ..
                case 4:
                   if (line[0] != ' ')
                   { //case 4a - main body of the block
                      actualName = line.substr(36); //name of new file or directory
                      if (line[21] == '<') //it is directory
                      {
                         //SECOND QUESTION:
                                  
                         //Here I need to create new directory and I don't know how!
                         //At first time it is something like sub1, which is subdirectory of
                         //root. It should be something similar to:
                         //Directory *sub1   = new Directory("sub1", whereInFile);
                         //root.children.push_back(sub1); (or "root.children.push_back(sub1, whereInFile);" ?)
                         //but for next cases similar to:
                         //Directory *sub11  = new Directory("sub1.1");
                         //sub1->children.push_back(sub11);
                         //and I should be able to access it later.
                         
                         //I should use "two stages: 1. create object,
                         //2. insert into tree (in right place)".
                         //Unfortunately still I don't know how to do it.
                      }
                   }
                   else
                   { //case 4b - line before the last one
                      whereInBlock++;
                   }
                   break;
                case 5: //again empty line
                   whereInBlock = 0;
                   break;
             } //end of "switch"
          } //end of "if (counter == 1)"
    
          //----------------------------------------------------
          //last and very short part of this while
          //----------------------------------------------------
          
          //every iteration it should increase whereInFile by one
          whereInFile++;
          
       } //end of "while(getline(fin, line))"
       
       //===========================================================================   
    
       cout<<"::End of file::\n";
       fin.close();
       system("pause");
       system("cls");
       
       //I finished reading tree from the file. I've got tree structure in RAM
       //and files are still in the input file. I don't read list of files into RAM.
       //Now I can allow the user to navigate the tree.
       //User can see the list of directories and write commands ".." for the
       //previous directory or "[name]" to enter the directory given by [name].
       //There may be "." for entering main directory.
       //There should be key shortcut (e.g. ctrl+esc or ctrl+Q) to exit
       //(by the way I don't know how to implement it). I need to implement
       //here "while(key_is_not_pressed) { let_user_explore_the_structure; }".
       //I will be using something like console to communicate with the user.
       
       //THIRD QUESTION: I want to show directories and files in the actual directory
       //(at the beginning it is root directory). I don't want to show the whole
       //structure by "print(&root);". I'd like to show only actual directory
       //but I don't have any idea how to indicate which directory is actual and
       //how to show this directory. I should be able to show list of files in the
       //actual directory (I don't store those files in RAM or other temporary txt
       //file so I need to reopen fin, use lineInFile of the actual directory and
       //read list of files from opened file.
    
       system("pause");
       return 0;
    }
    Regards!

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Interpreter.c
    By moussa in forum C Programming
    Replies: 4
    Last Post: 05-28-2008, 05:59 PM
  2. Linked List Queue Implementation help
    By Kenogu Labz in forum C++ Programming
    Replies: 8
    Last Post: 09-21-2005, 10:14 AM
  3. Binary Search Trees Part III
    By Prelude in forum A Brief History of Cprogramming.com
    Replies: 16
    Last Post: 10-02-2004, 03:00 PM
  4. Request for comments
    By Prelude in forum A Brief History of Cprogramming.com
    Replies: 15
    Last Post: 01-02-2004, 10:33 AM
  5. BST/Red and Black Tree
    By ghettoman in forum C++ Programming
    Replies: 0
    Last Post: 10-24-2001, 10:45 PM