C# String For-Loop

String type

For loops over characters in strings. Some code examples use an inefficient string loop pattern—this causes unnecessary allocations on the managed heap. These loops can be improved and simplified.

This C# example program shows how to loop over a string with the for-loop.

Example

Note

Initially here we look at two loops over a single string reference's character data. Each loop compares each character in the source string against the space character. However, the first loop is much faster and results in less allocations on the managed heap because it compares characters directly.

The second loop draws in the overhead of creating new string objects based on each character. This is a clear mistake, but one that is made often in code examples on the Internet and likely in many real programs.

Program that uses for-loops on input string [C#]

using System;

class Program
{
    static void Main()
    {
	string input = "Dot Net Perls website";
	//
	// Check each character in the string using for-loop.
	//
	int spaces1 = 0;
	for (int i = 0; i < input.Length; i++)
	{
	    if (input[i] == ' ')
	    {
		spaces1++;
	    }
	}
	//
	// BAD: Check each character in the string with ToString calls.
	//
	int spaces2 = 0;
	for (int i = 0; i < input.Length; i++)
	{
	    if (input[i].ToString() == " ") // NO
	    {
		spaces2++;
	    }
	}
	//
	// Write results.
	//
	Console.WriteLine(spaces1);
	Console.WriteLine(spaces2);
    }
}

Output

3
3
For loop

Overview. The first loop in the program text uses a three-part for-loop statement with an if-statement in the loop body. If the character is a space, the value stored in the spaces1 variable is incremented. In this way, the for-loop iterates over all characters in the string and counts the total number of spaces. No allocations on the managed heap occur and this is a well-performing loop over the string.

Converting each character to a new string. The second loop in the program text also uses a for-loop statement to iterate over the characters in the string. However, after accessing the character value, it calls the ToString method. This requires an allocation of a new string on the managed heap, because strings are reference types. Then, the op_Equality method is invoked on the two string instances in the loop body. This loop is much slower because it must allocate the strings and then use string comparisons.

Benchmark

Performance optimization

Let's compare the two loops on the same input string that are shown in the above example. The for-loop that uses direct character comparisons is far faster, nearly ten times faster, than the for-loop that invokes the ToString method. After the benchmark results, we note another common string loop mistake.

Benchmark Programs
Benchmark description

Iterations:             10000000
Input string:           "Dot Net Perls website"
Loop bodies:            Same as in top example.
Character testing loop:  46.50 ns
ToString loop:          445.11 ns
Summary:                Using ToString was nearly ten times slower.

One-character substrings. Also, the ToString loop here has similarities to a pattern occasionally used by developers that loops over the string by taking a one-character substring, as in Substring(0, 1). This also results in a string allocation because it demands a new string reference. If you are testing characters, you also do not need to do this. Loops that use Substring will be much slower than character-testing loops for this reason.

Summary

The C# programming language

We looked at a string loop mistake in the C# language. Developers who are used to other languages where character iteration is different sometimes make this sort of mistake, which is likely more connected to unfamiliarity than anything else. It is not necessary to convert single characters in a for-loop to strings before comparing them. Converting characters to strings causes a performance degradation that can be one order of magnitude.

Loop Over String Chars Loop Constructs
.NET