-1

I am basically reading a .txt file and storing values.

For example:

Student- Mark
Tennis

It will store Mark into memory as the studentName.

Now...If it is just

Student-
Tennis

Then it will work fine and produce an error.

However, if the file looks like this

Student-(space)(nothing here)
Tennis

It will store Tennis into memory as the studentName, when if fact it should store nothing and produce an error. I use '\n' character to determine if there is anything after the - character. This is my code...

istream& operator>> (istream& is, Student& student)
{   
    is.get(buffer,200,'-');
    is.get(ch);
    if(is.peek() == '\n')
    {
        cout << "Nothing there" << endl;
    }
    is >> ws;
    is.getline(student.studentName, 75);
}

I think it is because the is.peek() is recognizing white space, but then if I try removing white space using is >> ws, it removes the '\n' character and still stores Tennis as the studentName.

Would really mean a lot if someone could help me solve this problem.

Sam Thers
  • 67
  • 3
  • 12
  • 3
    your is.peek() == `\n`.....if this is true, then you should return from the function. – ha9u63a7 Dec 17 '14 at 23:02
  • use find_first_of() function to find the first space so you can recognize which spaces you should remove. – Irrational Person Dec 17 '14 at 23:03
  • It should probably be `\n\r` to take into account carriage returns – ha9u63a7 Dec 17 '14 at 23:03
  • @hagubear, what about the whitespaces? What if `is.peek()==ws` and everything after is blank? That's the trouble I am having – Sam Thers Dec 17 '14 at 23:07
  • 2
    Since you only want to read a line, use `std::getline` to read the line in, and then parse it. – T.C. Dec 17 '14 at 23:12
  • Is this an assignment? Are you permitted to use std::string? – Julian Dec 17 '14 at 23:15
  • @AtlasC1, I prefer using `c string arrays`. Isn't there a way of doing this using `c string arrays`? – Sam Thers Dec 17 '14 at 23:17
  • 3
    @SamThers There is, but C++ strings are safer and free you from the burden of managing your own memory. When used as intended they also prevent stack smash attacks. I would strongly discourage you from using C-style strings. There is no time like the present to make a change for the better. (I'd also note that there are fewer things more frustrating on SO than someone saying "I'd prefer to use the wrong tool for the job." It results in needlessly complicated and broken answers.) – cdhowie Dec 17 '14 at 23:31

2 Answers2

0

If you want to ignore whitespace but not '\n' you can't use std::ws as easily: it will skip over all whitespace and aside from ' ' the characters '\n' (newline), '\t' (tab), and '\r' (carriage return) are considered whitespace (I think there are actually even a few more). You could redefine what whitespace means for your stream (by replacing the stream's std::locale with a custom std::ctype<char> facet which has changed idea of what whitespace means) but that's probably a bit more advanced (as far as I can tell, there is about a handful of people who could do that right away; ask about it and I'll answer that question if I notice it, though...). An easier approach is to simply read the tail of the line using std::getline() and see what's in there.

Another alternative is create your own manipulator, let's say, skipspace, and use that prior to checking for newline:

std::istream& skipspace(std::istream& in) {
    std::istreambuf_iterator<char> it(in), end;
    std::find_if(it, end, [](char c){ return c != ' '; });
    return in;
}
// ...
if ((in >> skipspace).peek() != '\n') {
    // ....
}
Dietmar Kühl
  • 150,225
  • 13
  • 225
  • 380
0

You don't need to peek characters. I would use std::getline() and let it handle line breaks for you, then use std::istringstream for parsing:

std::istream& operator>> (std::istream& is, Student& student)
{   
    std::string line;
    if (!std::getline(is, line))
    {
        std::cout << "Can't read student name" << std::endl;
        return is;
    }

    std::istringstream iss(line);
    std::string ignore;
    std::getline(iss, ignore, '-');
    iss >> std::ws;
    iss.getline(student.studentName, 75);

    /*
    read and store className if needed ... 

    if (!std::getline(is, line))
    {
        std::cout << "Can't read class name" << std::endl;
        return is;
    }

    std::istringstream iss2(line);
    iss2.getline(student.className, ...);
    */

    return is;
}

Or, if you can change Student::studentName into a std::string instead of a char[]:

std::istream& operator>> (std::istream& is, Student& student)
{   
    std::string line;
    if (!std::getline(is, line))
    {
        std::cout << "Can't read student name" << std::endl;
        return is;
    }

    std::istringstream iss(line);
    std::string ignore;
    std::getline(iss, ignore, '-');
    iss >> std::ws >> student.studentName;

    /*
    read and store className if needed ... 

    if (!std::getline(is, student.className))
    {
        std::cout << "Can't read class name" << std::endl;
        return is;
    }
    */

    return is;
}
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • What if I want to use `c style arrays`? I prefer using `c style arrays`, its just when `is.peek()==ws` and everything after the whitespace is blank that is the problem – Sam Thers Dec 17 '14 at 23:27
  • I would not recommend using a C style array for the reading/parsing. The STL's parsing functionality prefer `std::string`. But, as you can see in my first example, the result of the parsing is stored in a final C Style array, at least. – Remy Lebeau Dec 17 '14 at 23:34