Spaces in string

Started by
13 comments, last by Oluseyi 19 years, 3 months ago
Try
getline(cin, item);

OT: don't suggest to read into char array and then convert from char to string, please. a:you already have function that reads line into string and does it well, b:it is inelegant to read into char and then copy&convert, c: and inefficient, d: length of buffer is limited, e: you can get buffer overflow errors, i think.
Advertisement
@Dmytry: You aren't going to get buffer overflow errors as long as you pass a correct size parameter - not due to the getline call itself, anyway. But your points are otherwise well taken, enough so that I am going to go into more detail on the whole topic ;)

cin.getline() - the getline member function of the istream object named cin - expects a character array as a buffer to hold its input. That's why it bothers asking for a length - you supply the length of the buffer, because it's Bad News (TM) if the data you're trying to read is longer than that and there isn't a safeguard. With this form, the code will stop reading if the buffer is full, even if the line isn't done yet. If you don't know how long lines can be (just that they could potentially be very long), then you are left with distasteful options:

1) just using a really big buffer and praying it's enough, while wasting that space most of the time.
2) Reading in a buffer-full at a time, doing some checking to see if the line is done, and appending the buffer to somewhere else - meanwhile, that somewhere else is either another 'really big buffer' (in which case you haven't really solved anything), or you have to keep reallocating it (i.e. do a bunch of tricky low-level memory allocation work).

Since using raw character arrays and pointers to represent text is already a very messy business (even without worrying about Unicode), we would like to be able to get a line into a std::string. This is also done using getline - this is a free function named getline, though. It takes the stream to read from as a parameter, as well as the string to read into. The stream has to be specified because it's no longer implicit (since this isn't a member function). The size is no longer needed, because std::string will resize itself as needed (just one of its many advantages over working with plain char *'s).

Thus:
#include <iostream>#include <string>using namespace std;int main() {    string inventory[9];    string item;    cout<<"What would you like to add to the inventory?"<<endl;    getline(cin,item); // Ahhh... much better.    inventory[0] = item;    cout<<inventory[0]<<endl;    // BTW, you don't need a temporary string 'item'; you can getline directly    // to inventory. It won't likely make any difference in the compiled code,    // so it boils down to what you find more readable. I usually find more    // compact things to be more readable - when they aren't, I start to wonder    // about the quality of my variable names ;)    return 0;}


Of course, this raises a few questions...

Q. Why do we need to have a free function like this? Can't the member function getline() be overloaded to take a std::string?

A. Apparently there were some kind of technical difficulties with this? I would appreciate if someone could fill in technical details, although it'd almost certainly be way over the OP's head and quite possibly over mine too ;)

Q. Given that only one of the two could be implemented as a member function, why not do it the other way around?

A. Your guess is as good as mine... There may have been motivation to emphasize the first version in the early days of C++, since people were used to everything being as close to the metal as feasible and distrusted the new-fangled std::string. Actually, I suppose iostream.h-for-C++ - and even the first version of 'iostream' - predate std::string. Or perhaps the answer to question 1 renders this all moot...
offtopic:
in C++ you can not add methods to existing class without changing this class. I had been stuck with this problem several times. When i have some class hierarchy i shouldn't change, but want to add some method to common parent, the only possibility is to change that parent, but in some cases you can't change existing code.(e.g. if it is standard) so you have to do things in non-OOP way. It especially sucks if you need to add virtual member. In this case, you need to code inheritance manually. I had to do it at least 2 times for converting from one tree-like structure to other tree-like structure.

buffer overflow: even if it doesn't overwrite anything in ram, if it behaves in unexpected way for long strings, there's still a problem. For example, it is implementation of some stream/protocol/something. If , for example, SQL queries will be passed through it, it may become possible to make exploit using this string trimming. to do evil job

Let you pass string like
`store "user-provided data here", a+b+c+d'
If user-provided data is long, a+b+c+d might be truncated out of string.
Or you pass 2 strings that is concatenated, truncation can be used to trim out quotes and make code injection be possible.

Or you might get no terminating zero if line is longer than buffer length.
Okay, I got it, and then had a problem with which space the "item" goes into, so I'm converting it to vector. I have it all good, but how do I output a vector?
Meta AdamOne of a million noob C++ programmers.
Quote:Original post by Meta Adam
...how do I output a vector?
You don't output a vector, you output the elements of a vector. You can either select the element to output manually (via indexing, or a loop), or you can use std::copy and a std::ostream_iterator.
using namespace std;vector<string> inventory;...// fill inventory...ostream_iterator<string> out(cout, "\n");copy(inventory.begin(), inventory.end(), out);

This topic is closed to new replies.

Advertisement