Start learning free

LESSON 169 OF 347 · STRINGS

Strings in C#: Indexing, Substring and Immutability

Lesson Read the full explanation

The Java String is an object that represents a sequence of characters, each identified by one index.

Creation:

To create strings in Java, you use double quotes like this:

string greeting = "Hello";

Accessing characters:

To access the characters in a string, you use the [) method

The following example returns the first character of a string with the index zero:

string str = "Hello";
char ch = str[0); 
// ch is "H"

Getting the length:

We can get the length of a string using the length() method.

For example, to access the last character of the string, you use the length() - 1 index:

string str = "Hello";
char ch = str[str.Length - 1); 
// ch is "o"

Concatenating strings via + operator:

To concatenate two or more strings, you use the + operator:

string name = "John";
string str = "Hello " + name;

Console.WriteLine(str); // prints "Hello John"

If you want to assemble a string piece by piece, you can use the += operator:

string greet = "Welcome";
string name = "John";
greet += " to AlgoCademy, ";
greet += name;

Console.WriteLine(greet); // "Welcome to AlgoCademy, John"

When concatenating many strings, it is recommended to use StringBuilder for performance

String slicing

We often want to get a substring of a string. For this, we use the substring() method.

substring(startIndex, endIndex) returns the substring from startIndex to endIndex:

string str = "JavaScript";
string substr = str.Substring(2, 6);

Console.WriteLine(substr); // prints "vaSc"

The startIndex is a zero-based index at which the substring() start extraction.

The endIndex is also zero-based index before which the substring() ends the extraction. The substr will not include the character at the endIndex index.

If you omit the endIndex, the substring() extracts to the end of the string:

string str = "JavaScript";
string substr = str.Substring(4);

Console.WriteLine(substr); // "Script"

String Immutability:

In Java, String values are immutable, which means that they cannot be altered once created.

For example, the following code:

string myStr = "Bob";
myStr[0] = 'J'; // compile error!!!

cannot change the value of myStr to "Job", because the contents of myStr cannot be altered.

Note that this does not mean that myStr cannot be changed, just that the individual characters of a string literal cannot be changed. The only way to change myStr would be to assign it with a new string, like this:

string myStr = "Bob";
myStr = "Job";
//or
myStr = 'J' + myStr.Substring(1, 3);

Immutability affects performance when concatenating many strings, it is recommended to use StringBuilder for performance

Convert a string to an array of characters:

When we have to change characters often in a string, we want a way of doing this quickly. Because strings are immutable, we change a character by creating a whole new string, which is O(n).

But arrays are mutable and changing an element in an array is O(1). So what we can do is first convert our string to an array of characters, operate on that array and than convert the array back to a string.

We can convert a string to an array using the toCharArray() method like this:

string str = "Andy";
char[] myArr = str.ToCharArray();

// myArr is ['A', 'n', 'd', 'y']
myArr[0] = 'a';
myArr[2] = 'D';

// We convert an array of chars back to a string using the constructor:
str = new string(myArr);

Console.WriteLine(str); // "anDy"

Iterating through the characters:

We can iterate throught the elements of a string using indices and a for loop like this:

string myStr = "Andy";
for (int i = 0; i < myStr.Length; i++) {
    Console.WriteLine(myStr[i));
}

// This will print the characters 'A', 'n', 'd' and 'y' on different lines

This takes O(n) time, where n is the length of the array we iterate on.


Assignment
Follow the Coding Tutorial and let's play with some arrays.


Hint
Look at the examples above if you get stuck.


STEP 1 OF 7
    Ctrl + Enter to check

    C# · STRINGS

    Strings in C#, explained

    What this lesson covers

    A C# string is an immutable sequence of characters. This lesson walks through the everyday operations: creating a string, reading characters, getting the length, joining strings, cutting out a piece with Substring, and the one workaround for editing characters, which is to go through a char[]. The exercise at the end turns "Java" into "TypeScript" using most of these.

    Creating, indexing and length

    A string literal uses double quotes. Square brackets with a zero-based index return one character as a char, and the Length property (a property, so no parentheses) gives the number of characters:

    string str = "Hello";
    char first = str[0];                 // 'H'
    char last = str[str.Length - 1];     // 'o'
    

    The last valid index is always Length - 1. Code ported from Java often calls charAt(i) or length(); in C# those are str[i] and Length.

    Joining strings

    The + operator joins two strings into a new one, and += joins and stores the result back in the variable:

    string name = "John";
    string greet = "Welcome";
    greet += " to the course, ";
    greet += name;
    Console.WriteLine(greet);   // Welcome to the course, John
    

    Each += creates a new string and copies the old text into it. That's fine for a handful of pieces, but when a loop appends thousands of times, use a StringBuilder, which grows in place.

    Substring

    Substring cuts a piece out of a string. It has two forms, and they take different arguments:

    • Substring(start) returns everything from index start to the end.
    • Substring(start, length) returns length characters beginning at start. The second argument is a length, not an end index. That differs from Java's substring(start, end) and JavaScript's slice(start, end).
    string str = "JavaScript";
    Console.WriteLine(str.Substring(4));      // Script
    Console.WriteLine(str.Substring(2, 6));   // vaScri  (6 characters from index 2)
    Console.WriteLine(str.Substring(10));     // prints an empty line
    

    A start index equal to Length gives an empty string, but asking for more characters than remain throws an ArgumentOutOfRangeException. For example, "Bob".Substring(1, 3) throws, because only two characters follow index 1.

    Immutability

    You can read a character with str[i], but you can't assign to it:

    string myStr = "Bob";
    myStr[0] = 'J';   // compile error: strings are read-only by index
    

    A variable can still be pointed at a different string, so building a new value works fine:

    string myStr = "Bob";
    myStr = "Job";
    myStr = 'J' + myStr.Substring(1);   // "Job" again: a char plus a string gives a string
    

    String methods follow the same rule. str.ToUpper() returns a new string and leaves str unchanged, so the result must be assigned to be kept.

    Editing characters through a char array

    To change several characters, copy the string into a char[], edit the array, and build a string from it. Array elements are mutable and each assignment takes O(1):

    string str = "Andy";
    char[] myArr = str.ToCharArray();   // ['A', 'n', 'd', 'y']
    myArr[0] = 'a';
    myArr[2] = 'D';
    str = new string(myArr);
    Console.WriteLine(str);             // anDy
    

    Note that ToCharArray() makes a copy, so editing the array never touches the original string. The conversion in each direction costs O(n).

    Iterating over the characters

    A for loop over the indexes visits each character once, which takes O(n) time for a string of length n:

    string myStr = "Andy";
    for (int i = 0; i < myStr.Length; i++) {
        Console.WriteLine(myStr[i]);
    }
    

    This prints A, n, d and y on separate lines. A foreach (char c in myStr) loop does the same when you don't need the index.

    The exercise, step by step

    The goal is to end up with the string "TypeScript", starting from "Java".

    1. Create lang. Declare string lang = "Java";.
    2. Append with +=. Adding "script" turns it into "Javascript". Because strings can't change, the operator builds a new string and stores it in lang.
    3. Take the tail. lang.Substring(4) starts at index 4, the s, and returns "script". The single argument means "to the end".
    4. Prefix it. "Type" + substr gives "Typescript", stored in newLang.
    5. Get a mutable copy. newLang.ToCharArray() returns a char[] named charArray.
    6. Capitalise the letter. The s is the fifth character, at index 4, so charArray[4] = 'S';. Use single quotes, because the element is a char.
    7. Convert back. new string(charArray) builds a string from the array, and assigning it to newLang gives "TypeScript".
    string lang = "Java";
    lang += "script";
    string substr = lang.Substring(4);
    string newLang = "Type" + substr;
    char[] charArray = newLang.ToCharArray();
    charArray[4] = 'S';
    newLang = new string(charArray);
    

    Common mistakes

    • Treating the second Substring argument as an end index. It is a length.
    • Using double quotes for a character. charArray[4] = "S"; doesn't compile, because a char element needs 'S'.
    • Off-by-one on the last character. str[str.Length] throws an IndexOutOfRangeException; the last index is Length - 1.
    • Ignoring the return value. A call such as lang.Substring(4); on its own computes a string and throws it away.
    • Writing .Length() or .length. In C# it is Length, with a capital L and no parentheses.

    Key takeaways

    • Strings are immutable; every operation that seems to change one produces a new string.
    • Substring(start) goes to the end, and Substring(start, length) takes a length.
    • Go through ToCharArray() and new string(...) to edit characters in bulk.
    • Use StringBuilder when appending many times in a loop.
    Keep going with C#About 340 step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free