views:

1958

answers:

17

Is there any good reason to use C-strings in C++ nowadays? My textbook uses them in examples at some points, and I really feel like it would be easier just to use a std::string.

+8  A: 

Because that's how they come from numerous API/libraries?

PhiLho
A: 

STL strings are certainly far easier to use, and I don't see any reason to not use them.

If you need to interact with a library that only takes C-style strings as arguments, you can always call the c_str() method of the string class.

17 of 26
The only problem with c_str() is that the pointer you get back is const. You're not supposed to modify the contents via that string. In situations like that, you can also use a vector<char> and get a lot of the benefits.
dvorak
Understood, I was referring to passing the strings into the library and not getting them out.
17 of 26
+19  A: 

The only reasons I've had to use them is when interfacing with 3rd party libraries that use C style strings. There might also be esoteric situations where you would use C style strings for performance reasons, but more often than not, using methods on C++ strings is probably faster due to inlining and specialization, etc.

You can use the c_str() method in many cases when working with those sort of APIs, but you should be aware that the char * returned is const, and you should not modify the string via that pointer. In those sort of situations, you can still use a vector<char> instead, and at least get the benefit of easier memory management.

dvorak
The return value is const for a reason. Modifying it by using a const_cast or C cast is desynchronizing the internal object state. It should read 'must not modify', not 'should not'.
Thorsten79
+3  A: 

Let's say you have some string constants in your code, which is a pretty common need. It's better to define these as C strings than as C++ objects -- more lightweight, portable, etc. Now, if you're going to be passing these strings to various functions, it's nice if these functions accept a C string instead of requiring a C++ string object.

Of course, if the strings are mutable, then it's much more convenient to use C++ string objects.

adum
Note that the same functions accepting a c++ string object would accept the C string anyway because of implicit construction, so, no reason to have those functions around. As for "more lightweight" and "more portable", the price to pay is having pointers (and having to test them). To high for me...
paercebal
it's true that some functions will accept a C++ string object, but some won't. also, implicit construction has a performance cost. but yeah, there are tradeoffs...
adum
+2  A: 

If the C++ code is "deep" (close to the kernel, heavily dependent on C libraries, etc.) you may want to use C strings explicitly to avoid lots of conversions in to and out of std::string. Of, if you're interfacing with other language domains (Python, Ruby, etc.) you might do so for the same reason. Otherwise, use std::string.

Kevin Little
+2  A: 

If a function needs a constant string I still prefer to use 'const char*' (or const wchar_t*) even if the program uses std::string, CString, EString or whatever elsewhere.

There are just too many sources of strings in a large code base to be sure the caller will have the string as a std::string and 'const char*' is the lowest common denominator.

Rob Walker
+1  A: 

Given the choice, there is generally no reason to choose primitive C strings (char*) over C++ strings (std::string). However, often you don't have the luxury of choice. For instance, std::fstream's constructors take C strings, for historical reasons. Also, C libraries (you guessed it!) use C strings.

In your own C++ code it is best to use std::string and extract the object's C string as needed by using the c_str() function of std::string.

wilhelmtell
And of course, you have to use C-style strings for string literals.
dan04
@dan04 Not necessarily. given `void f(std::string s);` you can call the function with `f("C string");` because a C string can implicitly cast into a `std::string`.
wilhelmtell
+1  A: 

Textbooks feature old-school C strings because many basic functions still expect them as arguments, or return them. Additionally, it gives some insight into the underlying structure of the string in memory.

Drew Stephens
+1  A: 

It depends on the libraries you're using. For example, when working with the MFC, it's often easier to use CString when working with various parts of the Windows API. It also seems to perform better than std::string in Win32 applications.

However, std::string is part of the C++ standard, so if you want better portability, go with std::string.

David Crow
+1  A: 

For applications such as most embedded platforms where you do not have the luxury of a heap to store the strings being manipulated, and where deterministic preallocation of string buffers is required.

LarryH
Does string.reserve() not allow deterministic preallocation?
Jason Baker
+2  A: 

c strings don't carry the overhead of being a class.

c strings generally can result in faster code, as they are closer to the machine level

This is not to say, you can't write bad code with them. They can be misused, like every other construct.

There is a wealth of libary calls that demand them for historical reasons.

Learn to use c strings, and stl strings, and use each when it makes sense to do so.

EvilTeach
A: 

The usual reason to do it is that you enjoy writing buffer overflows in your string handling. Counted strings are so superior to terminated strings it's hard to see why the C designers ever used terminated strings. It was a bad decision then; it's a bad decision now.

DrPizza
I wish the spineless assholes who just downvote anything they don't like would at least grow a pair and explain to me just which bit of this post they dislike. C strings are routinely handled improperly. Counted strings are much easier to handle safely.
DrPizza
Having worked with both pascal style strings (length first) and c style strings (null terminated) I've had fewer problems with c strings. That said pascal style are more efficient for some ops.
maccullt
@DrPizza - I didn't down vote you, but when I saw your post, I knew why it was at -1... Personally, I think it was your wording over an answer. But, I also agree with your comments. It would be good to know sometimes WHY someone chose to vote down. Maybe a SO suggestion for future use?
LarryF
+3  A: 

Memory control. I recently had to handle strings (actually blobs from a database) about 200-300 MB in size, in a massively multithreaded application. It was a situation where just-one-more copy of the string might have burst the 32bit address space. I had to know exactly how many copies of the string existed. Although I'm an STL evangelist, I used char * then because it gave me the guarantee that no extra memory or even extra copy was allocated. I knew exactly how much space it would need.

Apart from that, standard STL string processing misses out on some great C functions for string processing/parsing. Thankfully, std::string has the c_str() method for const access to the internal buffer. To use printf() you still have to use char * though (what a crazy idea of the C++ team to not include (s)printf-like functionality, one of the most useful functions EVER in C. I hope boost::format will soon be included in the STL.

Thorsten79
sprintf-like functionality is there - you just need to use a string stream and standard output operators.
Branan
@Branan: yes, but it's not the same thing and it gets very awkward very fast if you need a lot of parameters...
Andreas Bonini
+12  A: 

A couple more memory control notes:

C strings are POD types, so they can be allocated in your application's read-only data segment. If you declare and define std::string constants at namespace scope, the compiler will generate additional code that runs before main() that calls the std::string constructor for each constant. If your application has many constant strings (e.g. if you have generated C++ code that uses constant strings), C strings may be preferable in this situation.

Some implementations of std::string support a feature called SSO ("short string optimization" or "small string optimization") where the std::string class contains storage for strings up to a certain length. This increases the size of std::string but often significantly reduces the frequency of free-store allocations/deallocations, improving performance. If your implementation of std::string does not support SSO, then constructing an empty std::string on the stack will still perform a free-store allocation. If that is the case, using temporary stack-allocated C strings may be helpful for performance-critical code that uses strings. Of course, you have to be careful not to shoot yourself in the foot when you do this.

bk1e
+1  A: 

Some posts mention memory concerns. That might be a good reason to shun std::string, but char* probably is not the best replacement. It's still an OO language. Your own string class is probably better than a char*. It may even be more efficient - you can apply the Small String Optimization, for instance.

In my case, I was trying to get about 1GB worth of strings out of a 2GB file, stuff them in records with about 60 fields and then sort them 7 times of different fields. My predecessors code took 25 hours with char*, my code ran in 1 hour.

MSalters
+1  A: 

1) "string constant" is a C string (const char *), converting it to const std::string& is run-time process, not necessarily simple or optimized. 2) fstream library uses c-style strings to pass file names.

My rule of thumb is to pass const std::string& if I am about to use the data as std::string anyway (say, when I store them in a vector), and const char * in other cases.

Arkadiy
+2  A: 

After spending far, far, too much time debugging initialization rules and every conceivable string implementation on several platforms we require static strings to be const char*.

After spending far, far, too much time debugging bad char* code and memory leaks I suggest that all non-static strings be some type of string object ... until profiling shows that you can and should do something better ;-)

maccullt