Character access
There are two almost identical ways to access characters in a string. The easier to use and faster version is the overloaded operator[]:
char& string::operator[] (size_type nIndex)
const char& string::operator[] (size_type nIndex) const
- Both of these functions return the character with index nIndex
- Passing an invalid index results in undefined behavior
- Using length() as the index is valid for const strings only, and returns the value generated by the string’s default constructor. It is not recommended that you do this.
- Because char& is the return type, you can use this to edit characters in the array
Sample code:
|
std::string sSource{ "abcdefg" }; std::cout << sSource[5] << '\n'; sSource[5] = 'X'; std::cout << sSource << '\n'; |
Output:
f
abcdeXg
|
There is also a non-operator version. This version is slower since it uses exceptions to check if the nIndex is valid. If you are not sure whether nIndex is valid, you should use this version to access the array:
char& string::at (size_type nIndex)
const char& string::at (size_type nIndex) const
- Both of these functions return the character with index nIndex
- Passing an invalid index results in an out_of_range exception
- Because char& is the return type, you can use this to edit characters in the array
Sample code:
|
std::string sSource{ "abcdefg" }; std::cout << sSource.at(5) << '\n'; sSource.at(5) = 'X'; std::cout << sSource << '\n'; |
Output:
f
abcdeXg
|
Conversion to C-style arrays
Many functions (including all C functions) expect strings to be formatted as C-style strings rather than std::string. For this reason, std::string provides 3 different ways to convert std::string to C-style strings.
const char* string::c_str () const
- Returns the contents of the string as a const C-style string
- A null terminator is appended
- The C-style string is owned by the std::string and should not be deleted
Sample code:
|
std::string sSource{ "abcdefg" }; std::cout << std::strlen(sSource.c_str()); |
Output:
7
|
const char* string::data () const
- Returns the contents of the string as a const C-style string
- A null terminator is appended. This function performs the same action as
c_str()
- The C-style string is owned by the std::string and should not be deleted
Sample code:
|
std::string sSource{ "abcdefg" }; const char *szString{ "abcdefg" }; // memcmp compares the first n characters of two C-style strings and returns 0 if they are equal if (std::memcmp(sSource.data(), szString, sSource.length()) == 0) std::cout << "The strings are equal"; else std::cout << "The strings are not equal"; |
Output:
The strings are equal
|
size_type string::copy(char *szBuf, size_type nLength) const
size_type string::copy(char *szBuf, size_type nLength, size_type nIndex) const
- Both flavors copy at most nLength characters of the string to szBuf, beginning with character nIndex
- The number of characters copied is returned
- No null is appended. It is up to the caller to ensure szBuf is initialized to NULL or terminate the string using the returned length
- The caller is responsible for not overflowing szBuf
Sample code:
|
std::string sSource{ "sphinx of black quartz, judge my vow" }; char szBuf[20]; int nLength{ static_cast<int>(sSource.copy(szBuf, 5, 10)) }; szBuf[nLength] = '\0'; // Make sure we terminate the string in the buffer std::cout << szBuf << '\n'; |
Output:
black
|
Unless you need every bit of efficiency, c_str() is the easiest and safest of the three functions to use.
Hi
Thankyou for awesome tutorial.
Could you please clarify contradicting statements:
In table of chap: 22.1
data() -- Returns the contents of the string as a non-NULL-terminated character array
in chap: 22.4
const char* string::data () const
Returns the contents of the string as a const C-style string
A null terminator is appended. This function performs the same action as c_str()
Which one is correct : data returns null terminating string or non null terminating string?
2nd one seems correct
2nd is correct. I updated lesson 22.1, thanks for pointing it out!
I don't quite get the message- "The C-style string is owned by the std::string and should not be deleted". What do you mean by "owned by std::string and should not be deleted"?
`std::string` has dynamically allocates a C-style string. The C-style string is a member of the class `std::string`. `std::string` owns that C-style string. If you call `delete` on the C-style string, eg.
you're invoking undefined behavior, because the `std::string` will try to delete the C-style string again.
In this code example from the lesson:
I cannot initialize like this
throws the following error:
"error: ISO C++ forbids converting a string constant to 'char*' [-Wpedantic]|".
Works only this way:
P.S.
I just realized that if I uncheck a certain warning under compiler flags, the previous problem suddenly isn't a problem anymore. Not so much a compiler error, as some ISO standard which I generally don't understand.
Lesson updated to use `const char*`, thanks for pointing out the error.
Also note that the section about `data()` was outdated. `data()` and `c_str()` are the same, they both null-terminate the string.
> I just realized that if I uncheck a certain warning [...]
C++ is a standardized language. That is, no matter which compiler you use, the compilers have to produce programs with identical behavior.
By disabling the option you just disabled, you allowed compiler extensions. You're now allowed to do things that aren't in the standard, ie. you code isn't pure C++ anymore, it might not work for other people. Re-enable the option to make sure you're writing portable code.
I didn't even realize it was an error. :)
>>> `data()` and `c_str()` are the same, they both null-terminate the string.
Great! Thanks.
Had already re-enabled it!
And thanks. Finally this small mystery has been solved.
Why does string::copy(char *szBuf, size_type nLength, size_type nIndex) have its parameters backwards? Other functions expect the index first and the length second.
I have no idea. :)
Hi! You said that "c_str() is the easiest and safest of the three functions to use", but I disagree. If you get the C-style string via c_str() from a std::string and then perform appending on the std::string such that a reallocation occurs, the memory of the C-style string previously retrieved will be deallocated, so you will have a dangling pointer. This scenario can be reproduced with the following code:
Here is my favorite safer alternative, but there might be easier ones:
Hi Alex,
I tried running the following code:
But I am getting this error:
prog.cpp: In function 'int main()':
prog.cpp:8:39: error: 'strlen' was not declared in this scope
cout << strlen(sSource.c_str());
Can you please describe what is the problem in the following code?
strlen lives in the cstring header. #include <cstring> and you should be good to go.
Hi alex.First of all I'm very thankful to you for your awesome tutorials.
I have written program that changes all strings given by user in upper case to lower case.And I'm failed.Here is my code and I wish you could help with my problem.
[#include<string>
#include <iostream>
int main()
{
using namespace std;
string lwr ("abcdefgh");
string upr ("ABCDEFGH");
string Astring;
cout << "Enter a string: ";
cin >> Astring;
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 8; j++)
if (Astring[i] = upr[j])
{
Astring[i] = lwr[j];
}
else { }
}
cout << "String in lowercase: " << Astring;
return (0);
}]
I wrote only for these a,b,c,d,e,f,g,h letters.If my input is like deF then my program's output should be def.
I'd write a function that takes a reference to a character and if that character is found in lwr, converts it to the corresponding character in upr.
Then you could loop through Astring letter by letter and call the function on each letter.
Wrong equals!
should be
Trevor
Hi there,
I do not understand this
"Using length() as the index is valid for const strings only, and returns the value generated by the string’s default constructor. It is not recommended that you do this."
Could anyone help?
thanks,
Yang
Hi, Yang.
Let us see whether the aforementioned paragraph is correct or not:
"“Using length() as the index is valid for const strings only, and returns the value generated by the string’s default constructor. It is not recommended that you do this.”"
Let us write the following sample program:
#include <iostream>
#include <string>
using namespace std;
int main()
{
const string scSource("abcdefg");
string::size_type nLength = scSource.length();
cout << "Const string is: ["
<< scSource << "]" << endl;
cout << "Const string length is: ["
<< nLength << "]" << endl;
cout << "Last character is: ["
<< scSource[nLength-1] << "]" << endl;
cout << "Using length() returns: ["
<< scSource[nLength] << "]" << endl << endl << endl;
string sSource("hijklmn");
nLength = sSource.length();
cout << "Non-const string is: ["
<< sSource << "]" << endl;
cout << "Non-const string length is : ["
<< nLength << "]" << endl;
cout << "Last character is: ["
<< sSource[nLength-1] << "]" << endl;
cout << "Using length() returns: ["
<< sSource[nLength] << "]" << endl;
return 0;
}
The output of this sample program is:
Const string is: [abcdefg]
Const string length is: [7]
Last character is: [g]
Using length() returns: [ ]
Non-const string is: [hijklmn]
Non-const string length is : [7]
Last character is: [n]
Using length() returns: [ ]
As you can see, the string::operator[] is applicable using the length() function for both const strings and non-const strings - unlike specified in the aforementioned paragraph.
However, the results are unpredictable. In the output produced above using the Code::Blocks Integrated Development Environment and the gcc compiler, nothing was returned in both cases. This is probably why length()'s usage is not recommended.
I LOVED YOUR TUTORIAL. Thank you so much.
I've been trying to learn C++ for years, but I always got stucked in the pointers. Finally I understood them.
I wanted to make games, so I started with BASIC (like 13 years ago), then I learned Visual Basic 6 (bad idea), so when I tried to learn C++ I just cried xD.
Thanks again!!!!
Well, what a journey! Simply amazing tutorial. The best, by far. Clear and concise, exposing exactly what we want to know and mentioning the more advanced or lesser known/used stuff (instead of just not bringing them up at all). You should write a book! I would like to see more chapters added that explore some of the classes that others have suggested throughout the tutorials. I'm sure the information exists somwhere already is merely a Google away, but the way you present information is the best I've seen.
Oh, is there a way to get all of this tutorial in a pre-archived format so that I can download it all as a whole package? Would save me heading online all the time.
Anyway, thanks and bye.
can anybody write me a programme to open the url using C++ please give the complete programme
Awesome tutorial. I was looking to learn C++ for some game programing. I'm pretty bad at math, but it seems pretty managable the way you present it. Thanks so much.
Thank you for the great tutorial,
It really helped me learn to program in c++, and I believe it helped me to write better programs in general.
The tutorial was really clear and easy to understand, and I found it quite complete already.
I'm sure I will check back to skim-read one of the harder topics or see if you put up a new chapter for this awesome tutorial.
Amazing tutorial, thank you! When studying a C++ course at university where pedagogy is not prioritized it's a bless to have a tutorial like this to learn the basics.
Even though I know it is not your intent to cover the standard library some examples covering things like iterators, vectors and such would be much appreciated in the future.