C++: possible Xcode (Mac) problem. Can't read

2019-03-03 05:38发布

问题:

I'm a Mac Xcode (3.2.2) user, working with the GCC 4.2 compiler, fairly inexperienced with C++ and completely ignorant about compilers.

I need to read in numbers from an external file and store them in a vector of ints. I wrote code using streams and getline(). I can compile the code and it runs without errors, but there is no output. It works for a friend (non-Mac and non-GCC 4.2 compiler) though.

I did some googling and found several posts about a possible compiler (gcc, Apple) issue in Xcode 3.2.1 that might relate to my problem (this one, for example: C++ using getline() prints: pointer being freed was not allocated in XCode. However, I have Xcode 3.2.2. I tried the suggested fixes (related to adding _GLIBCXX_FULLY_DYNAMIC_STRING to (1) the target settings window or (2) as preprocessor macros before the includes), but my problem is still not solved.

So I don't know what my problem is at this point--whether it is the same compiler issue that people had in Xcode 3.2.1 but a different fix is required in 3.2.2. Or if there is some other problem in my code.

It would be great if someone could offer some advice. No advice is too simple. If there is another way to import numbers from an external file, I would love to know about it. Also, does anyone know if there would be any reason it would be possible to import data from a .dat file, but not a .txt file on a Mac?

Thank you.

Since first posting, I have included wilhelmtell's edits.

Goal: Read numbers from a text file into a vector of ints called "results."

1) The data in the data file test.dat initially looked like,

//Test

test

'1' '2' '3'

// There are also labels and comments in the text file that I don't want to read in but can't delete from the file.

#include <algorithm>
#include <cctype>
#include <iterator>
#include <fstream>
#include <iostream>
#include <vector>
#include <string>
#include <sstream>

using namespace std;

// Edited: added struct (wilhelmtell's advice)
struct not_digit_and_not_whitespace {
    bool operator()(char c) const {
        return ! std::isdigit(c) && ! std::isspace(c);
    }
};

int main()
{
    system("pwd");

    std::string line;
    const std::string fileName = "/Users/me/test.dat";  

    ifstream theStream( fileName.c_str() ); 

    if( ! theStream )
          std::cerr << "Error opening file test.dat\n";

    std::getline( theStream, line );
    // line.erase(remove( line.begin(), line.end(), '\'' ), line.end() ); // Edited (wilhelmtell's advice)
    line.erase(remove_if( line.begin(), line.end(),not_digit_and_not_whitespace()), line.end() );  // Edited: added (wilhelmtell's advice)

    std::istringstream myStream( line );
    std::vector<int> numbers((std::istream_iterator<int>(myStream)), std::istream_iterator<int>());

    std::copy(numbers.begin(), numbers.end(),
              std::ostream_iterator<int>(std::cout, "\n"));

    /* int temp;  // Edited: wilhemtell suggested using iterators instead.
    while ( myStream >> temp ){
        numbers.push_back( temp );
     std::cout << temp << std::endl;
    }*/
    return 0;
}

回答1:

This might work for you. It uses getline as you were trying, but uses the '\'' character to serve as the line delimiter. Ignore everything up to the first '. Assume everything until the next ' is part of a number. Continue until the logic fails (presumably due to end of file).

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

int main()
{
    system("pwd");

    std::string line;
    const std::string fileName = "test.dat";  

    std::ifstream theStream( fileName.c_str() ); 

    if( ! theStream )
          std::cerr << "Error opening file test.dat\n";

    std::vector<int> numbers;

    while (true)
    {
        // get first '
        std::getline(theStream, line, '\'');
        // read until second '
        std::getline(theStream, line, '\'');
        std::istringstream myStream( line );
        int i;
        myStream >> i;
        if (myStream.fail())
            break;
        numbers.push_back(i);
    }
    std::copy(numbers.begin(), numbers.end(),
              std::ostream_iterator<int>(std::cout, "\n"));
}


回答2:

My guess is that your test.dat file is not in the working directory. To verify that you can test the stream:

if( ! theStream )
    std::cerr << "Error opening file test.dat\n";

Check your project properties in XCode to see what the working directory is, and place the file there.

If your file contains data that doesn't parse as integers then the streams' int parsing will fail. Make sure the line you read has nothing but integers and whitespace:

#include <cctype>  // algorithm iterator ...

struct not_digit_and_not_whitespace {
    bool operator()(char c) const {
        return ! std::isdigit(c) && ! std::isspace(c);
    }
};

// ...
line.erase(remove_if( line.begin(), line.end(),
                     not_digit_and_not_whitespace()),
           line.end() );

Also, you can simplify your code. First, if you include <iostream> then you don't need <istream>. Secondly, you can use the range constructor of std::vector to get the integers.

#include <algorithm>  // iterator fstream iostream vector string sstream

int main()
{
    std::string line;
    std::ifstream theStream("test.dat");
    std::getline(theStream, line);
    line.erase(std::remove(line.begin(), line.end(), '\'' ),
               line.end());
    std::istringstream myStream(line);
    std::vector<int> numbers((std::istream_iterator<int>(myStream)),
                             std::istream_iterator<int>());
    std::copy(numbers.begin(), numbers.end(),
              std::ostream_iterator<int>(std::cout, "\n"));
    return 0;
}