Characters and Integers and File I/O

Hi.

I am writing a program which should take a number(integer, up to 5,6 digits) from a file and make calculations with it. But...

I know that ultimately, everything is stored as 0101010 and so on. But when it comes to data types, I get confused. Example: I use << to write an integer value to a .txt file. And sure, it works. But what is stored in the file? An integer value or a character value? What happens when I use cin to extract that data to a variable of type string in my program? What kind of conversions happen then? And what about to a variable of type int? What then? I have tried and it worked(both cases), but obviously they don't have the same value any more, since they are different types.

I am asking this because I am using getline() to extract the data from the .txt. But I know I can't use that to put the numbers into int like I could with cin. So my question would be: tell me how to solve the problem of extracting not-messed-up-value-by-conversions into int variable while explaining the above.

Thanks in advance.
Last edited on
I use cout to write an integer value to a .txt file. And sure, it works. But what is stored in the file?

Let's say all you take is an int, n == 255 and put it into a text file, like so:

1
2
3
4
5
6
7
8
9
10
11
#include <fstream>
using namespace std;

int main()
{
     int n = 255;

     ofstream output("myFile.txt"); //of course this would contain the full path
     output<<n;
     output.close();
}


The value of n, in the program, in binary representation would be the following:

1
2
31 30 ... 8 7 6 5 4 3 2 1 0
 0  0 ... 0 1 1 1 1 1 1 1 1


where the top numbers represent the bit position (least significant on the right). You can see from calculation that this is so because

1
2
3
4
5
6
7
8
255 = 27 (128) +
      26  (64) +
      25  (32) +
      24  (16) +
      23   (8) +
      22   (4) +
      21   (2) +
      20   (1)


while "myFile.txt" would contain the digits of n in character representation (one byte each), as per the following:

ASCII '2' (50) 0 0 1 1 0 0 1 0
ASCII '5' (53) 0 0 1 1 0 1 0 1
ASCII '5' (53) 0 0 1 1 0 1 0 1
End of File (4) 0 0 0 0 0 1 0 0


What happens when I use cin to extract that data to a variable of type string in my program?

A std::string maintains a dynamic char*. So, say you enter the characters 123456 into the console. The string would dynamically allocate an array of (at least) 7 bytes to be pointed to by the char*. When all is said and done, the char* would contain some memory location, M, where the memory starting at M would look like the following:

1
2
3
4
5
6
7
8
9
10
M           -> 0 0 1 1 0 0 0 1 ( '1', ASCII 49)
M + 1 byte  -> 0 0 1 1 0 0 1 0 ( '2', ASCII 50)
M + 2 bytes -> 0 0 1 1 0 0 1 1 ( '3', ASCII 51)
M + 3 bytes -> 0 0 1 1 0 1 0 0 ( '4', ASCII 52)
M + 4 bytes -> 0 0 1 1 0 1 0 1 ( '5', ASCII 53)
M + 5 bytes -> 0 0 1 1 0 1 1 0 ( '6', ASCII 54)
M + 6 bytes -> 0 0 0 0 0 0 0 0 ('\0',  ASCII 0)
M + 7 bytes -> ?
M + 8 bytes -> ?
...

The std::string would also contain some other internals.


And what about to a variable of type int?

This is when some magic happens. Say you enter 123 into the console and do cin>> into an int variable. What happens, is it figures out that the character '1' is in the hunderds position and thus it adds 1 x 100 to your int (initially zero). It then figures out that the character '2' is in the tens position and it adds 2 x 10 to your int. Finally, it determines that the character '3' is in the ones position and it adds 3 x 1 to your int. It does nothing with the null terminator character.


I am using getline() to extract the data from the .txt. But I know I can't use that to put the numbers into int like I could with cin

What you could do in this case is use getline and put the line from the file in a string. You could then use a stringstream to convert the string into an int.
http://www.cplusplus.com/reference/iostream/stringstream/

You could also use a binary file instead of a text file. That way, when you write an int to the file (4 bytes) you would then be able to read those 4 bytes back and put it directly into an int. No conversion necessary.
Great answer. Sorry for the mistake up there("I use cout to write an integer value to a .txt file."). That is of course wrong, but yet you understood what I meant.


Thanks again. Will practice binary I/O!

edit:
One more question: so, basically, the process of converting characters to integers can be done manually by me, theoretically?
Last edited on
Yes.

It's all a matter of determining the positions (ones, tens, hundreds, etc.) of the numbers. Say you have a character string of all numbers. If the length is 5 (excluding the terminator character), you know the first character is in the ten thousands position, the next is in the thousands position, etc. You would also need to do error checking (in case something besides digits is entered) and handle negative values.

It's of course preferable to do this using the built-ins (_atoi and stringstreams), but yes, theoretically it's possible, and it would be fun to write as well.
Aaaaaaand... thanks x1.000.000

What is wrong with this code?
Suppose
1. tempString contains the following:"/454/665/4/"
2. i is always the position of the first integer after "/"
3. tempBuf points to the stringbuf of tempStream
4. tempVar is int

1
2
3
4
5
tempBuf->str(tempString.substr(i,tempString.find('/',i)-i));
cout<<tempBuf->str();
tempStream.flush();
tempStream>>tempVar;
cout<<tempVar;


I put this in a loop(if necessary, I'll put the rest of the code here also), and every time it should have different result(the next string of numbers should be assigned to tempVar), but it doesn't. I expect this:

454 454 665 665 4 4
(without the space, I put it for clearness)

but I get this instead:
454 454 665 454 4 454


So what is wrong with the code? Or maybe I am expecting something wrong...

Thanks in advance, and sorry for bothering you again.
Why not put only the substring into a stringstream?

1
2
3
4
5
string currentSubstring = tempString.substr(i,tempString.find('/',i)-i);
tempStream<<currentSubstring;
tempStream>>tempVar;
tempStream.str(""); //clear the stringstream
cout<<tempVar;

I'd have to see the rest of the code to see why you're getting these results. It could be an artifact of using a pointer to the stringbuf.

sorry for bothering you again

It's not a bother at all :)
Last edited on
This is the complete code. I am sure it is not nearly the best code for the job, but I am satisfied by it for now.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
/*calculate total costs and income*/
    stringstream tempStream;
    stringbuf* tempBuf;
    tempBuf=tempStream.rdbuf();
    int cost=0,income=0,tempVar;
    for(unsigned int i=tempString.find('/');i<tempString.size();i++)
    {
        while(tempString[i]!=':'){i++;}
        i++;
        switch(tempString[i])
        {
            case 'c':i++;
                     switch(tempString[i])
                     {
                         case 'd':i=i+2;tempBuf->str(tempString.substr(i,tempString.find('/',i)-i));
                                  tempStream>>tempVar;
                                  cout<<tempVar;
                                  cost=cost+365*tempVar;break;
                         case 'm':i=i+2;tempBuf->str(tempString.substr(i,tempString.find('/',i)-i));
                                  tempStream>>tempVar;
                                  cout<<tempVar;
                                  cost=cost+12*tempVar;break;
                         case 'a':i=i+2;tempBuf->str(tempString.substr(i,tempString.find('/',i)-i));
                                  tempStream>>tempVar;
                                  cout<<tempVar;
                                  cost=cost+tempVar;break;
                         default:break;
                     }break;
            case 'i':i++;
                     switch(tempString[i])
                     {
                         case 'd':i=i+2;tempBuf->str(tempString.substr(i,tempString.find('/',i)-i));
                                  tempStream>>tempVar;
                                  cout<<tempVar;
                                  income=income+365*tempVar;break;
                         case 'm':i=i+2;tempBuf->str(tempString.substr(i,tempString.find('/',i)-i));
                                  tempStream>>tempVar;
                                  cout<<tempVar;
                                  income=income+12*tempVar;break;
                         case 'a':i=i+2;tempBuf->str(tempString.substr(i,tempString.find('/',i)-i));
                                  tempStream>>tempVar;
                                  cout<<tempVar;
                                  income=income+tempVar;break;
                         default:break;
                     }break;
            default:break;
        }
        while(tempString[i]!='/'){i++;}
    }
Last edited on
Topic archived. No new replies allowed.