3

Just as the title says, I'm reading in a string of integers from stdin. The data i'm trying to read in appears in the following form in a text file:

3
4
7 8 3
7 9 2
8 9 1
0 1 28
etc...    

The first two lines are always just single numbers (no problems there!) and the following lines each have 3 numbers. This file is redirected as stdin to my program (myprogram < textfile).

I've tried so many things but have not been able to successfully to do this! It seems so simple but I keep tripped up on where (or how) i should convert to an integer. Here is my latest attempt:

int main()
{

  string str, str1, str2;
  int numCities;
  int numRoads, x, y, z;
  cin >> numCities >> numRoads;

  cout << numCities << " " << numRoads << endl;
  //getline(cin, str1);


  while( getline(cin, str))
  {
    char *cstr;
    cstr = new char[str.size()+1];
    strcpy(cstr, str.c_str());

    x = atoi(strtok(cstr, " ")); //these will be stored in an array or something
    y = atoi(strtok(NULL, " ")); //but right now i just want to at least properly
    z = atoi(strtok(NULL, " ")); //store the appropriate values in these variables!


  }


 return 0;

}

I segfault when i try to use atoi...

Thanks in advance!

Wakka Wakka Wakka
  • 271
  • 1
  • 9
  • 16

3 Answers3

2

If you trust your input enough not to care whether the numbers have line breaks in the expected places, then you can do something like this:

int main()
{
    int numCities, numRoads;
    if (cin >> numCities >> numRoads)
    {
        int x, y, z;
        while (std::cin >> x >> y >> z)
        {
            // use the values in here...
        }
        if (!std::cin.eof())
            std::cerr << "encountered unparsable x, y and/or z before end of file\n";
    }
    else
        std::cerr << "unable to parse numCities and/or numRoads\n";
}

If you think it would help to have an error and explanation when linebreaks aren't in the expected places (e.g. numCities and numRoads on one line, blank line, x y on one line while z is on the next...) then you can read specific lines and parse out the values (more tedious though):

int main()
{
    std::string line;
    int numCities, numRoads;

    if (!std::getline(line, std::cin))
        FATAL("couldn't read line on which numCities was expected");
    std::istringstream iss(line);
    char unexpected;
    if (iss >> numCities)
        FATAL("unable to parse numCities value out of line '" << line << '\'')
    if (iss.getchar())
        FATAL("unparsabel trailing garbage characters after numCities value on line '" << line << '\'')

    // etc. (you can factor the above kind of logic into a function...)
}
Tony Delroy
  • 102,968
  • 15
  • 177
  • 252
1

First, you are using cin to read your input, then you use getline. However, when you read the last number, there is a '\n' missing. Your first getline(cin, str) is reading the '\n', this is why you get the segfault. To check it, add the following lines to your code:

// just change these lines: 
getline(cin, str);
cout << str << endl;
while(getline(cin, str))
{
    cout << str << endl;

    // ...

Your output will be:

// output
3 4

7 8 3
7 9 2
8 9 1
0 1 28

Do you only want to get all the numbers as int? Than, for this input, I recommend:

while (cin >> x >> y >> z) 
{
    cout << x << " " << y << " " << z;
}

getline() solution

You can still use getline function. Then, I suggest you to change your input reading to use getline for your first two lines too. By doing this way, you will not have problems with '\n'. But, I think it gets too complicated and I don't recommend. Specially if it is a marathon problem.

// ...
getline(cin, str);
numCities = atoi( str.c_str() );

getline(cin, str);
numRoads = atoi( str.c_str() );

cout << numCities << " " << numRoads << endl;

while(getline(cin, str))
  {    
    char *cstr;
    cstr = new char[str.size()+1];
    strcpy(cstr, str.c_str());

    x = atoi(strtok(cstr, " "));
    y = atoi(strtok(NULL, " "));
    z = atoi(strtok(NULL, " "));
  }
Yamaneko
  • 3,433
  • 2
  • 38
  • 57
  • Sorry for the late reply (my computer crapped out on me last night). That while state with cin is exactly what I needed, I was definitely overcomplicating this. I guess cin returns NULL if it's not reading anything in? Thanks so much! – Wakka Wakka Wakka Jul 23 '12 at 23:54
  • Exactly! `cin` is of type `std::istream` that is returned after reading. Since it is in a boolean context, it will be converted to boolean by the function `std::istream::operator void*()`. `NULL` becomes `false` and any other pointer becomes `true`. [More information here](http://www.parashift.com/c++-faq/istream-and-while.html) – Yamaneko Jul 24 '12 at 03:16
0

You can store the data to a string , and then change the string to an integer.

The test codes are as follows:

#include <iostream>
#include <stdlib.h>
#include <fstream>
#include <string>
using namespace std;

int main(int argc, char* argv[])
{
    ifstream in("t1.txt");

    string s1,s2,s3;
    int a1,a2,a3;

    in>>s1>>s2;
    a1 = atoi(s1.c_str());
    a2 = atoi(s2.c_str());
    cout<<a1<<" "<<a2<<endl;

    while((in>>s1>>s2>>s3))
    {
        a1 = atoi(s1.c_str());
        a2 = atoi(s2.c_str());
        a3 = atoi(s3.c_str());
        cout<<a1<<" "<<a2<<" "<<a3<<endl;
    }

}
aasa
  • 207
  • 1
  • 7