Click here to Skip to main content
15,891,657 members
Please Sign up or sign in to vote.
2.00/5 (1 vote)
See more:
Hello, guys.

Firstly, my program’s function fillCards saves a name and a surname in the structure and then writes it to cards.txt file. Then the function readCard reads structures to the array and show them. When user enters the number of structure, the function writes the structures of the array (except the structure which number is the same as the user’s entered number) to new.txt file. The problem is that new.txt file is filled with the same number of structures as cards.txt and instead of ignored structures the last structure is repeatedly written. How to write the particular structures from array to new.txt file and nothing more? I will be very greatful for any help.

C++
#include <iostream>
#include <fstream>
#include <string>
#include <cstring>

using namespace std;

struct card {
       char name[40];
       char surname[40];
};

card A = {"Anna", "Karenina"};
card S;

int fillCards() {

    //cards.txt is filled with stuctures
    char answer;
    int i = 0;

    ofstream file ("cards.txt", ios::binary);
    if (!file)
    cerr << "Unable to open cards.txt" << endl;

    do
    {
    i++;
    char word1 [40];
    char word2 [40];

    cout << "Enter a name..." << endl;
    cin >> word1;

    cout << "Enter a surname..." << endl;
    cin >>word2;


    strcpy (A.name, word1);
    strcpy (A.surname, word2);

    file.write((char *) &A, sizeof(card));

    do {
        cout << "Would you like to enter next person? (Y/N)" << endl;
        cin >> answer;
        answer = toupper(answer);
        }
    while ((answer != 'Y') && (answer != 'N'));
    }
    while ( answer == 'Y');

    file.close();

    return 0;
}


int readCards() {

    int i, k, length;


    //Structures are read to array from card.txt file

    ifstream file ("cards.txt", ios::binary);

    if (!file)
    cerr << "Unable to open cards.txt" << endl;

    file.seekg (0, ios::end);
    length = file.tellg();
    file.seekg (0, ios::beg);

    i = length/sizeof(card);

    card *arr = new card[i];

    for (int n = 0; n < i; n++) {
    file.read((char *) &S, sizeof(card));
    arr[n] = S;
    cout << (n+1) << " " << arr[n].name << " " << arr[n].surname << endl;
    }

    file.close();

    //Structures are written to new.txt file
    _unlink("cards.txt");
    
    ofstream rubber ("new.txt", ios::binary);

    if (!rubber)
    cerr << "Unable to open new.txt" << endl;

    cout << "Enter a number of person which you want to delete" << endl;
    cin >> k;

    for (int x = 0; x < i; x++) {
    if ((x + 1) != k ){
                rubber.write((char *) &arr[x], sizeof(card));
                cout << (x + 1) << " " << arr[x].name << " " << arr[x].surname << endl;
                    }
    }

    rubber.close();

    delete[] arr;

    return 0;
}


int showCards () {

    //Read new.txt file and show it to the user

    cout << "\nNaujas turinys" << endl;

    int m = 0;
    ifstream file ("new.txt", ios::binary);

    if (!file)
    cerr << "Unable to open new.txt" << endl;

    while((!file.eof()) && (!file.fail())) {
    m = m + 1;
    file.read((char *) &S, sizeof(card));
    cout << m << " " << S.name << " " << S.surname << endl;
    }

    file.close();
    return 0;
}

int main() {

    fillCards();
    readCards();
    showCards();

    return 0;
}


I've corrected mistake of number of the dynamic array's elements. But still my problem exists.
For example the contents of cards.txt :
1 Charlotte Smith
2 Emma Jones
3 Sophia Baker
4 Bernadette Soubirous

Then I choose number 2 (the value of k) and then program writes elements of array to new.txt except the element with Emma Jones. The contents of new.txt look like this:
1 Charlotte Smith
2 Sophia Baker
3 Bernadette Soubirous
4 Bernadette Soubirous

But I need the contents of new.txt to be like this:
1 Charlotte Smith
2 Sophia Baker
3 Bernadette Soubirous

Any ideas?
Posted
Updated 20-Mar-12 9:50am
v2
Comments
chandanadhikari 20-Mar-12 12:39pm    
hi,
try to print all the contents of the first file that you create(cards.txt) then it will be clear if the file is getting formed correctly.post here what you see
Nelek 20-Mar-12 14:13pm    
Just a silly question... what is the "i" in the first do...while at filling the array for? You just count up, but don't use it at all. Did you want to pass the number of introduced members to somewhere else?

Another bug that is probably not the source of your problem but should be noted:
C++
int i, m = 0, n, k;
card *arr = new card[i];

This allocates an array of random size, because i is not initialized. Your compiler should generate a warning message. If not, increase the compiler warning level.

You may use the file size divided by the structure size to get the number of structures stored in the file and use this as array size.
 
Share this answer
 
Comments
infogirl 20-Mar-12 13:34pm    
Thanks, actually compiler warns me about that.. Trying to figure out how to determine the size of file.
Nelek 20-Mar-12 13:48pm    
Have you consider to open the file for read and check how many "end of line" are there? That would give you a chance to declare the array with the needed number of items. Afterwards you could continue with your code as you do.
enhzflep 20-Mar-12 13:59pm    
There aren't any EOL markers in the file - remember, it's a binary file, not a text one.

With that said - Determining the number of elements is elemental.... Each struct contains two char arrays of 40 bytes each -
So, numElements = fileSize / 80
Nelek 20-Mar-12 15:21pm    
Right. Didn't read on detail, my bad.
enhzflep 20-Mar-12 14:04pm    
See below - you can calculate record count with:
NumRecords = fileSize / 80bytes

Also, I changed the code in each of your file-reading loops.
Here's the one from showCards() - it's virtually identical to the one in readCards() - the 2 differences being:
1) that in readCards, we need to copy the temp struct 'S' to the array
2) you print from the array, rather than the temp struct 'S'


int index = 0;
while(file.read((char *) &S, sizeof(card)) != 0)
{
cout << ":" << index+1 << " " << S.name << " " << S.surname << endl;
index++;
}
I said it earlier and I'll say it again - the file-reading loops in your code don't work as expected..

I suggest you copy the file-reading loop I provided earlier and replace the one in ShowCards with it.

Also, have you considered that when a user name is entered and read into S.name and S.surname, that you're not clearing out any old data in these arrays. This causes erroneous data to be written to both cards.txt and new.txt

Consider these two names entered:
name: "Peter"
surName: "Fitzgibbon"

Now, consider that the next time through the loop, this name is entered:
name: "Lou"
surName: "Pan"

Your name/surname arrays will now hold:

"Lou\0r"
"Pan\0gibbon"

While you won't see the 'r' or the 'gibbon' if you print this text, take a look at the file with a hex-editor and you'll see the extra text there.

The solution? Clear the arrays before you store data to them. Just before you strcpy the read data, memset A.name and A.surname

When you change the loop and fix the uninitialized data, your program works just fine. :)
 
Share this answer
 
The line
C++
while((!file.eof()) || (!file.fail())) {


Should probably be

C++
while((!file.eof()) && (!file.fail())) {


You should step through your program with the debugger and see if the variables and tests are doing what you expect them to do.
 
Share this answer
 
Comments
infogirl 20-Mar-12 12:42pm    
I have changed || to && but still instead of eleminated stucture appeared additional structure the same as the last. Debuger returns 0 and shows no errors if I understand well. I'm very new at c++ and at programming at all. By the way, I use Codeblocks and Windows Vista.. That's i get on the prompt line, for example: I choose to eleminate charlotte smith:
the conntents of cards.txt:
1 charlotte smith
2 emma moore
3 sophia baker
4 sophia baker

The contents of new.txt:
1 emma moore
2 sophia baker
3 sophia baker
4 sophia baker
JackDingler 20-Mar-12 13:50pm    
When you step through the debugger, does the code do anything you don't expect, such as escape a loop early, or do the variables have values that are not correct?

The debugger won't necessarily stop and tell you, that you have an error. But it can help you identify code that isn't workign the way you expect.
Nelek 20-Mar-12 14:15pm    
Using the same example than here... what did you get as output when you used the "||"?
chandanadhikari 20-Mar-12 13:46pm    
hi,
there is some logical error i think. if i am getting your problem statement correctly then, when one name is eliminated in the new text file then cards.txt and new.txt should not have the same number of entries in the first place.
I'd suggest to delete the output file before writing to it:

C++
_unlink("cards.txt"); // add this.
ofstream file ("cards.txt", ios::binary);


My guess is that the binary stream writes all records but one to the existing file in-place, and leaves the last one intact.

Hope this helps,

Pablo.
 
Share this answer
 
Comments
infogirl 20-Mar-12 11:04am    
I deleted cards.txt before creating new.txt file where particular stuctures are written... I have just tried that but nothing changed. :/ But thanks anyway!

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900