Strings - The Basics
Strings - The Basics
Chapter 4 C++Institute
What is a string?
A string (in the C++ language sense) is not a cord or a ribbon, but a set of characters. You
might ask what we can use it for if we have a data type like char. That's a good question.
The char variables are useful (and generally all we need) when we want to process single
characters, but they’re extremely difficult when we have to deal with data containing all
kinds of names (e.g. surnames, city names, street names, etc) or just text (e.g. agreements,
statements or simply books or emails). Processing that kind of data as a set of chars
resembles spelling – it’s tedious and slow. It’s much easier to treat all characters as a
whole, stored, assigned and processed at the same time.
What is a string?
Note one very important fact: the string type is not a built-in type (like int which can be
used at any time with no special preparation). If we want to use strings in our code, we
have to put the #include directive at the top of our program and request a header file
named string to be included during the compilation.
This lack of directive will cause a compilation error. Remember – you’ve been warned.
Initializing a string
A string can be initialized in a way that is identical to the one used for other regular types
i.e. by using an assignment operator followed by a string literal (a set of characters
surrounded by double quotes). But don't forget: apostrophes are for character literals
only. Strings always use quotes.
Initializing a string
In effect, the newly created variable named PetName will be assigned with a string
consisting of the characters “Lassie”. This isn’t the only information stored inside
the PetName variable, but we don't want to get ahead of the facts.
Notice that sometimes we have to use the word string in two different meanings:
We don't use the assignment operator here. We use a syntax that clearly resembles the
function invocation, with a pair of parentheses and an argument within. You may ask if
there’s a real function named PetName being invoked. The answer is “yes and no”. Yes
because there’s a specialized function responsible for creating strings and the function is
being invoked every time you want to create a new string. No because you're not allowed
to directly invoke the function like any other regular function.
Initializing a string
You can also use a value stored in any string variable to initialize the newly declared
variable like in the example on the right →
Both forms (assigning and functional) are permissable.
String operators
Just like any other data type, the string type
has its own operators.
#include <iostream>
#include <string>
int main(void) {
string TheGood = "Sun", TheBad = "Lune";
cout << TheGood + TheBad << endl;
cout << TheBad + TheGood << endl;
return 0;
}
String operators
The + (concatenation) operator has one important limitation. It cannot concatenate
literals. It can concatenate any variable with a literal, a literal with a variable, and
obviously a variable with another variable, but concatenating literals is something the
operator will never do for us.
#include <iostream>
#include <string>
int main(void) {
string String;
String = "A" + "B";
String = String + "C";
String = "B" + String;
cout << String << endl;
return 0;
}
String operators: + =
We hope you aren’t surprised with the news that the + (concatenation) operator, just like its
arithmetic cousin, may be used as a short-cut operator.
Inputting strings
Inputting strings is a bit more complicated, due to the fact that the cin stream treats spaces
(to be precise, not only regular spaces but also all so-called white characters) as
delimiters, demarcating limits between data. It means that you may run into trouble if you
want to input and store a string containing white characters.
Comparing strings
Strings (just like any other data) may be compared. The simplest case occurs when you
want to check if two variables of type string contain identical strings.
Something similar happens when you enter your password on logging into an account. The
password you entered is compared to the password stored in the system and if both strings
are equal, access is granted. (The real process is obviously more complex, but our
description is good enough to show you the idea of comparing strings).
Comparing strings
If you want to check if two strings (i.e. variables of type string) contain the same string
(i.e. a chain of characters) you can use the old good == operator. It can answer your
question and satisfy your curiosity.
Comparing strings
Of course, you can compare two
strings in more flexible ways too.
All the operators designed to compare
data are at your disposal:
> < >= <= !=.
You can check if one of the strings is
greater/lesser than the other, but
remember that these comparisons are
carried out in alphabetical order
where 'a' is greater than 'A' (sic) and
obviously 'z' is greater than 'a', but
less obviously, 'a' is greater than '1'.
Comparing strings
- the objective approach
Strings offer another more complex, but also more powerful, method of comparison. We
can make use of it if we have some background knowledge of how objects manipulate their
data. This’ll be a good introduction to practising the object-oriented programming style.
In the classical approach, we usually have some data and a set of functions operating on
the data. We’re used to the following way of initiating data processing:
function(data);
Comparing strings
- the objective approach
In the object-oriented approach, we use slightly different terminology. Both the data and
the functions are embedded in the so-called object. The data is the
object's property or member variable, and the functions are the
object's methods or member functions.
We’ll return to these terms soon and explain their meaning in more detail.
If we want a particular method (member function) to process data embedded within an
object, we activate the member function for the object. It looks like this:
object.member_function();
Comparing strings
- the objective approach
Comparing strings
- the objective approach
Of course, the possibilities of the compare member function don’t stop at checking the
identity of the strings. The function can also diagnose all of the possible relations between
two strings. Here’s how it works:
Note, that the direction of the inequality is the same for both functional and objective
notations.
Comparing strings
- the objective approach
Substrings and more
Definition
All string operations we’ve shown you thus far have referred to whole strings i.e. both
strings were taken integrally, from the first to the last character. The strings allow
themselves to be processed in a more precise way when only selected parts of them are
taken into consideration. A part of a string is called a substring.
If we want to create a new string consisting of characters taken from another (or even the
same) string's substring, we can use a member function called substr, and its simplified,
informal prototype looks like this:
Both parameters have default values. This enables us to use the function in a more flexible way. So:
s.substr(1,2) describes a substring of the s string, starting at its second character and ending at its
third character (inclusively)
s.substr(1) describes a substring starting at the second character of the s string and containing all of
the remaining characters of s, including the last one; the omitted length_of_substring parameter
defaults to covering all the remaining characters in the s string
Because we already know how to define and use substrings, we can take a little step back
and show you some other variants of the compare functions. They allow us not only to
compare whole strings, but also their substrings. Their prototypes are clear to understand
and easy to use (well, we hope you agree). Here are two of them (as usual, we give them to
you informally):
We’ll start with the first, obviously simpler case. This variant of the compare member
function compares the entire other string to the substring of the source string. This means
that the following snippet will output 0 (the strings are equal):
string S = "ABC";
cout << S.compare(1,1,"B");
More detailed string comparison
The second variant allows us to use only a part of the other_string. Similarly, the following
snippet will also output 0:
string S = "ABC";
cout << S.compare(1,1,"ABC",1,1);
Finding strings inside strings
Sometimes we have not only to extract a substring from a particular string, but also (which
is much more complex) to find a substring within another string, taking into account the
possibility that it may fail (not all haystacks contain needles).
Strings can do this for us. They can search for a substring or for a single character. For this
purpose, we need to use one of the variants of the find member function. Two of them are
particularly useful:
We can control the size of the memory a string uses with the reserve member function. It
can work in both directions with the same ease, i.e. it can shrink the buffers as well as
expand them. The function requires one parameter of type int to specify the desired size
of the allocated buffers.
One important thing you need to know here: the content of the string isn't changed in any
way – we can say that the content is immune to the effect of the reserve function.
How can we control the size of the string?
How to control the content of the string
We can also control the content length of the string in many ways. The functions we’re
going to show you here may also change the memory allocations – this is a possible side
effect.
First of all, we can empty the string, completely removing all the characters currently
stored inside it. This is equivalent to assigning an empty string to the string, but it could
be a little bit faster.
Emptying the string is done by the member function called clear.
It requires no parameters.
How to control the content of the string
Changing the size of the string is carried out by the member function called resize. It's
basic variant requires one parameter of type int, specifying the desired new size of the
string. If the parameter is smaller than the current string size, the string will be truncated.
If the parameter is larger than the string size, the string will be expanded. You can also use
an overloaded form of the function allowing you to specify a character to be used to fill the
newly allocated space (the null character '\0' is used for that purpose by default).
How to control the content of the string
How to control the content of the string
Strings offer some convenient member functions to do this. We've said previously that
strings aren't arrays. Yes, it's still true, but they are able to present their content as if it
were an actual array.
We can assume that it's a kind of very useful masquerade – a string can wear a mask and
show itself as an ordinary (well, almost ordinary) array. It allows us to read and write
every character separately.
How to control the content of the string
Strings – temporary summation
Appending a (sub)string
Inserting a string into a string is like distending its contents from within. A new set of
contents is just “pushed” into the old one. For example: the following snippet of code will
print “to be or not to be” to the cout stream:
quote.append(quote);
The replace member function is more subtle. It can replace a part of the string with
another string or another string’s substring.
The function needs to know which part of the string it’s going to replace and you have to
specify this by delivering two numbers: the first describing the starting position and the
second saying how many characters will be replaced.
Replacing a (sub)string
The first overloaded function
needs a string (as a third
parameter) to replace the old
content (it may be either
longer or shorter or equal in
size in comparison to the
original). The second function
enables you to specify the
substring to be used as a
substitution.
The second variant of the
function is here on the right
→
Erasing a (sub)string
We can also remove a part of a string, making the string shorter than before. We can do
this by using a member function called erase (a name which leaves no room for doubt) and
the function requires two numbers in order to perform its duty: the place where the
substring to be removed starts (this value defaults to zero) and the length of the substring
(this value defaults to the original string’s length).
This means that an invocation like this
TheString.erase();
erases all the characters from the string and leaves it empty.
Erasing a (sub)string
Exchanging the contents of two strings
When we’re dealing with sorting, we have to be able to exchange the content of two
selected cells of an array. We have to have an auxiliary variable for that purpose, since the
operation resembles replacing the liquid content of two glasses – you can’t do this
successfully without using a third glass. So, if we want to replace a string (or a drink)
stored within Glass1 and Glass2 variables, we need a third variable (glass) to do it. This is
how it goes:
AGlass = Glass1;
Glass1 = Glass2;
Glass2 = AGlass;
Exchanging the contents of two strings