Reading ints from a txt in a concise way

I'm still a bit new to C++, so I apologize in advance if some of what I say doesn't make sense at all.

My current goal is to take a text file that contains both words and an array of integers and read those integers into a two-dimensional array. After completing the great C++ tutorial here and using google to search for answers to every question I've had, I've finally come up with a way to do that. I'll post the code here and explain my thought process below:

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
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
#include <cstdlib>
#include <string>
#include <fstream>
#include <iostream>
using namespace std;

int main() {

    string dat_1("DAT_1");
    string end_dat_1("END_DAT_1");
    string dat_2("DAT_2");
    string end_dat_2("END_DAT_2"); //Search strings
    
    size_t begin;
    size_t end; //Used to determine where data is located
    
    int length; //Will store length of txt
    char * buffer;
    
    string str;
    string str2; //txt in string form and substring of data, respectively
    
    int map[8][8]; //array in which to store int data
    ifstream in("data.txt");
    ofstream out("output.txt"); //files to read from and write to
    
    in.seekg(0,ios_base::end);
    length = in.tellg();
    in.seekg(0,ios_base::beg); //determine length of txt and return to beginning
    
    buffer = new char[length]; //allocate memory for c_str
    
    in.read(buffer,length);
    in.close(); //copy contents of txt to buffer and close file
    
    str = string(buffer); //convert c_str to string and place in str
    
    delete[] buffer; //no longer need buffer
    
    begin = str.find(dat_1);
    end = str.find(end_dat_1); //find markers that denote beginning and end of data

    if(begin != string::npos && end != string::npos) {
        
        str2 = str.substr(begin + 6, end-begin+6); //create a substring of only data
        buffer = new char[str2.size()+1]; //allocate memory for c_str
        strcpy(buffer, str2.c_str()); //copy contents of str2 to buffer in c_str form

        for(int y = 0; y < 8; y++) {
            for(int x = 0; x < 8; x++) {
                map[x][y] = (int) strtol(buffer, &buffer, 10);
                out << map[x][y] << " ";
            }
            out << "\n"; //loop through data, converting numbers to integers
                         //strtol is used to create pointer to next number, but
                         //result is cast as an int since a long int is not needed
        }
        delete[] buffer; //data is stored; no longer need buffer
    }
    else {
        cout<<"Could not find one of DAT_1 or END_DAT_1";
    }

}


And here is the contents of data.txt:

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
Other information up here...

DAT_1
1 2 3 4 5 6 7 8
8 7 6 5 4 3 2 1
0 9 0 9 0 9 0 9
2 4 6 8 8 6 4 2
1 6 0 2 1 7 6 4
3 1 4 1 5 9 2 5
2 7 1 8 2 8 1 8
6 0 2 2 1 4 1 7
END_DAT_1

DAT_2
0 0 0 0 0 0 0 0
1 1 1 1 1 1 1 1
2 2 2 2 2 2 2 2
3 3 3 3 3 3 3 3
4 4 4 4 4 4 4 4
5 5 5 5 5 5 5 5
6 6 6 6 6 6 6 6
7 7 7 7 7 7 7 7
END_DAT_2

...


I'm copying the contents of data.txt to a string, then using the string function to find the beginning and end of the data (DAT_1 and END_DAT_1, respectively). I then cut out a substring that contains only my data so I can use it. In order to convert the data to ints, I first convert this string to a c_str, then use strtol() to convert (I would use atoi, but I'm not sure how to get more than one number that way). Since I don't need long ints, I cast the result as an int and store it in an array.

I'm concerned that this seems awfully convoluted for something that seems so simple. It seems like there are too many conversions. I convert from txt to a stream to char *, then to string to use the find functions, then to char * again so that I can convert to int, which requires a function that normally converts to long int. Am I missing something that will make the process easier? Am I on the right track, or am I coming up with complicated workarounds for something that should be simple? Or maybe this is simple in C++ terms?

Thanks for the help. I tried to struggle through as much as I could, and now that I have code up and running (and working!), I just want to make sure I'm on the right track.
I'm concerned that this seems awfully convoluted for something that seems so simple
It is, you can directly read integers from the file:
1
2
3
4
5
// get rid of all the C string stuff

for(int y = 0; y < 8; y++)
    for(int x = 0; x < 8; x++)
       in >> map[x][y];   // you can also test if the input operation succeeded: if ( in >> map[x][y] ) OK else FAILED 

You can also avoid copying the entire file in a string. You can read each word and compare it to dat_1 etc.
1
2
3
4
5
6
7
string current_word
while ( in.good() )
{
    in >> current_word; // The words are separed by whitespaces so you will get DAT_1
    if ( current_word == dat_1 )
        //...
}
Thanks for the help and quick reply. I just implemented what you suggested, and it does indeed work. I had thought about reading integers directly from the file, but when I couldn't find a way to place the cursor at a particular place except through seekg(), I gave up on that idea and tried to use string functionality. The solution always seems much more obvious after you know it. =)
Last edited on
Topic archived. No new replies allowed.