1
class Student {
     public:
        string name;
};

vs

class Student {
     public:
        char* name;
};

Please correct me if I'm wrong. If we were to use char* instead of string, we will have to write our very own copy-constructor because we need to every time we have pointer variables as data members. Right?

So, my question is: Why use char* at all?

Using string, in the constructor, we can directly do:

Student(string s) {
    name = s;
}

which is simpler compared to char*, which needs:

Student(string s) {
    name = new char[strlen(s)+1];  // extra 1 to store the '\n'
    strcpy(name,s);
}

Why not use string at all times instead of char* when being used as a data member of a class?

jww
  • 97,681
  • 90
  • 411
  • 885
abcde
  • 505
  • 1
  • 5
  • 8
  • 1
    You likely wouldn't. The only reason you would is if the type had to be a POD type, but then you can't implement your own assignment operator/copy constructor/destructor anyway – Ed S. Feb 08 '15 at 21:11
  • It is a rhetorical question. If you can't think of a good reason then just don't do it. Keep it in your back-pocket, maybe some day you don't want to copy a multi-megabyte string. – Hans Passant Feb 08 '15 at 21:13
  • ususally people use `string` because it's secure. people use char either because they don't know better or they really need the extra performance that comes with all the unsafety. – Alexander Oh Feb 08 '15 at 21:13
  • Who forces you to use `char*`? – Chiel Feb 08 '15 at 21:14
  • One thing I could think of is that char* creates the memory allocation in heap. I'm sure we can do that with string too. Yeah? How do we dynamically allocate memory in Heap using string? – abcde Feb 08 '15 at 21:15
  • 2
    Maybe you don't want to copy the data. (If it is static data, or the lifetime is encompassed by an outer object, then copying the pointer is good enough. You may also be in a situation where memory allocation is undesirable.) – Raymond Chen Feb 08 '15 at 21:15
  • I'm sorry. I'm taking a graduation course in C++ and we use char* all the time. So, I needed the clarification badly. – abcde Feb 08 '15 at 21:16
  • can I do this to create memory allocation in heap using string: "string* name = new String(s);" ? – abcde Feb 08 '15 at 21:19
  • Possible duplicate of [char\* vs std::string in c++](http://stackoverflow.com/questions/801209/c-char-vs-stdstring). – jww Feb 08 '15 at 21:23
  • Or is there a better way than "string* name = new String(s);" ? – abcde Feb 08 '15 at 21:23
  • @jww: But my question brings up new questions. – abcde Feb 08 '15 at 21:24
  • If I do "string* name = new String(s);" then I'll have to store it in a string pointer. But my variable name is just a string. So, how do I work around this? – abcde Feb 08 '15 at 21:26
  • Yes you should almost always use `std::string` (if you are interfacing with legacy software that uses `char*`, you obviously should use `char*` for the interface, but that's about it). If your course makes you use `char*` it's a less than ideal course. – n. m. could be an AI Feb 08 '15 at 21:26
  • You don't need string pointers. You say `string name = s;`. There's nothing to work around. – n. m. could be an AI Feb 08 '15 at 21:28
  • @RaymondChen Such cases are few and far between. The rule of thumb: use `std::string`. Works 99.99% of the time. Start worrying about cases where it doesn't work after you encounter one. – n. m. could be an AI Feb 08 '15 at 21:31
  • @n.m. : What you said creates the memory allocation on Stack. How do I create it on heap? (if I want to) – abcde Feb 08 '15 at 21:35
  • No, you don't want to create a memory allocation on heap. You don't want to worry about it at all. You want to forget about this stuff and concentrate on the really important parts, like getting the logic of your algorithm right. You want the language to take care of minute details for you. `std::string` does. Just say `std::string name = s;` and forget you have ever needed to worry about allocations. – n. m. could be an AI Feb 08 '15 at 21:42
  • @n.m. : Ok, fair enough. Thanks a lot, bro. Just to be clear again, `String name = s;` allocates memory on Stack, right? – abcde Feb 08 '15 at 21:46
  • It is a misleading terminology. Don't use it. The fact is that `std::string name = s` likely allocates partly on the stack and partly on the heap. Is it helpful? Not really I think. You need to think about the lifetime of the object, not where it is allocated. – n. m. could be an AI Feb 08 '15 at 21:50
  • Thanks once again. :) – abcde Feb 08 '15 at 21:56
  • The reason string needs to work with heap is that you wouldn't be able to do operations like push_back otherwise. It needs to be able to expand the amount of allocated memory. I don't think you should ignore how things work underneath. Of course, you don't need to worry about every little detail, but it's good to have at least a general idea of how things work. – Rafael Almeida Feb 08 '15 at 23:00

5 Answers5

2

I think the only reason char* is used in C++ as a string is because of C. I'm sure if it was a new language, one which didn't strive to be compatible with C, char* would not be used like that. You will notice that functions that handle char* as if it were a string all come from C.

Note that in C, there is no string, so

struct Student { char* name; };

is perfectly valid C code, whereas

struct Student { string name; };

is not. Therefore, it is not unusual, when dealing with code which previously target C, to see those char* types.

There are usually little reason for using char* as a string, unless you are either writing a new string class, interfacing C functions, or dealing with legacy code.

Rafael Almeida
  • 2,377
  • 3
  • 22
  • 32
1

You use char * instead of string, because a string is a string and a char * is a pointer to a character-aligned address.

Expanding on that, a string is an abstraction of a vector of characters with defined semantics. In C land, and in a lot of C++ programs, it represents an allocated block of memory along with a guarantee that it's terminated with the ascii NUL character 0x00. But a C++ implementation of string could instead use, say, a Pascal string with associated length, or it could represent strings in a string pool as a linked list.

A char * isn't providing that guarantee at all, and in fact might not be a string -- for example, it might be a collection of data with embedded 0x00 values. All it promises is that it's an address of something that the underlying architecture thinks is a character.

Charlie Martin
  • 110,348
  • 25
  • 193
  • 263
0

If you need a string, use std::string, not char*.

An obvious exception is interfacing to legacy code that uses char* to represent strings. Still, don't use char* outside of the interface layer.

You need to use char* when your data isn't a string, but a raw unstructured array of bytes. This is the case when you read or write binary data from files or network interfaces.

n. m. could be an AI
  • 112,515
  • 14
  • 128
  • 243
0

Sometimes, it is simpler to use char* instead of string, for example, when you are dealing with network and you need to transform a string full of bytes into a integer, float, etc.. I think that it's simpler to use a char*, instead of a string :

Using a char*

 char* buffer[4];
 read(buffer, 4); // A random read operation
 int value = *((int*)(&buffer[0]); // Not sure if it was like that...

Using a string

 std::string buffer;
 buffer.resize(4);
 read(buffer.data(), 4); // Will not work as buffer.data() returns a const char*
 int value = *((int*)(&buffer.data()[0]));

The problem of string is that it's designed to prevent bad usage or strange manipulations. As someone said, it's also because C++ is inherited from C. So there is functions (from libc/glibc) which takes a char* and not a string.

EDIT

Even if char* is different from char**, it's pretty complex to build a bi-dimensional array using std::vector or std::string, you should either make your proper class, use char**, or library specific implementation (Boost, Maths libs, etc...)

Raito
  • 1,553
  • 11
  • 27
  • The proof that `char*` is simpler is that your code using it is seriously broken. – James Kanze Feb 08 '15 at 22:52
  • Depending on the situation, it's simpler. When you can't rely on the simplicity of `std::string` because of legacy code/C API. – Raito Feb 08 '15 at 22:53
  • When is it simpler? All you've done in your posting is show code which doesn't work; if by "simpler", you mean "doesn't work", then OK. But otherwise... – James Kanze Feb 08 '15 at 23:07
  • Take a look here: https://github.com/LaurentGomila/SFML/blob/master/src/SFML/Network/Packet.cpp If we were using `std::string`, it would be a pain in the ass. `std::vector` is used, but a lot of const casting is done implicitly. `char*` would have been simpler in my opinion. – Raito Feb 09 '15 at 09:20
  • Why would `std::string` be a pain in the ass? (Although in this case, `std::vector` seems more appropriate.) There are some `reinterpret_cast` in the code, but only because the code is very unportable (since the results of the `reinterpret_cast` aren't guaranteed to work). And you'd need them if you were using `char*` as well. – James Kanze Feb 09 '15 at 10:36
  • I admit that I may be wrong, but ok let's say that `std::string` is good. How can you do memory operations (memcpy, etc...) ? You need to use `char*`, right? – Raito Feb 09 '15 at 11:10
  • Why do you want to do `memcpy`? When is it correct when dealing with external data? (I can't think of a case off-hand where just copying a block of bytes would be correct, but even if it were, `std::copy` works fine with iterators into an `std::string`.) – James Kanze Feb 09 '15 at 12:43
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/70589/discussion-between-raito-and-james-kanze). – Raito Feb 09 '15 at 17:55
0

About the only place where a competent C++ programmer will use char* is in the interface of an extern "C" program, or in very low level code, like an implementation of malloc (where you need to add a number of bytes to a void*). Even when calling into a C ABI, the char* needed by the interface will generally come from a &s[0], where s is an std::string, or if the interface is not const aware (and a lot of C interfaces aren't), then the results of a const_cast.

char const* is a bit more frequent: a string literal is, after all, a char const[], and I will occasionally define something like:

struct S
{
    int value;
    char const* name;
};

But only for static data, eg:

S const table[] =
{
    { 1, "one" },
    { 2, "two" },
    //  ...
};

This can be used to avoid order of initialization issues; in the above, the initialization is static, and guaranteed to take place before any dynamic initialization.

There are few other cases: I've used char const*, for example, when marshalling between to C ABIs. But they are rare.

James Kanze
  • 150,581
  • 18
  • 184
  • 329