MindRoller
MindRoller

Reputation: 241

C# - String IndexOf method with second argument equal to String length

At some point in my code, I use this method:

IndexOf(string str, int startIndex)

I am also doing some calculations before, and I invoke this method with second argument (startIndex) equal to length of a string passed as first argument. Of course, no such an index exists in a string, and if we did something like this:

string[string.Length] 

we would get an IndexOutOfRangeException

How does that method work exactly? In MSDN documentation it is clearly said, that startIndex is zero-based index of a string. Does it work and doesn't throw because a char array that String class operates on is null-terminated? I want to make sure that my program won't throw at any point.

Upvotes: 2

Views: 3053

Answers (4)

D Stanley
D Stanley

Reputation: 152521

From the documentation:

If startIndex equals the length of the string instance, the method returns -1.

As to why it doesn't throw an exception if index==length like array accessors do, the framework designers would have to answer that since the documentation doesn't say, and the C# source code eventually calls an internal C function.. Some uneducated guesses:

  • Backward compatibility with legacy string functions
  • Unicode support

Upvotes: 2

poke
poke

Reputation: 387607

To the source!

public unsafe int IndexOf(char value, int startIndex, int count) {
    if (startIndex < 0 || startIndex > Length)
        throw new ArgumentOutOfRangeException(nameof(startIndex), Environment.GetResourceString("ArgumentOutOfRange_Index"));

    if (count < 0 || count > Length - startIndex)
        throw new ArgumentOutOfRangeException(nameof(count), Environment.GetResourceString("ArgumentOutOfRange_Count"));

    fixed (char* pChars = &m_firstChar)
    {
        char* pCh = pChars + startIndex;

        while (count >= 4)
        {
            // .. some search
        }

        while (count > 0)
        {
            // .. some search
        }
    }

    return -1;
}

As you can see, the ArgumentOutOfRangeException is only thrown when using a startIndex that is larger than the length of the string. Since you are passing the length itself, this is not a problem. If you were to pass a number larger than it, you would see the exception:

Console.WriteLine("foo".IndexOf('a', 3)); // -1
Console.WriteLine("foo".IndexOf('a', 4)); // throws ArgumentOutOfRangeException

Now, we’re not actually calling the IndexOf shown above. Instead we are calling the following signature:

public int IndexOf(char value, int startIndex) {
    return IndexOf(value, startIndex, this.Length - startIndex);
}

So for the count parameter above, the value this.Length - startIndex is passed. Since startIndex is equal to the length, count will be zero.

So the two while loops we see in the implementation above will not execute at all. And thus, the default result -1 is returned.

(Small note: I’m using the .NET Core source since the .NET Framework reference source does not include the source of this method. The implementations should be mostly identical though.)


As for why you can begin your search after the end of the string, I have a simple explanation that could be the reason. If you look at a string, you can start searching at multiple points. Let’s use "foo bar" as the string:

Index:        0 1 2 3 4 5 6
Character:    f o o   b a r
Points:      ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑
             0 1 2 3 4 5 6 7

As you can see, there are 8 points before or after a character for a string of length 7. When you specify things like a start index, you aren’t actually talking about the character index, but the point index of the space in between the characters. This is evident by a use of "foo bar".Substring(5, 1) where you get the characters between point 5 and point 6 (5+1). This is also why str.Substring(str.Length) is an actually logical use to get the empty string that’s at the end of the string.

Upvotes: 3

rory.ap
rory.ap

Reputation: 35270

MSDN clearly states what exceptions it can throw. For example:

ArgumentOutOfRangeException

startIndex is less than 0 (zero) or greater than the length of this string.

It goes on to say:

Index numbering starts from 0. The startIndex parameter can range from 0 to the length of the string instance. If startIndex equals the length of the string instance, the method returns -1.

So there's really no guesswork required regarding exceptions.

Upvotes: 2

Tim Schmelter
Tim Schmelter

Reputation: 460098

It's mentioned explicitly in the documentation:

Index numbering starts from 0. The startIndex parameter can range from 0 to the length of the string instance. If startIndex equals the length of the string instance, the method returns -1.

Upvotes: 5

Related Questions