Guys, I've been stuck on this for a while now. This is actually one of my assignments, and I'm really lost. This is the assignment:
-------------------------------------------------------------------------------------------
You manage a .txt file containing the customer ID number and account balance of the members of a bank. Last week, a computing error caused each customer's account balance to get reversed. For example, if someone had an account balance of 132.64, this was reversed to become: 462.31. Write a program which will input the file and output a file containing the corrected account balances next to each customer ID number (a 9 digit number with no spaces).

Each line of the .txt file is of the form:

ID# Balance

ADDITIONAL REQUIREMENTS: Allow the user to specify both the input and output filenames in each problem. Program should perform the required checks for input and output files.
-------------------------------------------------------------------------------------------

Here is my code so far:

#include<fstream>
#include<iostream>
#include<string>
#include<cstdlib> //to use exit(1)

using namespace std;

int main()
{
    ifstream inFile, inSortFile;
    ofstream outFile;     
    ifstream checkFile;
    string inFileName, outFileName, ID, balance;
    
    do
    {
        cout << "What is the name of the file you would like to read from? ";
        cin >> inFileName;
        inFile.open(inFileName.c_str());
        if(inFile.fail()) cout << "The file called " << inFileName << " does not exist." << endl;
    }while(inFile.fail());
    
    cout << "The file was opened." << endl;
    cout << "Where would you like to output the data: ";
    cin  >> outFileName;
    
    checkFile.open(outFileName.c_str()); 
        
        if(!checkFile.fail())
        { //opening outer if
            cout << "A file with the name " << outFileName << " already exists." << endl
                 << "Do you wish to overwrite the file? Enter n or N if no, anything else if yes: ";
            
            char answer;
            cin >> answer;
            
            if(answer=='n'||answer=='N')
            { //opening inner if
                cout << outFileName << " will not be overwritten.\n";
                system("PAUSE");
                exit(1); 
            } //closing inner if
        } //closing outer if
        
        checkFile.close(); 
        outFile.open(outFileName.c_str()); 
        cout << "The data was successfully output to " << outFileName << "." <<endl;
    
    int count = 0;
    while(inFile.good())
    { //opening while
         inFile >> ID >> balance;
         outFile << ID << " " << balance << endl;
    } //closing while
    
system("pause");
return 0;
}

Right now pretty much all the code does is just copy the old file to the new one. But I want it to copy the first part of each line - ID#, but then reverse the other number, well what the assignment is asking me to do. I tried to store it as an array and then reverse it, but it's not working. That approach is probably wrong anyway because if it's a decimal, the point won't be put in the right place - 41.2 would become 2.14 instead of 21.4. PLEASE GUYS HELP! Any idea how to accomplish the task? Anything is appreciated, nothing too crazy though. I want to understand this and I'm still a beginner.

I'm sorry everyone I meant how can I take a string from a . txt, reverse it and write it to another .txt in C++?

Two possibilities:

Find the '.' and remove it. Reverse the number. Add the '.' back in.

Reverse the value. If the '.' is not in the proper position, switch characters until it's in the correct position. I.E., If your number reversed is
52.1232 switch the dot giving
521.232 and switch again
5212.32 and output the value.

Ok, I tried moving the decimal around, but every time the number in my file changes, the decimal point gets messed up again. So how would I delete the decimal and then write it back inside? I can delete it and I'm also saving its location, but how can I write it back inside? Here's what I did:

#include<fstream>
#include<iostream>
#include<string>
#include<cstdlib> //to use exit(1)

using namespace std;

int main()
{
    ifstream inFile, inSortFile;
    ofstream outFile;     
    ifstream checkFile;
    string inFileName, outFileName, ID, balance;
    
        cout << "What is the name of the file you would like to read from? ";
        cin >> inFileName;
        inFile.open(inFileName.c_str());
        if(inFile.fail())
            {
                cout << "The file " << inFileName << " does not exist." << endl;
                system("pause");
                return 0;
            }
    
    cout << "The file was opened." << endl;
    cout << "Where would you like to output the data: ";
    cin  >> outFileName;
    
    checkFile.open(outFileName.c_str()); 
        
        if(!checkFile.fail())
        { //opening outer if
            cout << "A file with the name " << outFileName << " already exists." << endl
                 << "Do you wish to overwrite the file? Enter n or N if no, anything else if yes: ";
            
            char answer;
            cin >> answer;
            
            if(answer=='n'||answer=='N')
            { //opening inner if
                cout << outFileName << " will not be overwritten." <<endl;
                system("PAUSE");
                exit(1); 
            } //closing inner if
        } //closing outer if
        
        checkFile.close(); 
        outFile.open(outFileName.c_str());

       
    int count = 0;
    while(inFile.good())
    { //opening while
         inFile >> ID >> balance;
         outFile << ID << " ";
         
         for(int i = balance.length(); i!=0; i--)
         {
//This part deletes the decimal point and reverses the number, it also shows the location of the decimal
//******************************************************************************    
            if (balance[i-1] == '.')
            {
                int a = i;
                balance[i-1] = balance[i];
                i--;
                cout << "The position of the decimal point is " << a << endl;
            }
//******************************************************************************         
            outFile << balance[i-1];
         }
         outFile << endl;
         
    } //closing while
    
    cout << "The data was successfully output to " << outFileName << "." <<endl;
system("pause");
return 0;
}

Too complicated.

During your loop,
1) If you see the '.' just don't output it
2) When you have 2 characters (digits) left, output a '.'

Too complicated.

During your loop,
1) If you see the '.' just don't output it
2) When you have 2 characters (digits) left, output a '.'

But the thing is it's not just two digits left. It could be 3 or 4 digits left, based on the file.
123.1 would become 132.1
12.136 would be 63.121
14.2 would be 24.1

If the numerical input can be any floating point value, then you have a harder job. One way to try might be convert the floating point value to a string using a stringstream, find the decimal point and count how many digits are present to the right of the decimal point. Then multiple the floating point value by 10 raised to the power equal to the number of digits to the right of the decimal point. Then cast the floating point to an int, reverse the digits of the int and divide the value of the reversed int by the power of ten used earlier.


Alternative once you have the index of the decimal point in the string, remove it, reverse the string, and insert the decimal point back into the string before using a stringstream to convert the string back to a floating point value

Such a mess. Much easier if file format restricted to known number of digits to the right of the decimal point.

Edited 5 Years Ago by Lerner: n/a

But the thing is it's not just two digits left. It could be 3 or 4 digits left, based on the file.
123.1 would become 132.1
12.136 would be 63.121
14.2 would be 24.1

So?

What is this loop supposed to do?

for(int i = balance.length(); i!=0; i--)
         {
//This part deletes the decimal point and reverses the number, it also shows the location of the decimal
//******************************************************************************    
            if (balance[i-1] == '.')
            {
                int a = i;
                balance[i-1] = balance[i];
                i--;
                cout << "The position of the decimal point is " << a << endl;
            }
//******************************************************************************         
            outFile << balance[i-1];
         }

And what is i? Is it ever equal to 2?

> Alternative once you have the index of the decimal point in the string, remove it,
> reverse the string, and insert the decimal point back into the string

Yes, Lerner. The simple way is the best way - if you want to manipulate text, treat it as text; if you want to perform arithmetic, treat it as a number.


> before using a stringstream to convert the string back to a floating point value

Just read it in as a string. Also sidestep the murky area of floating point rounding errors. Something like:

bool reverse_amounts( const char* in_path, const char* out_path )
{
    std::ifstream input(in_path) ;
    std::ofstream output(out_path) ;
    std::string id, amount ;
    while( input >> id >> amount ) output << id << ' ' << reverse_amount(amount) << '\n' ;
    return input.eof() && output.good() ;
}

> Such a mess. Much easier if file format restricted to known number of digits
> to the right of the decimal point.

It is a known number of digits to the right of the decimal point. Just that it is not a constant known at compile-time.

std::string reverse_amount( std::string amount )
{
    constexpr char DOT = '.' ;
    auto dot_pos = amount.find( DOT ) ; // locate the dot
    bool found_dot = dot_pos != std::string::npos ;
    if(found_dot) amount.erase( dot_pos, 1 ) ; // remove it
    std::reverse( amount.begin(), amount.end() ) ; // reverse the string
    if(found_dot) amount.insert( dot_pos, 1, DOT ) ; // and put it back
    return amount ;
}

Edited 5 Years Ago by vijayan121: n/a

So?

What is this loop supposed to do?

for(int i = balance.length(); i!=0; i--)
         {
//This part deletes the decimal point and reverses the number, it also shows the location of the decimal
//******************************************************************************    
            if (balance[i-1] == '.')
            {
                int a = i;
                balance[i-1] = balance[i];
                i--;
                cout << "The position of the decimal point is " << a << endl;

//******************************************************************************         
            outFile << balance[i-1];
         }

And what is i? Is it ever equal to 2?

Basically i is initially the length of the string that I'm receiving, for example length of 12.34. So that loop is pretty much taking the string balance, writing it into an array and then taking that array, reversing it and writing it to the output file. The stuff in the if condition is finding the period and deleting it and giving me its location (a is the cell where the '.' is in an array). And yea, i can be 2, it's the string length. And by the way, all of this extra stuff is going to go into the if section, because otherwise the program is fine, it's just the period that's confusing me.

My questions were there to help you answer your question, not explain the loop to us.

And yea, i can be 2, it's the string length.

and where does the period go? In the 6th position? The 3rd? Or...?

Vijayan's code should reverse 23.678 to 87.632 if that's what you want and are willing/able to use all the resources in the STL string class and the STL algorhithm class. But everything done in his code is doable in classic C++ using the same logic. To do so:

string input = "23.678";
char cInput[] = input.c_str();
int len = strlen(cInput);
int decimalIndex = 0;

//find position of decimal point, if any
for(int index = 0; )
  if current element of cInput is a decimal point
    set decimalIndex to index

if(decimalIndex not equal to 0)
  //remove the decimal point
  shift all elements of cInput to the right of decimalIndex to the left by one

//reverse cInput using standard functions or by raw code

//replace the decimal point, if there is one
if(decimalIndex not equal to zero)
  shift all elements at or to the right of decimalIndex in the reversed version of cInput to the right by one 

assign a decimal point to the element in reversed version of cInput with index equal to decimalIndex.

Edited 5 Years Ago by Lerner: n/a

My questions were there to help you answer your question, not explain the loop to us.

and where does the period go? In the 6th position? The 3rd? Or...?

If there are two numbers? If there are two numbers, then how would the period go in 3rd position? If I have 2.6 I want 6.2. If I have 32.1, I want 12.3. I just want to keep the period where it originally was, but reverse the number. And sorry, I haven't seen anything like vijayan121's code, and this program is only supposed to use class material.

Vijayan's code should reverse 23.678 to 87.632 if that's what you want and are willing/able to use all the resources in the STL string class and the STL algorhithm class. But everything done in his code is doable in classic C++ using the same logic. To do so:

string input = "23.678";
char cInput[] = input.c_str();
int len = strlen(cInput);
int decimalIndex = 0;

//find position of decimal point, if any
for(int index = 0; )
  if current element of cInput is a decimal point
    set decimalIndex to index

if(decimalIndex not equal to 0)
  //remove the decimal point
  shift all elements of cInput to the right of decimalIndex to the left by one

//reverse cInput using standard functions or by raw code

//replace the decimal point, if there is one
if(decimalIndex not equal to zero)
  shift all elements at or to the right of decimalIndex in the reversed version of cInput to the right by one 

assign a decimal point to the element in reversed version of cInput with index equal to decimalIndex.

Hmmm.. Lerner thanks for this, I couldn't really understand Vijayan's code. I'll think more about this, see what I can come up with.

OK, OK. Here's what I'm trying to get you to realize.
1) A dollar amount ALWAYS has 2 decimal places. (This comment is based on your misunderstanding of my previous post.)
2) To reverse the balance using your loop definition (with 1 minor change)

for(int i = balance.length()[B]-1[/B]; i>=0; i--)
    {
        If [B]i[/B] (the loop counter) indicates there are only 2 digits left in your balance value
            output the '.' (you are at the cents portion)
        If the current [B]balance[/B] character is not a '.'
            output the current [B]balance[/B] character (but [B]not[/B] the '.' from the balance value)
    }

Now look back at my posts. Do they make any sense now?

OK, OK. Here's what I'm trying to get you to realize.
1) A dollar amount ALWAYS has 2 decimal places. (This comment is based on your misunderstanding of my previous post.)
2) To reverse the balance using your loop definition (with 1 minor change)

for(int i = balance.length()[B]-1[/B]; i>=0; i--)
    {
        If [B]i[/B] (the loop counter) indicates there are only 2 digits left in your balance value
            output the '.' (you are at the cents portion)
        If the current [B]balance[/B] character is not a '.'
            output the current [B]balance[/B] character (but [B]not[/B] the '.' from the balance value)
    }

Now look back at my posts. Do they make any sense now?

OMG... I am an idiot! Wow, I just realized that dollar amounts would have 2 decimals! Thanks for clearing that up, it makes everything much easier! Let me just finish the code.

Ok, I'm completely lost right now. My loops either change everything after the decimal to the decimal points, or insert extra numbers in between, or replace the point with a number, but I just can't move the point itself, must have written like 50 loops by now.
Here's what I'm trying to do.
Suppose balance is 462.31.

if (balance [balance.length()-3] == '.')
{
   shift everything starting from that point to the left;
   delete the last entry; //I assume it would be blank or repeat the last character
                          //I don't want to keep it there because it will mess up the reversed array

   reverse the array;
   insert a decimal point at balance.length()-3;
}

How can I do this? Please, I've been trying to do this for five hours now. All of my loops are just inserting random numbers or replacing the numbers instead of moving them around.

This loop is removing the decimal point without affecting the outer loop counter i, but then when I output a file it's adding a bunch of numbers. For example:

Input:

222222222 462.31
333333333 12345

Output:

222222222 31 13264
333333333 54321

for(int i = balance.length(); i!=0; i--) // OPEN OUTER LOOP
         {//opening for
         
         //IF THERE IS A DECIMAL POINT  
        
           if (balance[balance.length()-3] == '.')
            {
                for (int a = balance.length()-3; a!=balance.length(); a++)
                    {
                        balance[a] = balance[a+1];
                        outFile << balance[a];
                    }
                //cout << "The position of the decimal point is " << a << endl;
            }
            
           // END IF THERE IS A DECIMAL POINT   
              
            else
            outFile << balance[i-1];
            
         }                                       //CLOSING OUTER FOR
         outFile << endl;

I pretty much want it to shift everything after the decimal point, but if I start at a=0, it's going to shift everything starting from the beginning and the decimal point stays where it was and this loop is giving me the ouput above.

Edited 5 Years Ago by Assassin7893: why didn't start at a=0

ok, i'm completely lost right now. My loops either change everything after the decimal to the decimal points, or insert extra numbers in between, or replace the point with a number, but i just can't move the point itself, must have written like 50 loops by now.


Look at my post and READ the code segment!
Follow it exactly!
Change nothing!
Add nothing!
Do not add any shifts! Do not add any if (something-3) tests!

I gave you EXACTLY the algorithm you need. Exactly!

What am I missing here?

for(int i = balance.length()-1; i>=0; i--) // OPEN OUTER LOOP
         {
            if (balance[i]=='.' && balance.length()-i==2)
                {
                    outFile << '.';
                }
            else
                {
                    outFile << balance[i];
                }
 
         }                                       //CLOSING OUTER FOR
         outFile << endl;

Edited 5 Years Ago by Assassin7893: n/a

Ok, I think I almost got this... Unless I screw up again somewhere. Just have to output '.' now

Can't figure out what goes into that if statement. if (i==2) works but only for numbers where you have 3 digits in front.

for(int i = balance.length()-1; i>=0; i--) // OPEN OUTER LOOP
         {
            if (balance[i]=='.')
                {
                    i--;
                    outFile << balance[i];
                    if (i==2) //THIS CONDITION IS GIVING ME TROUBLE
                    outFile << '.';
                }
            else
                {
                    outFile << balance[i];
                }
 
         }                                       //CLOSING OUTER FOR
         outFile << endl;
         
    } //closing while
for(int i = balance.length()-1; i>=0; i--)
    {
        If i (the loop counter) indicates there are only 2 digits left in your balance value
            output the '.' (you are at the cents portion)
        If the current balance character is not a '.'
            output the current balance character (but not the '.' from the balance value)
    }

if I see that the character is '.', then, to skip it, I decrease i again. Then my i changes and the period is not in the right place. I can get the '.' with two numbers after it, but then the program keeps the first dot. Or I can remove both dots, but somehow I just can't remove the original dot and place this one in the right position.

This loop is giving me ridiculous output, and the one a post above is only working when my number is in the format xxx.xx

for(int i = balance.length()-1; i>=0; i--) // OPEN OUTER LOOP
         {
            
            if (i==2)
            {
                outFile << balance[i];
                outFile << '.';
            }
            if (balance[i]!='.')
            {
                outFile << balance[i];
            }
         }                                       //CLOSING OUTER FOR

INPUT:
111111111 62.31
222222222 462.31
333333333 12345
444444444 3662.21
555555555 36237.21
555555555 333.42

OUTPUT:
111111111 13..26
222222222 132.264
333333333 543.321
444444444 1226.663
555555555 12732.263
555555555 243.333

Guys please, no more hints, I really appreciate the fact that you are trying to help me do it on my own, but I really don't have any idea how to get that algorithm to work. Can someone please modify this loop to make the wretched program work? I'm sure I just need to fix the condition, but I've tried everything, counting the is without i--, looking at the difference of i and balance.length(), using other variables. This just doesn't want to work properly. Again, I can insert the decimal point when I have two digits left at the end while keeping the original decimal, and I can remove all decimal points, but I just can't remove the original and put the new one in the right position.

for(int i = balance.length()-1; i>=0; i--) // OPEN OUTER LOOP
         {
            int a = balance.length()-1;
            if (balance[i]=='.')
                {
                    i--;
                    outFile << balance[i];
                    if (i==2) //THIS CONDITION IS GIVING ME TROUBLE
                    outFile << '.';
                }
            else
                {
                    outFile << balance[i];
                }
 
         }                                       //CLOSING OUTER FOR
         outFile << endl;

By the way that loop's inputs and outputs are here:

INPUT:
111111111 62.31
222222222 462.31
333333333 12345
444444444 3662.21
555555555 36237.21
555555555 333.42

OUTPUT:
111111111 1326
222222222 132.64
333333333 54321
444444444 122663
555555555 1273263
555555555 243.33

Edited 5 Years Ago by Assassin7893: n/a

This loop is giving me ridiculous output, and the one a post above is only working when my number is in the format xxx.xx

*sigh* Why can't you follow simple instructions?

for(int i = balance.length()-1; i>=0; i--) // OPEN OUTER LOOP
         {
            
            if (i==2)
            {
                outFile << balance[i]; //// where is this statement in my 
                                       //// instructions if [B]i=2[/B]?  And is [B]i=2[/B] 
                                       //// the correct test?  Does it give 2 
                                       //// decimal places or 3?
                outFile << '.';
            }
            if (balance[i]!='.')
            {
                outFile << balance[i];
            }
         }                                       //CLOSING OUTER FOR

It's damn close. You just added stuff I didn't have. And you didn't bother to actually think about the condition.


Then there's:

for(int i = balance.length()-1; i>=0; i--) // OPEN OUTER LOOP
         {
            int a = balance.length()-1;
            if (balance[i]=='.')
                {
                    i--;                   /// where is this statement in my instructions?

                    ///  Is any of this code in my instructions if the character is a '.'
                    outFile << balance[i]; 
                    if (i==2) 
                    outFile << '.';
                }
            else   /// There is no ELSE in my instructions
                {
                    outFile << balance[i];
                }
 
         }                                       //CLOSING OUTER FOR
         outFile << endl;

This isn't even an attempt at my easy solution...


Why do you have to make my simple instructions so complicated?

for(int i = balance.length()-1; i>=0; i--)
    {
        If i = x then  // x is the magic number representing 2 characters left
        {
            output the '.' 
        }
        If balance[i] is not '.'
        {
            output balance[i]
        }
    }
Comments
awesome

Okay I get it, but then that loop is also affecting my other loop for whole numbers. 54321, becomes 123.45.

for(int i = balance.length()-1; i>=0; i--) // OPEN OUTER LOOP
         {
 
            if (i==1)
            {
                outFile << '.';
            }
            if (balance[i]!='.')
            {
                outFile << balance[i];
            }
         }                                       //CLOSING OUTER FOR

Is there any way to add some more to the condition, say something like
if ((i==1) && balance data type is double)

Edited 5 Years Ago by Assassin7893: n/a

It's damn close. You just added stuff I didn't have. And you didn't bother to actually think about the condition.

And hey, I did think about that condition, it's just that with the stuff inside the condition, two got me closest to what I wanted. One didn't even output the decimal anywhere.

Yes, I finally figured it out, just had to add another condition inside if(i==1). I just added that the value of the array balance at the cell three cells away from the length of the string must be '.' . Thanks a lot WaltP, I really appreciate it.

This question has already been answered. Start a new discussion instead.