Solving Vector Length Test Problem: EOF & Do-While Loops

  • Thread starter yungman
  • Start date
  • Tags
    Vectors
In summary, the conversation is about a program that uses vectors to store information in a directory. The program is intended to take input for multiple names and phone numbers, but there is an issue with the input being skipped after the first iteration. The program also needs to be able to detect the end of the vector to stop the operation, but the method for doing so is unclear. The person is trying to use vectors as a scalable option, but is considering other options such as using pointers or fstream file. The conversation discusses the possibility of an issue with the input buffer after line 29, but the person is not sure what the issue may be.
  • #36
yungman said:
One think I am still not quite get, why the int variable has to have "static" in front when declaring in the class inside the .h file. that tripped me for a little while.
Strictly speaking, it doesn't - is Visual Studio insisting that it should? Note that you have declared nameL and phoneL as const; can you see why there is no point in having a const that is not static?
 
Last edited:
Technology news on Phys.org
  • #37
pbuk said:
I want a class for a contact directory: a good name will be Contacts.
I agree.
A name for the class that is unhelpful is VectorCall. The name you choose should convey to a third party what kind of object the class is supposed to represent. The class is designed around the vector template class, but that's not relevant to anyone trying to understand what it represents.

There are several other names that are not well-chosen:
  • nameL - better would be nameLen - the most important attribute is that this is the length of some string
  • phoneL - better as phoneLen
  • DirV - why do we care that the underlying container type is a vector?
  • Info - too vague
  • newF - newFile
  • ct2 - ?
  • yes - a terrible name for a variable that could contain 'n'
In the world of software development, several years are likely to go by after the code is written. In the maintenance phase, it's almost certain that a different developer will be tasked to fix bugs that crop up during the life of the software. If the original developer uses names for classes, functions, and variables whose purpose can't be deduced easily, it's much more difficult for a maintenance programmer to understand the code and fix these bugs.

In your constructor you have this code -
C++:
    else
        {//If the file exist, read entire file into vector DirV.
          file.read(reinterpret_cast<char*>(&Dir), sizeof(Dir));
          do
          {
            DirV.push_back(Dir);
            file.read(reinterpret_cast<char*>(&Dir), sizeof(Dir));
          } while (!file.eof());
          file.close();
        }
Why are you calling read() twice?
 
  • Like
Likes yungman
  • #38
Mark44 said:
yes - a terrible name for a variable that could contain 'n'

:eek:

It's a pity that after you wrote those nice long messages about useful naming - they were completely ignored. A real kick in the teeth there. Apart from some future programmer, the real beneficiaries are the people yungman will ask to debug his code the very same day.

In this case, though, you shouldn't worry about it, since "yes" will never contain anything. The cin.ignore() will take care of that. It's a pity that after the long thread on strings, c strings and arrays of char, what yungman took away from all that is "sprinkle some cin.ignore() statements in random places."

Mark44 said:
Why are you calling read() twice?

I think the better question is why is he calling it once? The job of the constructor is to construct the object, not to run all of the code, He shouldn't be reading files in the constructor and he sure shouldn't be writing them in the destructor.
 
Last edited:
  • #39
Vanadium 50 said:
I think the better question is why is he calling it once? The job of the constructor is to construct the object, not to run all of the code, He shouldn't be reading files in the constructor and he sure shouldn't be writing them in the destructor.
The same thought occurred to me, about what the job of a constructor should be.
 
  • #40
The destructor behavior is far, far worse. Suppose you call the constructor, do some running, and then decide that the in-memory copy is not what you want. Maybe it's even corrupted. Now what? If you destroy the bad object, it overwrites the good copy. If you decide to exit without writing, you implicitly call the destructor anyway and still manage to overwrite the good copy
 
  • #41
Mark44 said:
Why are you calling read() twice?
Not being a C++ programmer, I had to spend 30 seconds with Google to learn about the break statement.

Also, not being a C++ programmer, I'd missed the difference between "do {block} while (condition)" and "while (condition) {block};
 
Last edited:
  • #42
Mark44 said:
I agree.
A name for the class that is unhelpful is VectorCall. The name you choose should convey to a third party what kind of object the class is supposed to represent. The class is designed around the vector template class, but that's not relevant to anyone trying to understand what it represents.

There are several other names that are not well-chosen:
  • nameL - better would be nameLen - the most important attribute is that this is the length of some string
  • phoneL - better as phoneLen
  • DirV - why do we care that the underlying container type is a vector?
  • Info - too vague
  • newF - newFile
  • ct2 - ?
  • yes - a terrible name for a variable that could contain 'n'
In the world of software development, several years are likely to go by after the code is written. In the maintenance phase, it's almost certain that a different developer will be tasked to fix bugs that crop up during the life of the software. If the original developer uses names for classes, functions, and variables whose purpose can't be deduced easily, it's much more difficult for a maintenance programmer to understand the code and fix these bugs.

In your constructor you have this code -
C++:
    else
        {//If the file exist, read entire file into vector DirV.
          file.read(reinterpret_cast<char*>(&Dir), sizeof(Dir));
          do
          {
            DirV.push_back(Dir);
            file.read(reinterpret_cast<char*>(&Dir), sizeof(Dir));
          } while (!file.eof());
          file.close();
        }
Why are you calling read() twice?
Thanks for the suggestion. The reason I wrote the read like this is because I ran into problem reading the last element twice before. I did talk about this here and I wrote down in my notes to do this. Maybe this doesn't matter, but I don't want to take the chance and just put one more line.

Thanks
 
  • #43
yungman said:
Thanks for the suggestion. The reason I wrote the read like this is because I ran into problem reading the last element twice before.
It's not just bad form. It is actually wrong as written. What if you are reading from an empty file?
 
  • #44
Thanks everyone for the feedback. I did pay attention and understand about the importance of the names. It's not that I ignore all the suggestions from before. My situation is different, I am NOT a student, there is absolutely no chance I'll be working with anyone on programming in this life except if my grandkids ever want to work with grandpa. If that time comes(ever comes), you bet I will remember what you guys said. There is not going to be anyone else working with more programs, so I decided to shortcut it. The only one that needs to understand is me alone, I have my way of simplifying the names and I don't have issue with that.

Regarding to Constructor and Distructor. As I said before whether I am right or wrong, I do not want to run the HD or flash heavily not only for the slow speed, more importantly, both have finite number of cycles. I don't want to wear them out to do the heavy adding, deleting, sorting on the file. My goal started with the definition that I download the content to a vector, the rest of the program will work on the vector alone. Then upon ending the program, I write the updated file back to the HD. That is read once and write once to the HD or flash. Where better to put this task in Constructor and Distructor.

I totally disagree with the notion to worry about data corruption that might destroy the original good data in the file like Vanadium 50 said. So if you work with the file directly, every time you add or delete, you have to shift the elements up or down, when sorting, you read and write so many times. Your chance of screwing up the file is much higher than do it one time. Besides, hopefully user will detect the corruption of data and not save it. Screw up the file totally or partially is still screwing the file up, what's the difference? Data is destroyed either way. I might add the option in the program NOT to save to file if things looks bad though.

Again, thanks for all your help in getting this far. This is the first time I wrote this and this program is not done. I am thinking about using switch-case to select add, delete, display, display range into the program. This is just the bare bone of the program showing the data path and how I view in moving data. This part to me is the most important and most difficult. The other more fancy stuffs like options and sorting is much easier that this to me.

Thanks All.
 
Last edited:
  • #45
If I were writing this program, I would consider using two classes: one for an individual directory entry, and one for the directory as a whole.

The first class would contain name, phone number etc. for a single directory entry. It woud have member functions to create a new entry, read a single entry from disk, write it to disk, display the data, and edit the data (all applying to a single directory entry).

The second class would contain a vector whose elements are directory entries (i.e. objects of the first class). It would have member functions to read the entire directory from disk, write it to disk, search for a given name, create a new entry and insert it into the directory, display the entire directory in a table format, sort the directory by name or phone number, etc. These would all call upon member functions from the first class as necessary.
 
  • Like
Likes yungman
  • #46
yungman said:
My situation is different, I am NOT a student, there is absolutely no chance I'll be working with anyone on programming in this life except if my grandkids ever want to work with grandpa.
Wrong. You ARE the student, and we who respond to your questions are in the role of teacher.
yungman said:
If that time comes(ever comes), you bet I will remember what you guys said. There is not going to be anyone else working with more programs, so I decided to shortcut it. The only one that needs to understand is me alone, I have my way of simplifying the names and I don't have issue with that.
The time to remember what we've said is NOW, not some far-off time. You post your programs, and we attempt to make sense of them, despite your use of unhelpful and meaningless names.
You are NOT the only one who needs to understand your programs. How much harder do you think it is for us to help you if you seemingly go out of your way to make things more difficult to understand?
Maybe you're happy with your way of "simplifying the names," but from this side, all they do is convince us of your confusion.
yungman said:
Regarding to Constructor and Distructor. As I said before whether I am right or wrong, I do not want to run the HD or flash heavily not only for the slow speed, more importantly, both have finite number of cycles.
Using the hard drive or flash drive is totally irrelevant to what the constructor and destructor should be doing, which is creating an object and then destroying it, respectively. There should be other member functions that are tasked with filling an object with data, adding a contact, deleting a contact, etc. None of this should be done in a constructor.

In any case, I found a site that talks about the mean time before failure (MTBF) for typical hard drives -- somewhere between 100,000 and 1,000,000 hours, or between 11 and 110 years. Do you seriously think that your program is going to exercise a hard drive that much? Your concern is very much misplaced.
yungman said:
I totally disagree with the notion to worry about data corruption that might destroy the original good data in the file like Vanadium 50 said. So if you work with the file directly, every time you add or delete, you have to shift the elements up or down, when sorting, you read and write so many times. Your chance of screwing up the file is much higher than do it one time. Besides, hopefully user will detect the corruption of data and not save it. I might add the option in the program NOT to save to file if things looks bad though.
IMO you are NOT in a position to disagree with what @Vanadium 50 said, as you have nowhere near the knowledge of programming that he has. In his comment he gave a reason for his opinion - ignore it at your peril.
 
Last edited:
  • Like
Likes Vanadium 50
  • #47
jbriggs444 said:
Not being a C++ programmer, I had to spend 30 seconds with Google to learn about the break statement.

It's sibling, continue, is even more amazing.
 
  • #48
jtbell said:
If I were writing this program, I would consider using two classes: one for an individual directory entry, and one for the directory as a whole.

The first class would contain name, phone number etc. for a single directory entry. It woud have member functions to create a new entry, read a single entry from disk, write it to disk, display the data, and edit the data (all applying to a single directory entry).

The second class would contain a vector whose elements are directory entries (i.e. objects of the first class). It would have member functions to read the entire directory from disk, write it to disk, search for a given name, create a new entry and insert it into the directory, display the entire directory in a table format, sort the directory by name or phone number, etc. These would all call upon member functions from the first class as necessary.
Thanks, I have to think more, this is the starting point of the program, I am still thinking about the other add, delete, sort options. I will likely have more than one class. It's a challenge so far to put this together.

Thanks
 
  • #49
Mark44 said:
Wrong. You ARE the student, and we who respond to your questions are in the role of teacher.
The time to remember what we've said is NOW, not some far-off time. You post your programs, and we attempt to make sense of them, despite your use of unhelpful and meaningless names.
You are NOT the only one who needs to understand your programs. How much harder do you think it is for us to help you if you seemingly go out of your way to make things more difficult to understand?
Maybe you're happy with your way of "simplifying the names," but from this side, all they do is convince us of your confusion.
Using the hard drive or flash drive is totally irrelevant to what the constructor and destructor should be doing, which is creating an object and then destroying it, respectively. There should be other member functions that are tasked with filling an object with data, adding a contact, deleting a contact, etc. None of this should be done in a constructor.

In any case, I found a site that talks about the mean time before failure (MTBF) for typical hard drives -- somewhere between 100,000 and 1,000,000 hours, or between 11 and 110 years. Do you seriously think that your program is going to exercise a hard drive that much? Your concern is very much misplaced.
IMO you are NOT in a position to disagree with what @Vanadium 50 said, as you have nowhere near the knowledge of programming that he has. In his comment he gave a reason for his opinion - ignore it at your peril.
To clarify, I meant I am not a college student that have the whole career in front of me. Yes, I am a student here learning C++.

Point taken on the names.

Thanks
 
  • #50
jbriggs444 said:
It's not just bad form. It is actually wrong as written. What if you are reading from an empty file?
I have to experiment more with that, I did run into problem before. What will happen reading an empty file? Is it just reading garbage or can it do damage to the file?

Thanks
 
  • #51
yungman said:
To clarify, I meant I am not a college student that have the whole career in front of me.
I'm fairly sure that was already clear to most of us.
 
  • #52
About the part that read the file two times. This is the problem I am trying to avoid. Here is what happened when I deleted the read before the do-while loop:I made the first file.read into comment line. I move the DirV.push_back below the file read in the loop.

One read file.jpg


This is the result, the last line is repeated.
Read error.jpg


I have to think of some other way to fix this if I have to eliminate one read. BUT still, that doesn't help reading an empty file. The first read will read empty file.

What are the problems reading an empty file? If just reading garbage, then it's not too bad. But if it can do other damage, then it's not good.

Thanks
 

Attachments

  • One read file.jpg
    One read file.jpg
    34.4 KB · Views: 151
  • #53
yungman said:
I have to experiment more with that, I did run into problem before. What will happen reading an empty file? Is it just reading garbage or can it do damage to the file?
Step through the code mentally, thinking through what each line will do. Let us pull that code section down here so that we can examine it more easily.
C++:
    else
        {//If the file exist, read entire file into vector DirV.
          file.read(reinterpret_cast<char*>(&Dir), sizeof(Dir));
          do
          {
            DirV.push_back(Dir);
            file.read(reinterpret_cast<char*>(&Dir), sizeof(Dir));
          } while (!file.eof());
          file.close();
        }

Line 3: we start by attempting to read from the file into an array element. But the file is empty. So the read fails and the end file.eof() flag is set.

Line 4-5: We enter a do while loop. Since this is a do-while, there is no initial test of the termination condition.

Line 6: We do a DirV.push_back(Dir). One supposes that this somehow commits an array item to the in-memory directory. Based on the name "push_back", this is likely a metaphorical stack push. But the array entry we are pushing is garbage -- the read had failed.

Line 7: We attempt to read a second record, oblivious to the fact that we've already hit end of file.

Line 8: We check the loop termination condition. [One hopes and expects that the EOF condition remains set after multiple attempts to read past end of file]

Line 9: We close the file.
 
Last edited:
  • #54
yungman said:
About the part that read the file two times. This is the problem I am trying to avoid. Here is what happened when I deleted the read before the do-while loop:
Rule: Think before you code. You want to figure out the failure modes when writing the code, not when running it.

Rule: Always check the status code. [This one I picked up in a course on VMS system programming in the 80s. It was advice well worth listening to].

You want the sequence of operations to be:

Read
Test for end of file (not yet)
Push
Read next
Test for end of file (not yet)
Push
...
Read next
Test for end of file (EOF - exit)

There are a lot of ways to put that into a while loop.

You could put one read outside the loop and use:
Code:
Read
while not EOF
    Push
    Read
end while

Thinking back to first year programming in the '70's, when structured programming was just becoming all the rage, this is pretty much what we were taught to do.

Or you could test for the exit condition mid-loop

Code:
while (true)
    read
    if EOF then break
    push
end while

This has the advantage that you're not coding the read statement twice. And it puts the exit test where it belongs -- right when the exit condition arises.

I often find myself using the following construct - emulating a break.

Code:
DONE = false
while ( not DONE )
    read
    if not EOF
    then
        push
    else
        DONE = true
    end if
end while
 
Last edited:
  • #55
yungman said:
Where better to put this task in Constructor and Distructor.

In methods on the object with names like read_data and write_data.

You do not want to put code that does I/O into a constructor or destructor. The constructor and destructor should only be for allocating and deallocating memory for the object itself (which is done automatically by the compiler), not for reading data from disk or writing data to disk. If you try to read data from disk in an object's constructor, and something goes wrong, the object will be in an inconsistent state. If you try to write data to disk in an object's destructor, and something goes wrong, the object is gone and you have no way to recover from the error.
 
  • Like
Likes pbuk, Vanadium 50 and yungman
  • #56
PeterDonis said:
In methods on the object with names like read_data and write_data.

You do not want to put code that does I/O into a constructor or destructor. The constructor and destructor should only be for allocating and deallocating memory for the object itself (which is done automatically by the compiler), not for reading data from disk or writing data to disk. If you try to read data from disk in an object's constructor, and something goes wrong, the object will be in an inconsistent state. If you try to write data to disk in an object's destructor, and something goes wrong, the object is gone and you have no way to recover from the error.
Ah, I see what you mean about writing in Distructor, that if that fails, the program is closed. So I should use member function to write to file.

But what's wrong loading the file with Constructor? What do you mean the object will be in an inconsistent state?

Thanks
 
  • #57
jbriggs444 said:
This has the advantage that you're not coding the read statement twice.

The "C/C++ way" to do that is do...while. That executes at least once.
 
  • #58
yungman said:
what's wrong loading the file with Constructor? What do you mean the object will be in an inconsistent state?

If an error happens inside the constructor, there is no guarantee that the object will be constructed correctly. So you should not do anything inside a constructor that might cause an error.
 
  • #59
Vanadium 50 said:
The "C/C++ way" to do that is do...while. That executes at least once.
Possibly I am missing something. That would seem to mean that the exit condition needs to be checked twice.
Code:
do {
    read
    if not EOF
        push
    end if
} while not EOF
 
  • #60
jbriggs444 said:
Rule: Think before you code. You want to figure out the failure modes when writing the code, not when running it.

Rule: Always check the status code. [This one I picked up in a course on VMS system programming in the 80s. It was advice well worth listening to].

You want the sequence of operations to be:

Read
Test for end of file (not yet)
Push
Read next
Test for end of file (not yet)
Push
...
Read next
Test for end of file (EOF - exit)

There are a lot of ways to put that into a while loop.

You could put one read outside the loop and use:
Code:
Read
while not EOF
    Push
    Read
end while

Thinking back to first year programming in the '70's, when structured programming was just becoming all the rage, this is pretty much what we were taught to do.

Or you could test for the exit condition mid-loop

Code:
while (true)
    read
    if EOF then break
    push
end while

This has the advantage that you're not coding the read statement twice. And it puts the exit test where it belongs -- right when the exit condition arises.

I often find myself using the following construct - emulating a break.

Code:
DONE = false
while ( not DONE )
    read
    if not EOF
    then
        push
    else
        DONE = true
    end if
end while
I tried your suggestion:

One read file.jpg


It still print out the last line twice.

I wish I can find the thread that we talked about this, it's tricky. The eof() does not become true right away and double write the last data.
 
  • #61
jbriggs444 said:
the exit condition needs to be checked twice.

What is wrong with that? Logically, the condition for deciding to push the record is not necessarily the same as the condition to continue reading. They happen to be the same in this case, but they don't have to be.
 
  • Like
Likes jbriggs444
  • #62
I have to do this to make it work. I remember last time when I have the issue, the eof() does not become true upon reading the last element, it's one after the last element. But it will still contain the last element in the buffer. So the next push_back, it will repeat writing the last element again.

The following way can fix it:
One read file.jpg


We spent a lot of time on this, it's so important that I wrote down clearly in my notes.

Unless there is any reason against this way, I am going to put this in my program. This will definitely avoid reading empty file.

Thanks
 
  • #63
It has been stated at least three times by three different people that you should NOT be doing file I/O in the constructor, and same for the destructor.
 
  • Like
Likes Vanadium 50
  • #64
Mark44 said:
It has been stated at least three times by three different people that you should NOT be doing file I/O in the constructor, and same for the destructor.
I know, give me time to change the program, want to resolve the double read first. I still need to change the names also.

Then I can delete the Constructor and Distructor, can't think of any reason to keep them.

I just created readFile() and writeFile() and copy the Constructor and Distructor into them resp. Then write code in main() to call readFile() at the beginning and call writeFile at the end of the program.
 
Last edited:
  • #65
I fixed the program, file reading and writing are out of the constructor and distructor. In fact, I got rid of the constructor and distructor. I don't see any use of them. This is a running program.

I change the names to more readable. I don't need to have double read in line 30 after I move the while(!file.eof()) to the top instead of do-while().

This is the .h file
C++:
#ifndef VectorCall_H
#define VectorCall_H
#include <vector>
#include <fstream>
class DirectoryClass
{
  private:
    const static int nameLen = 25, phoneLen = 12;
  public:
    struct Directory { char name[nameLen];    char phone[phoneLen]; };
    std::vector<Directory>DirV;
    Directory Dir; bool newF, failOpen;
    std::fstream file;
 
    bool readFile()//
    {
        failOpen = false;
        file.open("Directory.dat", std::ios::in | std::ios::binary);
        if (file.fail())
        {//If file doesn't exist, create the file
            std::cout << " Fail to open file.\n";
            file.open("Directory.dat", std::ios::out | std::ios::binary | std::ios::app);
            file.close();
            failOpen = true;
        }
        else
        {//If the file exist, read entire file into vector DirV.
            while (!file.eof())
            {
                file.read(reinterpret_cast<char*>(&Dir), sizeof(Dir));
                if (file.eof()) {  break; }
                DirV.push_back(Dir);
            };
            file.close();         
        }
        return failOpen;
    }
    void createFile()
    { file.open("Directory.dat", std::ios::out | std::ios::binary | std::ios::app);
      file.close(); }
    void writeFile()
    {
        int ct2 = 0;
        file.open("Directory.dat", std::ios::out | std::ios::binary);
        do//write the updated data in vector DirV into the file before closing
        {
            file.write(reinterpret_cast<char*>(&DirV[ct2]), sizeof(DirV[ct2]));
            ct2++;
        } while (ct2 < DirV.size());
        file.close();
    }
    void push_backV() { DirV.push_back(Dir); }
    void print() { std::cout << "Name:  " << Dir.name <<
            "   Phone:  " << Dir.phone << "\n\n"; }
};
#endif
This is the source.cpp
C++:
#include <iostream>
#include <string>
#include <vector>
#include "VectorCall.h"
using namespace std;

int main()
{
  char more;  int index = 0; const int nameLen = 25, phoneLen = 12;
  DirectoryClass Information;
  char displayAll, tryAgain = false;
  Information.readFile();
  if (Information.failOpen == true)
  {cout << " Fail to open file, want to try again? "; cin >> tryAgain;}
  if (tryAgain == true) Information.readFile();
  if (Information.failOpen == true)
  {//First time set up the directory by entering all the names and information
    cout << " File does not exist, let's create the file. " <<
         "You need to enter informations:\n\n";
    Information.createFile();
    cin.ignore();
    do
    {   cout << " Enter name:  "; cin.getline(Information.Dir.name, nameLen);
        cout << " Enter phone:  "; cin.getline(Information.Dir.phone, phoneLen);
        //Info.print();
        Information.push_backV();//writing into vector DirV.
        cout << " Do you want to enter another name?  "; cin.get(more);
        cin.ignore();
    } while (tolower(more) == 'y');
  }
//Ask whether to display all the information in the file.
    cout << "  Press 'y' to see the whole list.  "; cin >> displayAll;
    cin.ignore(); cout << endl;
    if (displayAll == tolower('y'))
    {   do
        {  cout << "Name stored in DirV is:  " << Information.DirV[index].name <<
                  " phone:  " << Information.DirV[index].phone << "\n\n";
           index++;
        } while (index < Information.DirV.size());
    }
    else { cout << " Bye\n\n"; }
    Information.writeFile();
    return 0;
}

Hope this looks better. Let me know what else.I was looking at the next program in the book, I notice even with the Declaration and Implementation files, the book shows using a lot of internal functions within the main program body. I would think it's better to push as much to external as possible.

I understand Class is a blueprint to create object incidence. But I keep thinking it's more useful to put as much work ( functions) into the Specification and Implementation files as possible so the main() don't have to do a lot. It's like calling external functions to do the job. Isn't it the point that try to use external function( or whatever name you call) to do as much as possible so you can make the main() as simple as possible for fast turn around? It's like structure, define the structure and use it to make lives easier.

I can envision having a class to read and write file, using arguments like 1) c-string that contains the filename, path where to save or to open the file, 2) the kind of file and 3) the vector to write to the file like what I am doing. So this Class can read and write different files with different ADT datatype.

Then another class to define structure, cin information, store into a vector like what I am doing. Within that, I can put add element, delete element, sort elements.

With that, the main() just call them to do all the jobs. So far, things are still short, I use inline function. But I am sure when I add in the add, delete and sort, I have to have a separate Implementation file to avoid a very long declaration file.

Thanks
 
Last edited:
  • #66
yungman said:
What are the problems reading an empty file? If just reading garbage, then it's not too bad. But if it can do other damage, then it's not good.
If you try to read from an empty file, you reach end-of-file immediately. I tested this with the following program:
C++:
#include <iostream>
#include <fstream>
#include <iomanip>

using namespace std;

int main ()
{
//  Open a file for output, but don't write anything to it.
//  Then close it.

    ofstream outputFile ("emptyfile.dat");
    cout << "Trying to open emptyfile.dat for output..." << endl;
    if (outputFile)
    {
        cout << "Successfully opened emptyfile.dat for output." << endl;
    }
    else
    {
        cout << "Failed to open emptyfile.dat for output." << endl;
    }
    outputFile.close();
    cout << "Closed emptyfile.dat." << endl;

//  Open that file for input, and try to read from it.

    cout << "Trying to open emptyfile.dat for input..." << endl;
    ifstream inputFile ("emptyfile.dat");
    if (inputFile)
    {
        cout << "Successfully opened emptyfile.dat for input." << endl;
        cout << "Trying to read from emptyfile.dat..." << endl;
        string line;
        if (getline (inputFile, line))
        {
            cout << "'" << line << "' was read from emptyfile.dat." << endl;
        }
        else
        {
            cout << "EOF on emptyfile.dat." << endl;
        }
        inputFile.close();
        cout << "Closed emptyfile.dat." << endl;
    }
    else
    {
        cout << "Can't open emptyfile.dat." << endl;
    }    

    return 0;
}
Output:
Code:
Trying to open emptyfile.dat for output...
Successfully opened emptyfile.dat for output.
Closed emptyfile.dat.
Trying to open emptyfile.dat for input...
Successfully opened emptyfile.dat for input.
Trying to read from emptyfile.dat...
EOF on emptyfile.dat.
Closed emptyfile.dat.
 
  • Like
Likes yungman
  • #67
I am so glad I posted my program in post 65! I can't find my original program now that I am ready to get back to it! I have to copy both files from post 65 to recreate the program! That really save my day.

I finally finish the other part of the program in sorting, adding, deleting, now back to the Class and files.
 

Similar threads

Back
Top