Skip to content

Beginner · References, pointers, arrays and strings · topic 12 of 42 · 30 min

Text: C strings and std::string

Explanation

C strings are char arrays ending in a hidden '\0' character and are easy to misuse. std::string manages its own memory, grows as needed and has handy functions: size, substr, find, + and comparisons. Use std::string for text in C++, and std::to_string / std::stoi to convert numbers.

Two kinds of text

C++ inherited C's way of storing text: an array of char that ends with a special character '\0' (the null terminator) so functions know where the text stops. These are called C strings. They are fixed in size and easy to overflow. C++ adds std::string, a class from the standard library that grows as needed and frees its own memory. Use std::string unless a C library forces you to use C strings.

cpp
const char* cStr = "Pune";        // 5 chars in memory: P u n e \0
std::string city = "Pune";         // a std::string
std::cout << city.size() << '\n';  // 4 (the \0 is not counted)
A string literal like "Pune" is a C string; std::string can be built from it.

Everyday std::string operations

cpp
#include <iostream>
#include <string>

int main() {
    std::string first = "Asha", last = "Verma";
    std::string full = first + " " + last;     // joining (concatenation)
    std::cout << full << '\n';                  // Asha Verma
    std::cout << full.size() << '\n';           // 10
    std::cout << full[0] << '\n';               // A
    std::cout << full.substr(5, 3) << '\n';     // Ver (from index 5, 3 chars)

    std::size_t pos = full.find("Verma");
    if (pos != std::string::npos) {
        std::cout << "found at " << pos << '\n';  // found at 5
    }
    full += "!";                                // append
    full.replace(0, 4, "Ravi");                 // Ravi Verma!
    std::cout << full << '\n';
}
find returns std::string::npos (a special "not found" value) when the text is missing.

Comparing and looping

cpp
std::string a = "apple", b = "banana";
if (a < b) std::cout << "apple comes first\n";   // dictionary order
if (a == "apple") std::cout << "same text\n";

int vowels = 0;
for (char c : std::string("Bengaluru")) {
    if (c == 'a' || c == 'e' || c == 'i' || c == 'o' || c == 'u') ++vowels;
}
std::cout << vowels << '\n';   // 4
std::string supports ==, < and friends, compared character by character.
Careful: With C strings, == compares ADDRESSES, not text. const char* a = "hi"; char b[] = "hi"; a == b is false even though the text is the same. With std::string, == compares the text. This is one more reason to prefer std::string.

Characters: <cctype>

cpp
#include <cctype>
std::string s = "Upi123";
int digits = 0;
for (char c : s) {
    if (std::isdigit(static_cast<unsigned char>(c))) ++digits;
}
std::string up = s;
for (char& c : up) c = static_cast<char>(std::toupper(static_cast<unsigned char>(c)));
// digits == 3, up == "UPI123"
isdigit, isalpha, isspace, toupper and tolower work on single characters. The unsigned char cast avoids undefined behaviour with non-ASCII bytes.

Numbers to text and back

cpp
int pin = 411001;
std::string s = std::to_string(pin);    // "411001"
int n = std::stoi("250");               // 250
double d = std::stod("99.5");           // 99.5
// std::stoi("abc") throws std::invalid_argument
std::stoi / std::stol / std::stod convert text to numbers and throw an exception on bad input.

Unicode note

A char is one byte. English letters fit in one byte, but Hindi, Tamil and emoji in UTF-8 use several bytes per character, so "नमस्ते".size() is 18: it is made of 6 Unicode code points (letters and vowel signs) of 3 bytes each, even though you see only about four letter shapes. For real Indian-language text processing, use a Unicode library (for example ICU). For most backend work, you just store and pass the UTF-8 bytes along unchanged, which std::string does fine.

Tip: std::string_view (C++17) is a cheap, read-only "window" onto existing text. It is great for function parameters that only read text, but it does not own the characters, so never keep a string_view to a temporary string after that string is gone.

Common mistakes

  • Forgetting #include <string>. Sometimes it compiles anyway through another header, then fails on a different compiler.
  • Using s[i] with i >= s.size(). Use .at(i) while learning; it throws instead of corrupting memory.
  • Comparing find() with -1 or 0 instead of std::string::npos.
  • Adding two string literals: "Hello" + " world" is an error (both are C strings). Make one a std::string first.

Need help?

Stuck on a word or an idea? Search this course, or every course, and jump straight to the explanation or a worked question.

Try:

Watch the lesson

Text: C strings and std::string · 1/6

C strings vs std::string

Text in C plus plus comes in two kinds: old C strings and std string. Use std string.

Prefer a video by a teacher? Find free videos on “c++ std::string tutorial substr find stoi to_string” on YouTube ↗

In real life: Checking a PAN number format

A PAN (Permanent Account Number) has 10 characters: 5 capital letters, 4 digits and 1 capital letter, like ABCDE1234F. Banks and tax websites check this shape before sending the number to the server. A short loop over a std::string with <cctype> functions does the check.

cpp
#include <cctype>
#include <iostream>
#include <string>

bool looksLikePan(const std::string& s) {
    if (s.size() != 10) return false;
    for (int i = 0; i < 10; ++i) {
        unsigned char c = static_cast<unsigned char>(s[i]);
        bool letterPlace = (i < 5 || i == 9);
        if (letterPlace && !std::isupper(c)) return false;
        if (!letterPlace && !std::isdigit(c)) return false;
    }
    return true;
}

int main() {
    std::cout << looksLikePan("ABCDE1234F") << looksLikePan("ABCD12345F") << '\n';   // 10
}
Only the shape is checked; the real verification happens with the tax department's service.

Practice (0/4 done)

Task 1 · Question

std::string s = "Mumbai"; What is s.size()?

Task 2 · Question

What does this print? std::string s = "Hyderabad"; std::cout << s.substr(0, 5) << " " << s.find("bad");

Task 3 · Question

Which line does NOT compile?

Task 4 · Practice

Write std::string initials(const std::string& fullName) that returns the capital initials of a name, so "rahul kumar sharma" becomes "RKS". Then write bool isPalindromeWord(const std::string& w) that ignores case ("Malayalam" is true).

Quick quiz

Question 1

1.What marks the end of a C string?

Question 2

2.What does s.find("x") return when "x" is not in s?

Question 3

3.Which converts the text "450" to the int 450?

Question 4

4.std::string a = "apple", b = "Apple"; Is a == b?

Question 5

5.Why can "नमस्ते".size() be larger than the number of letters you see?

Read more (free)

Open a question to see the answer and why. The first ones are this topic's own quiz, so try the quiz above before you peek.

What marks the end of a C string?

Answer: The null character '\0'

C functions read characters until they meet '\0'.

What does s.find("x") return when "x" is not in s?

Answer: std::string::npos

npos is the largest value of std::size_t and means "not found".

Which converts the text "450" to the int 450?

Answer: std::stoi("450")

stoi means "string to int". to_string goes the other way.

std::string a = "apple", b = "Apple"; Is a == b?

Answer: No, comparison is case sensitive

Characters are compared exactly; 'a' and 'A' are different.

Why can "नमस्ते".size() be larger than the number of letters you see?

Answer: Hindi characters take several bytes each in UTF-8, and size counts bytes

std::string stores bytes. Devanagari characters use 3 bytes each in UTF-8.

What marks the end of a C string?Related

Answer: The null character \0

Every string function stops at \0.

From Strings are char arrays

Which is best for joining 10,000 pieces of text in a loop?Related

Answer: strings.Builder

Builder appends to one growing buffer instead of copying the whole string each time.

From Strings, bytes and runes

Why is comparing set("aab") with set("abb") a wrong anagram check?Related

Answer: Sets keep only which characters appear, not how many times

Both sets are {"a", "b"}, but the counts differ, so they are not anagrams.

From Strings: building, comparing and counting

What is the main advantage of std::vector over a C-style array?Related

Answer: Its size can change at run time and it knows its size

vector grows with push_back and reports size(); it also manages its own memory.

From Arrays, std::array and a first look at std::vector

Pass the quiz (60% or more) or mark this topic as done when you are ready.

Your progress is saved on this device only.

Next steps

  1. This is the last topic of “References, pointers, arrays and strings”. The module exam comes next.
  2. Module 3 exam: References, pointers, arrays and strings · 12 questions · 20 min, without help. 4 topics of this module still to finish first.
  3. Then the next module, Classes, constructors and RAII. 42 topics left in the course before the final exam.

← Previous: Arrays, std::array and a first look at std::vector