2

I am drawing shapes in an SVG file that I generate through input I give with a .dat file.

I need to take a line from the .dat file, and remove 4 individual integers from it, and save those integers into a vector. To do this, I've attempted to create a class, square, that holds 4 integers (they represent the top left and bottom right coordinates of the square). Preferably, I'd be able to do this in a constructor of the class, but I have no idea to go about doing that.

Essentially, I know I'll have a string that looks something like "1 1 50 50," and I want to turn it into 4 integers. The issue I'm having is that I need to make it 4 integers of a class object, not just 4 integers.

class SQ
{
  public:
    sq() = default;
    static int tl_x;
    static int tl_y; //top left corner
    static int br_x;
    static int br_y; //bottom right corner
};

I've tried the code below, but it obviously doesn't work because it only saves the first integer it comes across.

while (getline(file,s))
  {
    int *f = new int(stoi(s));
    vec.push_back(f);
  }

I appreciate any help :)

user11344930
  • 49
  • 2
  • 6
  • 1
    Repeat while the string is not empty? – DeiDei Apr 11 '19 at 08:36
  • 1
    Possible duplicate of [Convert String containing several numbers into integers](https://stackoverflow.com/questions/1321137/convert-string-containing-several-numbers-into-integers) – Robert Andrzejuk Apr 11 '19 at 08:38
  • 1
    Welcome to SO. I believe this question has been asked before: [How do I convert an inputted string of numbers into an int array?](https://stackoverflow.com/questions/55483621/how-do-i-convert-an-inputted-string-of-numbers-into-an-int-array/55484698#55484698) – Constantinos Glynos Apr 11 '19 at 08:39
  • 3
    In your loop, `int f; std::stringstream ss (s); while ((ss >> f)) vec.push_back(f);` (**note:** NOT `int *f`) – David C. Rankin Apr 11 '19 at 08:39
  • 1
    You can use `strtok` to to split the string to four strings and then call `stoi` on each substring – Z E Nir Apr 11 '19 at 08:40

3 Answers3

0

You don't have to read the line into a std::string as you can read the integers one by one and directly store them into a vector. Try something like the following.

#include <fstream>
#include <vector>

int main()
{
  std::ifstream ifile("./yourfile.dat");

  std::vector<int> theIntegers;

  for (int idx = 0, val = 0; idx < 4; ++idx)
  {
    ifile >> val;
    theIntegers.push_back(val);
  }
}

EDIT: You can read the file in a constructor simply by passing the std::istream by reference to the constructor. In the example below I assume that you want to read exactly four integers while discarding the possible remainder of the line.

#include <istream>
#include <string>
#include <array>

/*
 * This class holds four integers to describe a square
 * On construction, it reads four integers from a given std::istream
 * Note that it does not check the formatting of the input file and
 * that it reads the first four integers and discards the remaining
 * characters until the next newline character.
 */

class Square
{
  std::array<int, 4> d_coordinates;

  public:
    Square() = delete;

    Square(std::istream &iFile)
    {
      for (int idx = 0, val = 0, n =  size(d_coordinates); idx < n; ++idx)
      {
        iFile >> val;
        d_coordinates[idx] = val;
      }

      // Remove the newline character at the end of this line
      // If you for some reason want to store multiple squares
      // on a single line, then just remove the next two lines

      std::string tmp;
      std::getline(iFile, tmp); 
    }
};

int main()
{
  std::ifstream ifile("./yourFile.dat");

  Square x(ifile);
  Square y(ifile);
  Square z(ifile);
}
  • While this will work for 4-integers per line, it is very fragile. If you need to handle 3 integer or 5 per-line, you need to change your loop limits. This is where a stringstream provides a benefit. You simply create a stringstream from the line and then read integers from the stringstream until you run out of things to read, no matter if that is 1 integer or 1000 integers. No change in code is required. – David C. Rankin Apr 11 '19 at 09:05
  • @DavidC.Rankin That's true, however, the OP explicitly asked for four integers and did not state whether there could be more integers on the same line that should be ignored. – Michiel uit het Broek Apr 11 '19 at 09:06
  • Yep, no argument there. He asked for 4 and you gave him 4. If there are more integers and only 4 were desired, then either a counter on the read, or a counter on the use would be needed. – David C. Rankin Apr 11 '19 at 09:09
0

If you read a line of integers like "1 1 50 50" into a string and need to parse the integers from the string, then the standard C++ way to handle the conversion is by creating a stringstream from your string and using iostream to extract the integers from the stringstream.

For example:

#include <iostream>
#include <sstream>
#include <vector>
#include <string>

int main (void) {

    std::istringstream is { "1 1 50 50\n" };  /* simulated input */
    std::string s;
    std::vector<int> vect;

    while (getline (is, s)) {       /* read string */
        int f;                      /* declare int */
        std::stringstream ss (s);   /* make stringstream from s */
        while ((ss >> f))           /* read ints from ss into f */
            vect.push_back (f);     /* add f to vector */
    }

    for (auto& i : vect)            /* output integers in vector */
        std::cout << i << '\n';
}

(if you need to store all lines individually, just use std::vector<std::vector<int>> vect;)

Note the initial istringstream was simply a way to simulate input for getline.

Example Use/Output

$ ./bin/ssint
1
1
50
50

Look things over and let me know if you have further questions.

David C. Rankin
  • 81,885
  • 6
  • 58
  • 85
0

Using a stringstream, istream_iterator, back_inserter and copy algorithm we can write it like this:

while (getline(file, s))
{
    auto       str_stream       = stringstream(s);
    auto       str_iter         = istream_iterator< int >(str_stream);
    const auto end_of_str       = istream_iterator< int >();
    auto       back_insert_iter = back_inserter(vec);

    copy(str_iter, end_of_str, back_insert_iter);
}
Robert Andrzejuk
  • 5,076
  • 2
  • 22
  • 31