Fog Creek Software
Discussion Board




strings in C++

I've been spoiled by VB & C# regarding strings... I just want to concatenate an int on the end of a string.  This is what I want to do in C#:

string foo = "";
int bar = 42;
foo = "Hello " +  bar;

In C++, I've tried these:
string foo = "";
int bar = 42;
a) foo = "Hello " + bar;
b) foo = "Hello " + itoa(bar);
c) foo = "Hello " + _itoa(bar);
d) foo = "Hello ";
    foo += bar;
e) foo = "Hello ";
    foo += itoa(bar);
f) char buffer [33];
  foo = "Hello " + itoa(bar, buffer, 10);
g) char buffer [33];
    foo = "Hello " + _itoa(bar, buffer, 10);

When I try using itoa, I get a "itoa undeclared" error, even though I'm including cstdlib.  I also get an "_itoa undeclared" error when I try that.

Here are the URL's that tell me I should be able to do what I'm attempting.  What am I missing here?
http://www.cplusplus.com/ref/cstdlib/itoa.html
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vccore98/HTML/_crt__itoa.2c_._i64toa.2c_._ui64toa.2c_._itow.2c_._i64tow.2c_._ui64tow.asp

And no, adding an int to a string is not a homework problem.  I just got stuck on this one piece of minutia, and I can't seem to get past it.

nathan
Friday, June 18, 2004

Try this:

#include <string>
#include <sstream>
using namespace std;

int main(int argc, char* argv[])
{
    stringstream ss;
    ss << "hello " << 42;

    string foo = ss.str();
    
    return 0;
}

John C
Friday, June 18, 2004

A number of comments:

You can't concatenate strings that way. The strings you're using are C-style strings, which are not much more than glorified pointers. The addition operator changes the pointer instead of the value in the string. What you probably want to use are C++-style strings:
#include <string>
...
std::string hello = "Hello ";
(or use 'using namespace std;' if you don't want to type std:: every time).
std::string foo = hello + " bar";
...
or
...
std::string foo = std::string("Hello ") + " bar";

Since you use cstdlib, I believe itoa is also in the std namespace, so either use std::itoa or 'using namespace std'.

So:

std::string foo = std::string("Hello ") + itoa(bar, buffer, 10);
with buffer sufficiently large.

Of course, John C's solution is much more elegant IMO. There's also an other solution, though I haven't used it yet: Boost provides a way to use typesafe printf-style format specifications.

vrt3
Friday, June 18, 2004

Keith:

I'm using namespace std; so adding std:: to the type declaration doesn't do anything for me.  Thanks though.

John:

I came across the stringstream in my googles, and thought it was interesting.  It seems kind of overkill to resort to that for concatenation of a string & an int.  Thanks.

nathan
Friday, June 18, 2004

vrt3:

I'm not worried about concating strings.  I can do that just fine.  I need to concat an int to a string.  Does the string library include an int to string conversion function?  I didn't see one, but I might have looked in the wrong place.

I'm including string already, the only reason I'm including csdtlib is because I'm using rand in another part of my program. 

Thanks.

nathan
Friday, June 18, 2004

char szText[255];
char *psz = "Hello";
int i = 42;

sprintf( szText, "%s%d", psz, i );

MikeG
Friday, June 18, 2004

nathan, I tend to use stringstream for all my concatenation needs where strings are concerned (you can do much more than combine strings and ints of course). I prefer that to using sprintf as it's type-safe and makes me less prone to making mistakes.

John C
Friday, June 18, 2004

stringstream may seem like overkill, but it does something very similar to what goes on "under-the-hood" in a language like Visual Basic.  You really shouldn't worry too much about prematurely optimizing this -- if you find this is done a lot through profiling, then it might be worth looking for less bulky methods.

Ben Combee
Friday, June 18, 2004

itoa is *not* a standard C funtion. It may be defined by some platforms, but, for instance, it's not in the C library for Linux or OS X (just checked).

scruffie
Friday, June 18, 2004

sprintf

Anon
Friday, June 18, 2004

I've personally always preferred sprintf over C++-style operator<<. GCC can check most standard types against the format string, so it's fairly safe.

Dan Maas
Friday, June 18, 2004

Incidentally I believe that the lack of a standard string type (or lists and associative arrays) is THE reason C++ started losing ground to Java.

(yes there's std::string and std::list, but how many *APIs* actually use these? I don't think I've ever written code to an interface that used std:: types. Perhaps due to the poor performance of some C++ library implementations?)

Dan Maas
Friday, June 18, 2004

I always use sprintf, besides, it lets you specify the format you want doubles to be displayed in and such. 

tonsofpcs
Friday, June 18, 2004

Ah, you just reminded me of how goddamn annoying C++ is. Have fun.

Matt
Friday, June 18, 2004

Agreed about sprintf -- formatting numeric output in ostreams is possible but a huge pain in the ass. I much prefer formatting a line of output in char arrays and then passing the line to ostream::<<

Jeremy Osner
Friday, June 18, 2004

> yes there's std::string and std::list, but how many *APIs*
> actually use these?

What do you mean by "API" in this context? I think the Boost libraries ought to count...

Michael Eisenberg
Friday, June 18, 2004

>> but how many *APIs* actually use these?

I'm not sure they would be binary-compatible when compiled with different compilers.

As for how many *programs* use std::string internally, that's a different story. But to the outside, they have no choice but to expose char*s.

Alex
Friday, June 18, 2004

In addition to the itoa, sstream and sprintf, one can use the "lexical cast" approach:

The "lexical cast" performs a "do what I mean" cast by transferring data types using translation capabilities provided by the types. It is surely not the fastest way to concatenate strings and integers, but it is one of the cleanest:

--

#include <iostream>
#include <string>
#include "boost/lexical_cast.hpp"

int
main(int argc, char* argv[] ) {
  std::string s ;
  s = boost::lexical_cast<std::string>("hello, ")
    + boost::lexical_cast<std::string>(42) ;
  std::cout << s << std::endl ;
  return 0 ;
}

--
omerm@tiamat:~$ g++ -I boost_1_31_0 test_lexical_cast.C
omerm@tiamat:~$ ./a.out
hello, 42
omerm@tiamat:~$

Omer Mussaev
Friday, June 18, 2004

John C has the correct answer.
boost::lexical_cast also works, but it's slow and should be used sparingly.
Anything else is just badly informed.

Using char*, itoa and printf is C NOT C++, it makes me weep when I see people writing such bad code (Nathan), then claiming that the language is to blame.
Then when he is presented with the correct answer, he rejects it as if he knows what's best arrrrgggghhhhh!!!!!!!
If this is commercial work, I suggest you alert your manager to the fact that you are way out of your depth.

Craig
Friday, June 18, 2004

Well put craig! I was also going to have a go at the use C in C++ but decided against it in the end...

John C
Friday, June 18, 2004

Get used to this sort of thing as you learn more about the C++ standard library.

It is an absolutely beautiful, flexible design (from an academic standpoint) that absolutely sucks to use on a daily basis until you know it inside and out. 

Mr Fancypants
Friday, June 18, 2004

Re: Craig

I understand your comment, but am I the only one who finds the use of stream inserters and manipulators extremely cumbersome and verbose for neat formatting of data in printed output?

A simple format string such as "%8.3f %.6g %3.1f %4d" is so much more concise and readable than messing about with setwidth() and setprecision() all over the place.

Ian
Friday, June 18, 2004

That is one weakness of streams, boost::format is a nice compromise.
I've been bitten to many times by fixed buffer code going to production.
C++ and STL are not easy to lean, granted, but once mastered you have a powerful tool for problem solving.

Craig
Friday, June 18, 2004

Craig:

I didn't mean to come across as knowing what's best.  I'm just a lowly CS major trying to figure out how to concat an int onto a string.  Coming from a VB/C# background, I looked first to an overload of the + operator.  Honestly, I expected to find something there.  I never thought the language was to blame, I thought my knowledge was lacking. 

I admit, I did think that overloading a stream operator to do a string concatenation was overkill.  Yes, that was an uninformed opinion.  I didn't mean to be rude to John, or to appear to be dismissive.  I just thought there was a simpler way.  I see now I was wrong.

I feel silly for taking offense at your post, but it seems rather unfair.  Ok, the code in my original post was bad.  I admit that, that's why I'm asking what I'm missing.  Heck, most of it didn't even compile... So when I ask a question about it, you claim that I make you weep, as though my code is a personal affront to you and your family.  Geez, lighten up.

nathan
Friday, June 18, 2004

Didn't mean to be so heavy handed, I'm too jaded ;)

Craig
Saturday, June 19, 2004

Re: few APIs use C++ standard types

I don't mean libraries like Boost that go "underneath" your code, I mean APIs that you write code "to", like Win32 and MFC. MFC uses CString. libxml++ uses something called Glib::ustring. The Maya 3D package uses MString. The situation for "list" classes is the same as for strings. Why don't public C++ APIs use standard types?

I understand the theoretical advantages of the C++ standard library and STL, but I have been totally turned off to them by poor implementations. I played around with the GNU C++ library a while ago. Just using a single std::string forced me to link in all sorts of object code I didn't need (specifically ALL of iostreams) and bloated my compiled program by something like >200KB. Just for one string! The GNU STL is even worse. I then tried STLPort, which is not half bad. But then I wrote my own little out-of-line String and List classes, like 2 pages of code each, and they work fine for me. I suppose this is the path that leads C++ API vendors to re-invent their own data structures.

Dan Maas
Saturday, June 19, 2004

printf-like formatting in C++-style: http://www.boost.org/libs/format/index.html

Still somewhat ugly syntax; I haven't used it yet, but on the look of it I like it better than the << operator stuff.

At work we use Borland C++Builder, which has a string class called AnsiString. That class has a method sprintf which does the same as the C function of that name, but puts the result in the object. That means you don't have to allocate a buffer yourself, which is one of the biggest disadvantages of sprintf. Still not type safe though, I've been bitten by that a few times.

nathan: I think the only conversion from int to string is via stringstream.

That's another advantage of AnsiString: it has a constructor to convert from integers, and a ToInt method to convert back to an integer. I think std::string focuses too much on being a sequence of characters and too little on what people actually do with strings. For example, there's no easy way to compare two strings case insensitif.

vrt3
Saturday, June 19, 2004

"I then tried STLPort, which is not half bad. But then I wrote my own little out-of-line String and List classes"

What is so bad about std::list?

"bloated my compiled program by something like >200KB"

Was this for embedded work?

A lot of C++ API's don't use STL because implementations were not mature enough at the time, that does not mean it's still a good idea.
I've had to support code were other people felt the need to re-implement STL functionality themselves, in every case it was born out of a misunderstanding of what you can do with STL.
In every case I have been able to jettison 1000's of lines of un-needed code by replacing it with standard classes.

That's not to say there are not holes, case insensitive comparisons are one, but it's only a couple of lines of code.

Craig
Saturday, June 19, 2004

No, I'm a regular desktop programmer, but I still think 200KB for one std::string is overkill. In my mind a string is basically just an automatically-allocated buffer, at MOST something slightly fancy like a reference-counted shared buffer. I don't see how either of these needs 200KB of code. My attitude is that I truly care about what goes into my executables. If I see hundreds of KB of iostreams code, when I never use iostreams, then something is wrong.

I'll be the first to admit that my custom containers are less flexible and probably slower than STL. If I had to do more complex sorting or algorithmic stuff I'd probably use STL.

The compile time difference is huge as well. It was something like 10 minutes with STL vs 2 minutes with my containers. I dislike the C++ tendency for all code to be in-line in headers. I use void* containers with out-of-line code wrapped in typesafe in-line templates.

(I do have one specific problem with std::list, which is that you can't integrate the list pointers into an existing object)

Dan Maas
Sunday, June 20, 2004

How much overhead does the custom code add?, less I would assume, the overhead will come in terms of time and money when somebody else needs to support your applications.

"I do have one specific problem with std::list, which is that you can't integrate the list pointers into an existing object"
Explain please, I don't understand.

Craig
Sunday, June 20, 2004

"For example, there's no easy way to compare two strings case insensitif."

Making a case-insensitive variant of std::string is actually quite easy, see http://www.gotw.ca/gotw/029.htm

However, there are few compatibility problems with this approach when using it together with normal strings or iostreams.

jannek
Monday, June 21, 2004

What I mean by the std::list pointers is that in C, you'd typically have an object like this:
struct MyObject {
    MyObject *prev, *next;
    ....
};

Whereas in C++ you have std::list<MyObject>, but it must allocate an additional memory block to hold the prev,next pointers, so it's slower and less memory efficient.

(the counter-argument is that std::list is more flexible because you don't need to change MyObject to make it a member of another list. In my personal experience this has never been an issue)

Dan Maas
Monday, June 21, 2004

I still do not fully understand your counter argument for the non-usage of std::list, if you are wanting to share list entries between different lists, you could use boost::shared_ptr.....

The strange cross polination of C and C++ you are using is something I have seen before, I had a programmer that felt the need for this same  re-invention of well worn wheels, he was fired.

Unless you have some severe platform constraints, of which I am not aware of, in a post TRS-80 world this would seem like extreme premature optimization.

Craig
Wednesday, June 23, 2004

I only re-implement things that suck. Both STL implementations I tried sucked (too much object code bloat, compile speed too slow, indecipherable source code). The GNU C++ standard library sucks (too much object code bloat, non-functional versioning policy, mutexes used even in non-multithreaded applications, etc). At one point I was pretty sure I was going to have to re-implement parts of the C library due to glibc's non-functional versioning policy, but that fortunately did not turn out to be a problem.

I don't have anything against the C++ standard itself. But I have never seen an *implementation* of the standard library or STL that satisfied me. I'm not sure I ever will...

Dan Maas
Wednesday, June 23, 2004

That's it, I'm gonna find where the ocean drops of the end of the world!

Craig
Thursday, June 24, 2004

*  Recent Topics

*  Fog Creek Home