08: Strings

UC Irvine - Fall ‘22 - ICS 45C

Quick list of things I want to talk about:

  • Mutable
  • c_str
  • Quotes
  • Size

Expanded notes:

Basics

A string is a type we use to store a bunch of text (a sequence of chars). However, strings are not a base type and not included by default in C++, so you should add a new include at the top of your file:

#include <string>

Similarly to cout and cin, strings are also a part of the std namespace, which we’ll learn more about it next week. For now, if you are using the using namespace std directive, it should all work out.

Declaring a string

We can create a string just like any other variable:

string test; // empty string
string other_test = "this one is initialized!";

One thing to note here is the double quotes! String require you to use those, if you use single quotes the compiler will want a single character inside of it.

A string has a some similarities to arrays:

  • no bound checks;
  • index access with [];

However, when you create a string without initialization like the example above, we can assume that it’s empty.

Mutability

Another similarity to arrays, and unlike in other languages, strings in C++ are mutable! So you could modify an existing index like this:

string msg = "hello";
msg[0] = 'H';

Unlike other arrays, you can append to a string like this:

string msg = "Hello";
msg += " world!";

If you do that, you modified the original string, and did not create a new one.

Size

As you saw above, a string is similar to a char array, but we can actually change its size. That works because string objects are not fully stored in the stack. They actually are split between the stack and the heap, where we have more space and flexibility how to use it. Again, we’ll get more into this when we cover pointers!

Comparisons

In C++11, we can compare strings using ==, !=, <, <=, >, and >=. All these comparisons compare the two strings alphabetically, not based on the actual objects.

Taking strings as input

So far we have been using cin >> x to take input. And if we try it out with strings, at first it seems to work fine:

string name;
int age;

cout << "Please enter your name and age: ";
cin >> name >> age;
cout << "Name: " << name << "\nAge: " << age << '\n';

If you run this code with this output:

Alice 20

You should see this output:

Name: Alice
Age: 20

Similarly, if you have that same input broken into lines you should see the same output. Using

Alice
20

as input would give us the same result.

However, what if Alice wants to type her last name too? What happens?

By using cin >> name >> age, cin is trying to be smart and break things apart. In that case, it would use the space as a delimiter, and only the first string would work as a name. So if you had this input:

Alice Zane 20

Or this:

Alice
Zane
20

Or this:

Alice Zane
20

cin would assign Alice to our variable name, but then try to convert the string Zane into an integer… which doesn’t work! So we would end up with this output:

Name: Alice
Age: 0

To go around that, we can ask our code to read an entire line into a variable. So instead of trying to break values by space, you can store everything until the user presses enter/return.

To do that, we can use the getline function. getline takes two arguments, where it’s reading from and where to store it. In the previous example, it would work like this:

string name;
int age;

cout << "Please enter your name and age: ";
getline(cin, name);
cin >> age;
cout << "Name: " << name << "\nAge: " << age << '\n';

Here, we’re trying to read from cin and store it in name. By doing it like this, we can store the entire first line in our variable. So if the input is:

Alice Zane
20

You should see this output:

Name: Alice Zane
Age: 20

Methods

String objects have a bunch of methods that you can use. A few that I think might be useful:

  • empty returns a bool indicating if the string is empty;
  • size and length return the size of characters in the string;
  • max_size returns the maximum number of characters that you can store in the string;
  • find finds a sequence of characters starting from the beginning;
  • rfind finds a sequence of characters starting from the end.

There are also some functions that might be useful:

  • stoi to convert a string to an int;
  • stof to convert a string to a float.

You can see all the methods and functions available here: https://en.cppreference.com/w/cpp/string/basic_string

Note that there isn’t a split method, which lets you tokenize a string. However, you can combine existing methods and string-functions to achieve the same goal, e.g., https://stackoverflow.com/a/14266139

C-strings

Whenever you’re looking for resources online, you might see strings defined as char str[] or char *str. That means it is an array of chars. This happens because on C, an array of chars is how you define strings, and they should always be terminated with a value of 0.

So, for example, if you want to store the word hi in a char [], you will need 3 positions. One for 'h', one for 'i', and one for 0, which is a null character that indicates the string terminated.

The reason you might see this in C++ is because some libraries that were originally written in C are still used. To make it easy for you, if you ever need to use a “c-style string”, the C++ string has a c_str method that you can use.

References