Reputation: 427
I'm teaching myself C++ and I'm a bit confused about pointers (specifically in the following source code). But first, I proceed with showing you what I know (and then contrasting the code against this because I feel as if there are some contradictions going on).
What I know:
int Age = 30;
int* pointer = &Age;
cout << "The location of variable Age is: " << pointer << endl;
cout << "The value stored in this location is: " << *pointer << endl;
Pointers hold memory addresses. Using the indirection (dereference) operator (the *), you can access what is stored in memory location of the pointer. Onto the code in this book I'm having trouble understanding...
cout << "Enter your name: ";
string name;
getline(cin, name); //gets full line up to NULL terminating character
int CharsToAllocate = name.length() + 1; //calculates length of string input
//adds one onto it to adjust for NULL character
char* CopyOfName = new char[CharsToAllocate];
// pointer to char's called CopyOfName, is given the memory address of the
//beginning of a block
//of memory enough to fit CharsToAllocate. Why we added 1? Because char's need a
//NULL terminating character (\0)
strcpy(CopyOfName, name.c_str()); //copies the string name, into a pointer?
cout << "Dynamically allocated buffer contains: " << CopyOfName << endl;
delete[] CopyOfName; //always delete a pointer assigned by new to prevent memory leaks
Output:
Enter your name: Adam
Dynamically allocated buffer contains: Adam
The comments in the above code are my comments. My problem begins with strcpy
. Why is name.c_str()
copied into a pointer CopyOfName
? Does this mean that all strings are essential pointers? So like
string testing = "Hello world";
Is actually a pointer pointing to the memory location where "H" is stored?
Next, why is it in the print out statement using CopyOfName
and not *CopyOfName
? Pointers hold memory addresses? Using *CopyOfName
would print out the contents of the memory location. I tried this in Code::Blocks and if the input text was "Hello World." Using *CopyOfName
in the print out statement would just give an "H". This makes sense since when I declared that I needed a memory block with the 'new' thing, this actually returns a pointer to the first part of the dynamically allocated memory block.
The only way I can reconcile this is if a string is actually a pointer.
string testing = "Confused";
cout << testing << endl;
would print out the word "Confused"
However, if I try to compile
string testing = "Confused";
cout << *testing;
I get an error message.
Basically, to summarize my question, I'm trying to understand the code with strcpy
and the cout
statement.
Upvotes: 16
Views: 77445
Reputation: 1109
Why is name.c_str() copied into a pointer CopyOfName?
"name" is an STL string. This is an object, which is different than a c-string. A c-string is a collection of memory, that holds characters, and has a null termination. So, if you're using STL strings and want to turn them into c-strings, you use .c_str() on it to get the c-string.
CopyOfName contains enough memory to hold name, since it was allocated to hold it.
cout has a TON of different things you can use with <<. It looks like it can take char *'s (which are c-strings) or STL strings. It does not look like it can take pointers to STL strings.
I got kind of confused when you introduced "testing" but I think that you are getting confused between c-strings (which are char *'s) and STL strings, which are objects. Don't feel bad, or give up. This stuff is tricky and takes a while to get.
I would reccomend to try and understand the different between the terms "c-string", "char *", "stl string" and maybe "pointer to stl string" too.
Upvotes: 2
Reputation: 714
You are asking the right questions as a learner.
Answers:
string
is an object, the c_str()
essentially returns a pointer to the first
character of the string (C Style)string
object
cout
prints the string. Also, C++ is smart enough to determine *testing
is illegalUpvotes: 2
Reputation:
Pointers are not the same as arrays. String literals are immutable, and when you have a pointer to a string literal, you can inspect its contents, but modifying them are undefined behavior. When using this syntax:
char arr[] = "hi there";
The string literal is copied into the array. Because you do not specify a size, the compiler automatically deduces it. The NUL
terminator is automatically added as well. If you specify a size, you must make sure that the buffer can hold the NUL
terminator. Therefore:
char arr[5] = "hello";
is a mistake. If you use the brace initializer syntax:
char arr[5] = { "h", "e", "l", "l", "o" };
This is a mistake because there is no NUL
terminator. If you use strcpy
, a NUL
terminator will be added for you.
std::string
provides two methods of returning a pointer to its underlying contents: data
and c_str
. Pre-C++11, the only difference is data
does not include the NUL
terminator. In C++11, it now does, so their behavior is identical. Because the pointer can easily be invalidated, is not safe to manipulate those pointers. It is also not safe to do char * ptr = str.c_str();
because the lifetime of the array returned by c_str
dies at the semi-colon. You need to copy it into a buffer.
Upvotes: 5
Reputation: 4206
It seems like you understand what C-style strings are, but to summarize, they are just arrays of characters in memory, by convention terminated by a nul character \0
. Usually they are referenced via a char*
pointing to the first letter in the string. When they are printed, typically the characters of the string are printed starting from the first, and printing (or copying, etc.) stops when the \0
terminator is reached.
An std::string
is a class that (typically) wraps a C-style string. This means that a std::string
object (typically) has a private C-style string that is used to implement its functionality. The function std::string::c_str()
returns a pointer to this underlying C-style string.
Let's suppose that char *str;
points to a C-style string. If you attempt to run cout << *str << endl;
, you noticed that only the first character is printed. That is because of C++'s function overloading. The data type of *str
is char
, so the char
version of cout
is called and faithfully prints the single character *str
. For compatibility with C-style strings, the version of cout
that takes a char*
as an argument treats the pointer as a C-style string for printing purposes. If you cout
an int*
, for example, the underlying int
will not be printed.
Edit: Another comment:
The reason that your attempt to dereference an std::string
object failed is that, indeed, it is not a pointer. You could dereference the return value of std::string::c_str()
, and you would get back the first char
of the string.
Related: How is std::string implemented?.
Upvotes: 19
Reputation: 99
So like
string testing = "Hello world";
Is actually a pointer pointing to the memory location where "H" is stored?
No, above you are have object called string
. It would be true for char* testing = "Hello World"
. As you can see it is even declared as pointer and it points to first character in string - H.
Next, why is it in the print out statement that
CopyOfName
is not*CopyOfName
? Pointers hold memory addresses? Using*CopyOfName
would print out the contents of the memory location. I tried this in code blocks and if the input text was "Hello World." Using*CopyOfName
in the print out statement would just give an "H"
cout take pointer to first character of the string so CopyOfName
is right. In this case it will print every character starting from H until it finds \0 (null character). Strings like "hello" have actually 6 characters - 'h' 'e' 'l' 'l' 'o' '\0'
When you write *CopyOfName
you are dereferencing this pointer and *CopyOfName
is actually only one character
Upvotes: 3
Reputation: 4490
Taking your questions in order:
"Why is name.c_str() copied into a pointer CopyOfName? Does this mean that all strings are essential pointers? So like string testing = "Hello world"; Is actually a pointer pointing to the memory location where "H" is stored?"
As Yu Hao pointed out in his/her comment, it is important to understand the difference between C++-style strings and C-style strings. In the first case, you are dealing with an "opaque" object, whereas in the latter case you are basically dealing with an "array" of characters.
With C++ string objects, you can use the c_str()
method to get a (pointer to a) C-style array of characters. In C, an array is represented using the pointer to the beginning of the array and then references are achieved by supplying an offset (the index into the array) from that starting address. So the answer to the last question in this bundle is "yes", the pointer to the C-style string is the pointer to the first character, 'H'.
"Next, why is it in the print out statement that CopyOfName is not *CopyOfName? Pointers hold memory addresses?"
Because the operator <<
is overloaded to handle C-strings. The implementation of this method "knows what to do with" the pointer.
Upvotes: 3
Reputation: 476
I think what you are doing, and others please correct me if I'm wrong, is that you're copying your string into a dynamic char array. So no you are not copying it into a pointer. The reason a pointer is involved there is because dynamic arrays require pointers to allocate their memory correctly if I am right.
Upvotes: 1
Reputation: 3214
In C, where C++ standard strings didn't exist, char* was the so-called "string." As you noted, it is an array of characters ending in a NULL character. Just about any standard library function which takes a C-style string will take a pointer to said string, for two reasons:
Upvotes: 1
Reputation: 780818
In C, strings are simply arrays of characters. And arrays decay to pointers when used as the argument to a function.
In C++, std::string
is a class. It includes a C-style character array within it, and this is what c_str()
returns. But the string itself is not a pointer, so you can't dereference it; you have to use the c_str()
method to get a pointer to the string contents.
Upvotes: 5