简体   繁体   中英

C++ pass string by reference vs pass char array by reference

Okay so I'm new to C++ and I just wanted to ask why you shouldn't pass the char array by reference with the "&" sign but you should with strings since both arguments are pointers. Example code I have written:

void changeChar(char* buffer, int bSize) {
    strcpy_s(buffer, bSize, "test123");
}

void changeString(string* buffer) {
    *buffer = "test321";
}

char mychar[10] = "hello world";
string mystr;

changeChar(mychar, sizeof(mychar));
changeString(&mystr);

You need to know, that std::string is not a built-in type. It is a class, that implements all kind of custom behaviour, such as creating hard copy on object copying.

"some text" // this is a string literal, meaning the type is const char[num]

When you enter a string literal, it is located most likely inside section of the code named ".rodata" (read only data). You cannot legaly modify value of this characters. The text has also a "null terminator" - character of value of zero at the end. It is useful, because you need to know when the literal ends. num is always number of characters +1 , because of the null terminator.

When you write this:

const char* text = "hello world!";
// note that this is illegal:
// char* text = "hello world!"; // literal is read-only.

You just say:

let text point to the memory, where the literal is located.

Copying text actually requires from as more work. It must be done explicitly:

char* notReadOnly = new char[30]; // you can allocate some more
// program will still interpret character of value 0 as the end, even if buffer is bigger
std::strcpy(notReadOnly, "hello world");
// use string literal as src in std::strcpy

Note, that you need to manually delete it too:

delete[] notReadOnly;

std::string makes it a lot easier. It automatically copies the text, when you write sth like this:

std::string text = "some string literal";

std::string 's copy constructor also makes hard copy of the buffer. Even if std::string class looked like this:

class string
{
    char *buffer;
    std::size_t numberOfCharacters;
};

Every time its copied, it performs hard copy of the buffer , which can look like this:

class string
{
    // rest
    string(const string &other)
    {
        numberOfCharacters = other.numberOfCharacters;
        buffer = new char[numberOfCharacters];
        // copy everything
        std::strncpy(buffer, other.buffer, numberOfCharacters);
    }
};

Note, that this is just a simplified example.

std::string a = "some text";
std::string b = a; // copy constructor is called. It uses method implemented above

const char* x = "some text2";
const char* y = x; // copy constructor is called. Only the address is copied, there is no hard copy of the actual buffer.

Copy constructors are also called, when you pass variable to a function as parameter. Compilers can optimize it however in some common cases.

changeChar() takes a char* pointer to a char located somewhere in memory (the function assumes the char* is actually pointing to a char[] array of the specified size).

A fixed-length array decays into a pointer to its 1st element when referred to by just its name. So there is no need to (nor can you) use operator& to pass your mychar[] array to your changeChar() function when it takes a char* pointer.

If you don't want to pass mychar by pointer, you have to pass it by reference instead (otherwise, passing it by value will make a copy of the array, and then the function won't be able to modify the original array). In which case, the compiler can deduce the array size for you:

template<size_t size>
void changeChar(char (&buffer)[size]) {
    strcpy_s(buffer, size, "test123");
}

char mychar[] = "hello world";
changeChar(mychar);

changeString() takes a string* pointer to a string object located somewhere in memory.

You can't pass an object by pointer without using operator& (or std::addressof() when a class overrides operator& ) to get the address of the object (unless it was allocated with new , which is not the case in your example).

If you don't want to pass the string object by pointer, you have to pass it by reference instead (otherwise, passing the object by value will make a copy of the object, and the function won't be able to modify the original object):

void changeString(string &buffer) {
    buffer = "test321";
}

string mystr;
changeString(mystr);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM