Newbie question on strings

Discussion in 'C++' started by Deniz Dogan, May 25, 2007.

  1. Deniz Dogan

    Deniz Dogan Guest

    Hello.

    I am rather new to C/C++ and the only programming/scripting languages
    that I know (well) is Java, Ruby, Python and similar high-level
    languages. Just so you know where I'm coming from.


    I have a really simple problem. I have this piece of code:

    // Array of "numerical" characters.
    char numbers [] = {'0','1','2','3','4','5','6','7','8','9'};

    // Checks whether a char is a numerical character (0-9).
    bool isnumber(char x) {
    for (int i = 0; i < sizeof(numbers); ++i) {
    if (x == numbers) {
    return true;
    }
    }
    return false;
    }

    int main() {
    string mystring;
    getline(cin, mystring);

    string x = "", y = "";
    for (int i = 0; i < sizeof(mystring); ++i) {
    if (isnumber(mystring))
    x << mystring;
    else
    y << mystring
    }
    return 0;
    }

    As you can see, I'd like to have one string x containing all of the
    numerical characters from the input, and all the non-numerical ones in a
    string y.

    The compilation error that I get is the following:

    addressbook.cpp: In function `int main()':
    addressbook.cpp:40: error: no match for 'operator<<' in 'x <<
    (&mystr)->std::basic_string<_CharT, _Traits, _Alloc>::eek:perator[] [with
    _CharT = char, _Traits = std::char_traits<char>, _Alloc =
    std::allocator<char>](((unsigned int)i))'
    addressbook.cpp:47: error: no match for 'operator<<' in 'y <<
    (&mystr)->std::basic_string<_CharT, _Traits, _Alloc>::eek:perator[] [with
    _CharT = char, _Traits = std::char_traits<char>, _Alloc =
    std::allocator<char>](((unsigned int)i))'


    My guess is that this means that I am disallowed to use the << operator,
    for some reason.

    Any help is highly appreciated and I apologize for not being able to
    solve this problem myself, as it probably is a very simple error.

    -- Deniz Dogan
    Deniz Dogan, May 25, 2007
    #1
    1. Advertising

  2. Deniz Dogan

    Deniz Dogan Guest

    Deniz Dogan wrote:
    > Hello.
    >
    > I am rather new to C/C++ and the only programming/scripting languages
    > that I know (well) is Java, Ruby, Python and similar high-level
    > languages. Just so you know where I'm coming from.
    >
    >
    > I have a really simple problem. I have this piece of code:
    >
    > // Array of "numerical" characters.
    > char numbers [] = {'0','1','2','3','4','5','6','7','8','9'};
    >
    > // Checks whether a char is a numerical character (0-9).
    > bool isnumber(char x) {
    > for (int i = 0; i < sizeof(numbers); ++i) {
    > if (x == numbers) {
    > return true;
    > }
    > }
    > return false;
    > }
    >
    > int main() {
    > string mystring;
    > getline(cin, mystring);
    >
    > string x = "", y = "";
    > for (int i = 0; i < sizeof(mystring); ++i) {
    > if (isnumber(mystring))
    > x << mystring;
    > else
    > y << mystring
    > }
    > return 0;
    > }
    >
    > As you can see, I'd like to have one string x containing all of the
    > numerical characters from the input, and all the non-numerical ones in a
    > string y.
    >
    > The compilation error that I get is the following:
    >
    > addressbook.cpp: In function `int main()':
    > addressbook.cpp:40: error: no match for 'operator<<' in 'x <<
    > (&mystr)->std::basic_string<_CharT, _Traits, _Alloc>::eek:perator[] [with
    > _CharT = char, _Traits = std::char_traits<char>, _Alloc =
    > std::allocator<char>](((unsigned int)i))'
    > addressbook.cpp:47: error: no match for 'operator<<' in 'y <<
    > (&mystr)->std::basic_string<_CharT, _Traits, _Alloc>::eek:perator[] [with
    > _CharT = char, _Traits = std::char_traits<char>, _Alloc =
    > std::allocator<char>](((unsigned int)i))'
    >
    >
    > My guess is that this means that I am disallowed to use the << operator,
    > for some reason.
    >
    > Any help is highly appreciated and I apologize for not being able to
    > solve this problem myself, as it probably is a very simple error.
    >
    > -- Deniz Dogan


    I just realized that sizeof might not be the thing I'm looking for here.
    Not sure though.
    Deniz Dogan, May 25, 2007
    #2
    1. Advertising

  3. On 25 Maj, 14:42, Deniz Dogan <> wrote:
    > Hello.
    >
    > I am rather new to C/C++ and the only programming/scripting languages
    > that I know (well) is Java, Ruby, Python and similar high-level
    > languages. Just so you know where I'm coming from.
    >
    > I have a really simple problem. I have this piece of code:
    >
    > // Array of "numerical" characters.
    > char numbers [] = {'0','1','2','3','4','5','6','7','8','9'};
    >
    > // Checks whether a char is a numerical character (0-9).
    > bool isnumber(char x) {
    > for (int i = 0; i < sizeof(numbers); ++i) {
    > if (x == numbers) {
    > return true;
    > }
    > }
    > return false;
    > }


    You should use the isdigit() function found in <ctype> instead.


    > int main() {
    > string mystring;
    > getline(cin, mystring);
    >
    > string x = "", y = "";


    You don't have to initialize them just 'string x, y;' will do.

    > for (int i = 0; i < sizeof(mystring); ++i) {
    > if (isnumber(mystring))
    > x << mystring;


    To add a character to a string use the += operator.

    > else
    > y << mystring
    > }
    > return 0;
    >
    > }


    --
    Erik Wikström
    =?iso-8859-1?q?Erik_Wikstr=F6m?=, May 25, 2007
    #3
  4. Deniz Dogan

    Deniz Dogan Guest

    Erik Wikström wrote:
    > On 25 Maj, 14:42, Deniz Dogan <> wrote:
    >> Hello.
    >>
    >> I am rather new to C/C++ and the only programming/scripting languages
    >> that I know (well) is Java, Ruby, Python and similar high-level
    >> languages. Just so you know where I'm coming from.
    >>
    >> I have a really simple problem. I have this piece of code:
    >>
    >> // Array of "numerical" characters.
    >> char numbers [] = {'0','1','2','3','4','5','6','7','8','9'};
    >>
    >> // Checks whether a char is a numerical character (0-9).
    >> bool isnumber(char x) {
    >> for (int i = 0; i < sizeof(numbers); ++i) {
    >> if (x == numbers) {
    >> return true;
    >> }
    >> }
    >> return false;
    >> }

    >
    > You should use the isdigit() function found in <ctype> instead.
    >
    >
    >> int main() {
    >> string mystring;
    >> getline(cin, mystring);
    >>
    >> string x = "", y = "";

    >
    > You don't have to initialize them just 'string x, y;' will do.
    >
    >> for (int i = 0; i < sizeof(mystring); ++i) {
    >> if (isnumber(mystring))
    >> x << mystring;

    >
    > To add a character to a string use the += operator.
    >
    >> else
    >> y << mystring
    >> }
    >> return 0;
    >>
    >> }

    >
    > --
    > Erik Wikström
    >


    Thanks a lot, Erik!

    --
    Deniz Dogan
    Deniz Dogan, May 25, 2007
    #4
  5. Deniz Dogan

    Gavin Deane Guest

    On 25 May, 13:44, Deniz Dogan <> wrote:
    > Deniz Dogan wrote:
    > > Hello.

    >
    > > I am rather new to C/C++ and the only programming/scripting languages
    > > that I know (well) is Java, Ruby, Python and similar high-level
    > > languages. Just so you know where I'm coming from.

    >
    > > I have a really simple problem. I have this piece of code:

    >
    > > // Array of "numerical" characters.
    > > char numbers [] = {'0','1','2','3','4','5','6','7','8','9'};

    >
    > > // Checks whether a char is a numerical character (0-9).
    > > bool isnumber(char x) {
    > > for (int i = 0; i < sizeof(numbers); ++i) {
    > > if (x == numbers) {
    > > return true;
    > > }
    > > }
    > > return false;
    > > }

    >
    > > int main() {
    > > string mystring;
    > > getline(cin, mystring);

    >
    > > string x = "", y = "";
    > > for (int i = 0; i < sizeof(mystring); ++i) {
    > > if (isnumber(mystring))
    > > x << mystring;
    > > else
    > > y << mystring
    > > }
    > > return 0;
    > > }

    >
    > > As you can see, I'd like to have one string x containing all of the
    > > numerical characters from the input, and all the non-numerical ones in a
    > > string y.

    >
    > > The compilation error that I get is the following:

    >
    > > addressbook.cpp: In function `int main()':
    > > addressbook.cpp:40: error: no match for 'operator<<' in 'x <<
    > > (&mystr)->std::basic_string<_CharT, _Traits, _Alloc>::eek:perator[] [with
    > > _CharT = char, _Traits = std::char_traits<char>, _Alloc =
    > > std::allocator<char>](((unsigned int)i))'
    > > addressbook.cpp:47: error: no match for 'operator<<' in 'y <<
    > > (&mystr)->std::basic_string<_CharT, _Traits, _Alloc>::eek:perator[] [with
    > > _CharT = char, _Traits = std::char_traits<char>, _Alloc =
    > > std::allocator<char>](((unsigned int)i))'

    >
    > > My guess is that this means that I am disallowed to use the << operator,
    > > for some reason.


    Correct. << in this context is the stream insertion operator. a string
    is not a stream so attempting to use the stream insertion operator
    makes no sense. Use += to append a char to a string.

    >
    > > Any help is highly appreciated and I apologize for not being able to
    > > solve this problem myself, as it probably is a very simple error.

    >
    > > -- Deniz Dogan

    >
    > I just realized that sizeof might not be the thing I'm looking for here.
    > Not sure though.


    Also correct. sizeof evaluates the size of the object. The size of a
    string object is not the same thing as the length of the data the
    object is managing. Fortunately, the string class provides you with a
    member function, length(), which returns what you need.

    Gavin Deane
    Gavin Deane, May 25, 2007
    #5
  6. Deniz Dogan

    Lionel B Guest

    On Fri, 25 May 2007 14:42:44 +0200, Deniz Dogan wrote:

    > Hello.
    >
    > I am rather new to C/C++ and the only programming/scripting languages
    > that I know (well) is Java, Ruby, Python and similar high-level
    > languages. Just so you know where I'm coming from.
    >
    >
    > I have a really simple problem. I have this piece of code:
    >
    > // Array of "numerical" characters.
    > char numbers [] = {'0','1','2','3','4','5','6','7','8','9'};
    >
    > // Checks whether a char is a numerical character (0-9). bool
    > isnumber(char x) {
    > for (int i = 0; i < sizeof(numbers); ++i) {
    > if (x == numbers) {
    > return true;
    > }
    > }
    > return false;
    > }
    >
    > int main() {
    > string mystring;
    > getline(cin, mystring);
    >
    > string x = "", y = "";
    > for (int i = 0; i < sizeof(mystring); ++i) {
    > if (isnumber(mystring))
    > x << mystring;
    > else
    > y << mystring
    > }
    > return 0;
    > }
    >
    > As you can see, I'd like to have one string x containing all of the
    > numerical characters from the input, and all the non-numerical ones in a
    > string y.


    You're probably looking for std::stringstream. Try this:

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

    using namespace std;

    int main()
    {
    string mystring;
    getline(cin, mystring);

    stringstream x, y; // does have operator <<

    for (string::size_type i = 0; i < mystring.size(); ++i) {
    if (isdigit(mystring)) // `std::isdigit' does what your `isnumber' does
    x << mystring;
    else
    y << mystring;
    }

    cout << "x = " << x.str() << endl; // stringstream::str() returns the actual string
    cout << "y = " << y.str() << endl;

    return 0;
    }

    --
    Lionel B
    Lionel B, May 25, 2007
    #6
  7. Deniz Dogan

    Daniel T. Guest

    Deniz Dogan <> wrote:

    > // Array of "numerical" characters.
    > char numbers [] = {'0','1','2','3','4','5','6','7','8','9'};
    >
    > // Checks whether a char is a numerical character (0-9).
    > bool isnumber(char x) {
    > for (int i = 0; i < sizeof(numbers); ++i) {
    > if (x == numbers) {
    > return true;
    > }
    > }
    > return false;
    > }
    >


    remove all of the above. use the line below instead:

    #include <cctype>

    > int main() {
    > string mystring;
    > getline(cin, mystring);
    >
    > string x = "", y = "";
    > for (int i = 0; i < sizeof(mystring); ++i) {


    for ( int i = 0; i < mystring.size(); ++i ) {

    > if (isnumber(mystring))

    if ( isdigit( mystring ) )

    > x << mystring;

    x += mystring;

    > else
    > y << mystring

    y += mystring;
    > }
    > return 0;
    > }
    Daniel T., May 25, 2007
    #7
  8. Deniz Dogan

    Guest

    I know, in this place there are many real gurus with huge experience
    programming using C++ and I'm interesting, how they can implement this
    functionality. My version:

    #include <iostream>
    #include <conio.h>
    #include <sstream>

    using namespace std;

    int main()
    {
    char c;
    stringstream x, y;
    do
    {
    c = (char)getchar();
    isdigit(c) ? x << c : y << c;
    }
    while(c != '\n');

    cout <<"x = " << x.str() << endl;
    cout << "y = " << y.str() << endl;

    getchar();

    return 0;
    }

    With impatience wait for yours solutions.
    , May 25, 2007
    #8
  9. Deniz Dogan

    Gavin Deane Guest

    On 25 May, 16:36, wrote:
    > I know, in this place there are many real gurus with huge experience
    > programming using C++ and I'm interesting, how they can implement this
    > functionality. My version:
    >
    > #include <iostream>
    > #include <conio.h>
    > #include <sstream>
    >
    > using namespace std;
    >
    > int main()
    > {
    > char c;
    > stringstream x, y;
    > do
    > {
    > c = (char)getchar();
    > isdigit(c) ? x << c : y << c;
    > }
    > while(c != '\n');
    >
    > cout <<"x = " << x.str() << endl;
    > cout << "y = " << y.str() << endl;
    >
    > getchar();
    >
    > return 0;
    >
    > }
    >
    > With impatience wait for yours solutions.


    The main problem with your code as a C++ solution is that conio.h and
    getchar are not part of C++. To read and process an entire line, the
    getline function, as used by the OP is perfectly adequate. One other
    minor point, you only use your string streams for output so x and y
    can be ostringstream rather than stringstream.

    #include <iostream>
    #include <sstream>
    #include <string>
    #include <cctype>

    using namespace std;

    int main()
    {
    string line;
    ostringstream x, y;
    getline(cin, line);
    for (string::size_type i = 0; i < line.length(); ++i)
    {
    char c = line;
    isdigit(c) ? x << c : y << c;
    }
    cout <<"x = " << x.str() << endl;
    cout << "y = " << y.str() << endl;
    return 0;
    }

    Gavin Deane
    Gavin Deane, May 25, 2007
    #9
  10. Deniz Dogan

    red floyd Guest

    Gavin Deane wrote:
    > On 25 May, 16:36, wrote:
    >> I know, in this place there are many real gurus with huge experience
    >> programming using C++ and I'm interesting, how they can implement this
    >> functionality. My version:
    >>
    >> #include <iostream>
    >> #include <conio.h>
    >> #include <sstream>
    >>
    >> using namespace std;
    >>
    >> int main()
    >> {
    >> char c;
    >> stringstream x, y;
    >> do
    >> {
    >> c = (char)getchar();
    >> isdigit(c) ? x << c : y << c;
    >> }
    >> while(c != '\n');
    >>
    >> cout <<"x = " << x.str() << endl;
    >> cout << "y = " << y.str() << endl;
    >>
    >> getchar();
    >>
    >> return 0;
    >>
    >> }
    >>
    >> With impatience wait for yours solutions.

    >
    > The main problem with your code as a C++ solution is that conio.h and
    > getchar are not part of C++.


    Actually, getchar() *is* part of C++ (the stdio library is incorporated
    by reference), but he doesn't include either <stdio.h> or <cstdio>.

    > To read and process an entire line, the
    > getline function, as used by the OP is perfectly adequate. One other
    > minor point, you only use your string streams for output so x and y
    > can be ostringstream rather than stringstream.
    >
    > #include <iostream>
    > #include <sstream>
    > #include <string>
    > #include <cctype>
    >
    > using namespace std;
    >
    > int main()
    > {
    > string line;
    > ostringstream x, y;
    > getline(cin, line);
    > for (string::size_type i = 0; i < line.length(); ++i)
    > {
    > char c = line;
    > isdigit(c) ? x << c : y << c;
    > }
    > cout <<"x = " << x.str() << endl;
    > cout << "y = " << y.str() << endl;
    > return 0;
    > }
    >
    > Gavin Deane
    >
    red floyd, May 25, 2007
    #10
  11. Deniz Dogan

    Daniel T. Guest

    In article <>,
    wrote:

    > I know, in this place there are many real gurus with huge experience
    > programming using C++ and I'm interesting, how they can implement this
    > functionality. My version:
    >
    > #include <iostream>
    > #include <conio.h>
    > #include <sstream>
    >
    > using namespace std;
    >
    > int main()
    > {
    > char c;
    > stringstream x, y;
    > do
    > {
    > c = (char)getchar();
    > isdigit(c) ? x << c : y << c;
    > }
    > while(c != '\n');
    >
    > cout <<"x = " << x.str() << endl;
    > cout << "y = " << y.str() << endl;
    >
    > getchar();
    >
    > return 0;
    > }
    >
    > With impatience wait for yours solutions.


    #include <algorithm>
    #include <iterator>
    #include <iostream>

    using namespace std;

    bool is_digit( char c )
    {
    return isdigit( c );
    }

    int main()
    {
    string input;
    getline( cin, input );
    const string::iterator it =
    stable_partition( input.begin(), input.end(), &is_digit );
    cout << "x = ";
    copy( input.begin(), it, ostream_iterator<char>( cout ) );
    cout << "\ny = ";
    copy( it, input.end(), ostream_iterator<char>( cout ) );
    }
    Daniel T., May 25, 2007
    #11
  12. Deniz Dogan

    James Kanze Guest

    On May 25, 5:36 pm, wrote:
    > I know, in this place there are many real gurus with huge experience
    > programming using C++ and I'm interesting, how they can implement this
    > functionality. My version:


    > #include <iostream>
    > #include <conio.h>
    > #include <sstream>


    > using namespace std;


    > int main()
    > {
    > char c;
    > stringstream x, y;


    Why stringstream? He's only writing, so at the very least, it
    should be ostringstream. And in fact, he's not formatting
    anything; he's dealing with elements that are already text. So
    just appending to a string would seem just as appropriate.

    > do
    > {
    > c = (char)getchar();


    And what happens when you reach end of file?

    The standard idiom would be something like:

    char c ;
    while ( std::cin.get( c ) && c != \=n' ) {
    // ...

    If it were C, and you only had getchar, then you'd have to
    assign the results to an int first, something like:

    for ( int c = getchar() ;
    c != EOF && c != '\n' ;
    c = getchar() ) {
    // ...

    You can use the same idiom in C++, of course:

    for ( int c = std::cin.get() ;
    c != EOF && c != '\n' ;
    c = std::cin.get() ) {
    // ...

    In this case, it has a definite advantage, see below:

    > isdigit(c) ? x << c : y << c;


    This has undefined behavior, to start with. You can't call the
    one argument isdigit function with a char. If you want to get
    fancy, and use ?: (I'm not sure it's the best solution here),
    what's wrong with:

    ( isdigit( static_cast< unsigned char >( c ) )
    ? x
    : y ) += c ;

    If c is an int, with the immediate results of std::cin.get(), or
    getchar(), then you don't need the cast.

    > }
    > while(c != '\n');


    And of course, since the tests are at the top of the loop, you
    don't need the while here.

    > cout <<"x = " << x.str() << endl;
    > cout << "y = " << y.str() << endl;


    > getchar();


    What does this do?

    > return 0;
    > }


    > With impatience wait for yours solutions.


    I'd go with std::string for the collectors, my last for loop,
    and an if.

    --
    James Kanze (Gabi Software) email:
    Conseils en informatique orientée objet/
    Beratung in objektorientierter Datenverarbeitung
    9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
    James Kanze, May 25, 2007
    #12
  13. Deniz Dogan

    James Kanze Guest

    On May 25, 11:43 pm, "Daniel T." <> wrote:
    > In article <>,


    Very good, but...

    > #include <algorithm>
    > #include <iterator>
    > #include <iostream>


    > using namespace std;


    > bool is_digit( char c )
    > {
    > return isdigit( c );


    Where is isdigit defined. There are isdigit functions defined
    in two different standard headers; you didn't include either of
    them, and the call here is legal with none of them, it's either:

    #include <locale>
    // ...
    return std::isdigit( c, std::locale() ) ;

    or
    #include <ctype.h>
    // ...
    return isdigit( static_cast< unsigned char >( c ) ) ;

    Given the way you've written it, why write it at all?

    > }


    > int main()
    > {
    > string input;
    > getline( cin, input );


    I'd check that the read succeeded, just to be sure.

    > const string::iterator it =
    > stable_partition( input.begin(), input.end(), &is_digit );


    In theory, you could use the two argument version of
    std::isdigit directly in the call here, by means of ptr_fun and
    bind2nd. But since these are all templates, as is the two
    argument function, you'd have to explicitly tell the compiler
    which instantiation to use. The resulting expression is not
    particularly succinct.

    If you do this sort of thing for a living, of course, you'll
    probably have the necessary predicates already present in your
    library, so it would be a lot simpler.

    > cout << "x = ";
    > copy( input.begin(), it, ostream_iterator<char>( cout ) );
    > cout << "\ny = ";
    > copy( it, input.end(), ostream_iterator<char>( cout ) );


    (You forgot the final newline.)

    I'd probably write this:

    cout << "x = " << std::string( input.begin(), it ) << '\n' ;
    cout << "y = " << std::string( it, input.end() ) << '\n' ;

    It's probably less efficient this way, but IMHO considerably
    more readable.

    > }


    I do like your use of a standard algorithm.

    --
    James Kanze (Gabi Software) email:
    Conseils en informatique orientée objet/
    Beratung in objektorientierter Datenverarbeitung
    9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
    James Kanze, May 26, 2007
    #13
  14. Deniz Dogan

    Gavin Deane Guest

    On 25 May, 21:35, red floyd <> wrote:
    > GavinDeanewrote:


    > > The main problem with your code as a C++ solution is that conio.h and
    > > getchar are not part of C++.

    >
    > Actually, getchar() *is* part of C++ (the stdio library is incorporated
    > by reference), but he doesn't include either <stdio.h> or <cstdio>.


    My mistake. Thanks. James Kanze's post elsethread seems to cover the
    problems in the original use of getchar().

    Gavin Deane
    Gavin Deane, May 26, 2007
    #14
  15. Deniz Dogan

    Daniel T. Guest

    James Kanze <> wrote:
    > "Daniel T." <> wrote:
    >
    > Very good, but...
    >
    > > #include <algorithm>
    > > #include <iterator>
    > > #include <iostream>

    >
    > > using namespace std;

    >
    > > bool is_digit( char c )
    > > {
    > > return isdigit( c );

    >
    > Where is isdigit defined. There are isdigit functions defined
    > in two different standard headers; you didn't include either of
    > them, and the call here is legal with none of them, it's either:
    >
    > #include <locale>
    > // ...
    > return std::isdigit( c, std::locale() ) ;
    >
    > or
    > #include <ctype.h>
    > // ...
    > return isdigit( static_cast< unsigned char >( c ) ) ;
    >
    > Given the way you've written it, why write it at all?


    The missing include was an oops on my part, apparently it is included
    through one of the others on my system. As for the cast to unsigned
    char, I feel it is completely unnecessary in this case (I did consider
    it.) The only thing at issue is if 'c' is negative and how that will
    expand out to an int. If you actually tested isdigit( c ) with isdigit(
    static_cast<unsigned char>( c ) ) for all values of 'c', I expect you
    will find that the return values are the same in every case. (In looking
    around, this may not be true for EBCDIC.)

    > > }

    >
    > > int main()
    > > {
    > > string input;
    > > getline( cin, input );

    >
    > I'd check that the read succeeded, just to be sure.


    I considered it, but didn't find it necessary. If getline fails, input's
    value will be unchanged (i.e. empty.) Unless the original requirements
    stated that something special had to be done on failure, I see no reason
    for it.

    > > const string::iterator it =
    > > stable_partition( input.begin(), input.end(), &is_digit );

    >
    > In theory, you could use the two argument version of
    > std::isdigit directly in the call here, by means of ptr_fun and
    > bind2nd. But since these are all templates, as is the two
    > argument function, you'd have to explicitly tell the compiler
    > which instantiation to use. The resulting expression is not
    > particularly succinct.


    I'm interested. I've attempted to do this several times but have been
    unable to figure out the syntax. Care to elaborate?

    > > cout << "x = ";
    > > copy( input.begin(), it, ostream_iterator<char>( cout ) );
    > > cout << "\ny = ";
    > > copy( it, input.end(), ostream_iterator<char>( cout ) );

    >
    > (You forgot the final newline.)


    No, I didn't. I found it unnecessary.

    > I'd probably write this:
    >
    > cout << "x = " << std::string( input.begin(), it ) << '\n' ;
    > cout << "y = " << std::string( it, input.end() ) << '\n' ;
    >
    > It's probably less efficient this way, but IMHO considerably
    > more readable.


    That's a good question. Is it less efficient? I like your use of the
    string constructor instead of using copy.

    > > }

    >
    > I do like your use of a standard algorithm.


    Why reinvent the wheel?
    Daniel T., May 26, 2007
    #15
  16. Deniz Dogan

    James Kanze Guest

    On May 26, 5:23 pm, "Daniel T." <> wrote:
    > James Kanze <> wrote:
    > > "Daniel T." <> wrote:


    > > Very good, but...


    > > > #include <algorithm>
    > > > #include <iterator>
    > > > #include <iostream>


    > > > using namespace std;


    > > > bool is_digit( char c )
    > > > {
    > > > return isdigit( c );


    > > Where is isdigit defined. There are isdigit functions defined
    > > in two different standard headers; you didn't include either of
    > > them, and the call here is legal with none of them, it's either:


    > > #include <locale>
    > > // ...
    > > return std::isdigit( c, std::locale() ) ;


    > > or
    > > #include <ctype.h>
    > > // ...
    > > return isdigit( static_cast< unsigned char >( c ) ) ;


    > > Given the way you've written it, why write it at all?


    > The missing include was an oops on my part, apparently it is included
    > through one of the others on my system.


    Happens a lot:-(.

    > As for the cast to unsigned
    > char, I feel it is completely unnecessary in this case (I did consider
    > it.) The only thing at issue is if 'c' is negative and how that will
    > expand out to an int. If you actually tested isdigit( c ) with isdigit(
    > static_cast<unsigned char>( c ) ) for all values of 'c', I expect you
    > will find that the return values are the same in every case. (In looking
    > around, this may not be true for EBCDIC.)


    They aren't on any machine I know of (Windows with VC++, Linux
    with g++, and Solaris with Sun CC or g++). In all cases,
    isalpha(0xFF) returns true (non-zero), but if you assign the
    value to a char c, it becomes -1, which is (typically) EOF, and
    required to return false. For the other negative characters,
    it's possible to implement the function so that they do
    systematically return the correct value, but although some
    implementations do, it isn't required by the standard, and as
    far as I know, it isn't documented or guaranteed by those
    implementations. And in the past, I've definitly used
    implementations where calling isdigit with a negative value
    could return true (although none of the digits are allowed to
    have negative values when assigned to a char).

    > > > }


    > > > int main()
    > > > {
    > > > string input;
    > > > getline( cin, input );


    > > I'd check that the read succeeded, just to be sure.


    > I considered it, but didn't find it necessary. If getline fails, input's
    > value will be unchanged (i.e. empty.) Unless the original requirements
    > stated that something special had to be done on failure, I see no reason
    > for it.


    That's a curious attitude. I'd say that unless the original
    requirements said that an error should be treated as an empty
    string, I see no reason for supposing that it can be treated as
    anything but an error.

    > > > const string::iterator it =
    > > > stable_partition( input.begin(), input.end(), &is_digit );


    > > In theory, you could use the two argument version of
    > > std::isdigit directly in the call here, by means of ptr_fun and
    > > bind2nd. But since these are all templates, as is the two
    > > argument function, you'd have to explicitly tell the compiler
    > > which instantiation to use. The resulting expression is not
    > > particularly succinct.


    > I'm interested. I've attempted to do this several times but have been
    > unable to figure out the syntax. Care to elaborate?


    Studying it more closely, I'm not sure you can, at least not
    without TR1. You can't use std::ctype<>::is, because that is a
    member function which requires two arguments, and the adapters
    for pointer to member function allow at most one argument. And
    you can't use the convenience function std::isdigit, because the
    second argument is a reference, and the function adapter doesn't
    support reference parameters. (Boost::bind, which is part of
    TR1, handles all of these issues, however.)

    At one time in the past, I'd posted something similar for
    tolower in fr.comp.lang.c++:

    typedef std::ctype< char >
    Cvt ;
    std::transform(
    source.begin(), source.end(),
    std::back_inserter( dest ),
    std::bind1st(
    std::mem_fun(
    static_cast< char (Cvt::*)( char ) const >(
    &Cvt::tolower ) ),
    &std::use_facet< Cvt >( std::locale() ) ) ) ;

    It was my memories of this which provoked the comment that the
    notation wasn't particularly succinct.

    As I said, I do this sort of thing often enough to have a
    template Is< std::ctype_base::mask mask > (and IsNot) in my
    toolkit, so the predicate object would simply be
    Is<std::ctype_base::digit>(). (You can pass a locale to the
    constructor, but by default, it uses the current global locale.)

    > > > cout << "x = ";
    > > > copy( input.begin(), it, ostream_iterator<char>( cout ) );
    > > > cout << "\ny = ";
    > > > copy( it, input.end(), ostream_iterator<char>( cout ) );


    > > (You forgot the final newline.)


    > No, I didn't. I found it unnecessary.


    How can you find it unnecessary? It is practically required by
    the language. The last character written to a file in text mode
    must be a '\n'. (In practice, if the output is redirected to a
    file, some programs will be unable to read the partial last
    line.)

    > > I'd probably write this:


    > > cout << "x = " << std::string( input.begin(), it ) << '\n' ;
    > > cout << "y = " << std::string( it, input.end() ) << '\n' ;


    > > It's probably less efficient this way, but IMHO considerably
    > > more readable.


    > That's a good question. Is it less efficient?


    Probably. You have to construct the std::string objects, which
    typically requires a dynamic allocation. I doubt that it would
    be measurable compared to the actual output, however.

    > I like your use of the
    > string constructor instead of using copy.


    In this particular case, the motivation is to not have to
    interrupt the chaining of the << to output the data.

    > > > }


    --
    James Kanze (Gabi Software) email:
    Conseils en informatique orientée objet/
    Beratung in objektorientierter Datenverarbeitung
    9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
    James Kanze, May 27, 2007
    #16
  17. Deniz Dogan

    Daniel T. Guest

    On May 26, 8:12 p.m., James Kanze <> wrote:
    > On May 26, 5:23 p.m., "Daniel T." <> wrote:


    > That's a curious attitude. I'd say that unless the original
    > requirements said that an error should be treated as an empty
    > string, I see no reason for supposing that it can be treated as
    > anything but an error.


    Of the two reference programs given, one went into an infinite loop if
    getchar failed, while the other did exactly what my program does. I
    chose to go with the more reasonable reference.

    > > > > cout << "x = ";
    > > > > copy( input.begin(), it, ostream_iterator<char>( cout ) );
    > > > > cout << "\ny = ";
    > > > > copy( it, input.end(), ostream_iterator<char>( cout ) );
    > > >
    > > > (You forgot the final newline.)

    > >
    > > No, I didn't. I found it unnecessary.

    >
    > How can you find it unnecessary? It is practically required by
    > the language. The last character written to a file in text mode
    > must be a '\n'. (In practice, if the output is redirected to a
    > file, some programs will be unable to read the partial last
    > line.)


    Required by the language? Maybe that is too strong of a phrase...
    "Some programs" are written incorrectly.
    Daniel T., May 27, 2007
    #17
  18. Deniz Dogan

    James Kanze Guest

    On May 27, 4:06 pm, "Daniel T." <> wrote:
    > On May 26, 8:12 p.m., James Kanze <> wrote:


    > > > > (You forgot the final newline.)


    > > > No, I didn't. I found it unnecessary.


    > > How can you find it unnecessary? It is practically required by
    > > the language. The last character written to a file in text mode
    > > must be a '\n'. (In practice, if the output is redirected to a
    > > file, some programs will be unable to read the partial last
    > > line.)


    > Required by the language? Maybe that is too strong of a phrase...


    Well, it says in the C standard that an implementation is not
    required to process a text file correctly if it doesn't end with
    a '\n', and the C++ standard defines its behavior here by
    reference to the C standard. Not terminating a text file with a
    '\n' is an error.

    > "Some programs" are written incorrectly.


    Yes: those that don't terminate a text file with a '\n'.

    Note that even when the output is to a window running a command
    interpreter, your last line will run into the prompt if it isn't
    correctly terminated. If you're prompt begins with a new line,
    you won't be bothered, but that results in a lot of extra space
    when you use programs which do work correctly.

    --
    James Kanze (Gabi Software) email:
    Conseils en informatique orientée objet/
    Beratung in objektorientierter Datenverarbeitung
    9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
    James Kanze, May 27, 2007
    #18
  19. Deniz Dogan

    Daniel T. Guest

    James Kanze <> wrote:
    > On May 27, 4:06 pm, "Daniel T." <> wrote:
    > > On May 26, 8:12 p.m., James Kanze <> wrote:

    >
    > > > > > (You forgot the final newline.)

    >
    > > > > No, I didn't. I found it unnecessary.

    >
    > > > How can you find it unnecessary? It is practically required by
    > > > the language. The last character written to a file in text mode
    > > > must be a '\n'. (In practice, if the output is redirected to a
    > > > file, some programs will be unable to read the partial last
    > > > line.)

    >
    > > Required by the language? Maybe that is too strong of a phrase...

    >
    > Well, it says in the C standard that an implementation is not
    > required to process a text file correctly if it doesn't end with
    > a '\n', and the C++ standard defines its behavior here by
    > reference to the C standard. Not terminating a text file with a
    > '\n' is an error.


    So if my program is supposed to output something that must be processed
    by a C/C++ implementation, then I need a newline. That says nothing
    about the program I wrote.

    However, given the fact that one of the reference programs mentioned
    ended with a newline (the other didn't produce any output at all,) I
    should probably have done so as well. Thus, using the same argument I
    used to show that a blank string on bad input is correct, I show that
    not putting a newline at the end is incorrect. :)
    Daniel T., May 27, 2007
    #19
  20. Deniz Dogan

    Jerry Coffin Guest

    In article <f36lk4$n8i$>,
    says...

    [ ... ]

    > int main() {
    > string mystring;
    > getline(cin, mystring);
    >
    > string x = "", y = "";
    > for (int i = 0; i < sizeof(mystring); ++i) {
    > if (isnumber(mystring))
    > x << mystring;
    > else
    > y << mystring
    > }
    > return 0;
    > }


    Yet another approach looks like this:

    #include <algorithm>
    #include <string>
    #include <cctype>

    struct non_digit {
    bool operator()(int d) {
    return !std::isdigit(d);
    }
    };

    int main() {
    using namespace std;

    string mystring, x, y;

    getline(cin, mystring);
    remove_copy_if(mystring.begin(), mystring.end(),
    back_inserter(x), non_digit());
    remove_copy_if(mystring.begin(), mystring.end(),
    back_inserter(y), isdigit);

    return 0;
    }

    This has the disadvantage of scanning through the input string twice
    though, so it's at least theoretically slower. OTOH, given that the
    string is presumably being entered by the user, it's unlikely to be long
    enough for this to mean much.

    --
    Later,
    Jerry.

    The universe is a figment of its own imagination.
    Jerry Coffin, May 28, 2007
    #20
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Kurt Krueckeberg
    Replies:
    2
    Views:
    708
    =?ISO-8859-1?Q?Ney_Andr=E9_de_Mello_Zunino?=
    Nov 17, 2004
  2. Rick

    Comparing strings from within strings

    Rick, Oct 21, 2003, in forum: C Programming
    Replies:
    3
    Views:
    378
    Irrwahn Grausewitz
    Oct 21, 2003
  3. Klaus Neuner
    Replies:
    7
    Views:
    486
    Klaus Neuner
    Jul 26, 2004
  4. Girish Sahani
    Replies:
    17
    Views:
    571
    Boris Borcic
    Jun 9, 2006
  5. Ben

    Strings, Strings and Damned Strings

    Ben, Jun 22, 2006, in forum: C Programming
    Replies:
    14
    Views:
    755
    Malcolm
    Jun 24, 2006
Loading...

Share This Page