Add ^ to the beginning of your pattern, and add $ to the end of it to match the beginning and end of the string, respectively. This will make the pattern match the entire string and produces your desired result:
string input = "Mountain View, CA 94043";
string pattern = @"^(?i:(?:([^\d,]+?)\W+\b((?:CA|SD|SC|CT|DC)\b)?\W*)?(\d{5}(?:[- ]\d{3,4})?)?)$";
Match m = Regex.Match(input, pattern);
foreach (Group g in m.Groups)
{
Console.WriteLine(g.Value);
}
Since you didn't restrict the pattern to be an exact match, as above, it found partial matches, especially since some of your groups are completely optional. Thus, it considers "Mountain" a match, then considers "View, CA 94043" as the next match.
EDIT: as requested in the comments, I'll try to point out the differences between the Java and .NET regex approaches.
In Java the matches() method returns true/false if the pattern matches the whole string. Thus it doesn't require the pattern to be modified with boundary anchors or atomic zero-width assertions. In .NET there is no such equivalent method that will do this for you. Instead, you need to explicitly add either the ^ and $ metacharacters, to match the start and end of the string or line, respectively, or the \A and \z metacharacters to do the same for the entire string. For a reference of .NET metacharacters check out this MSDN page. I'm not sure which set of anchors Java's matches() uses, although this article suggests \A and \z are used.
Java's matches() returns a boolean, and .NET provides the Regex.IsMatch() method to do the same thing (apart from the already discussed difference of matching the entire string). The .NET equivalent of Java's find() method is the Regex.Match() method, which you can use in a loop to continue to find the next match. In addition, .NET offers a Regex.Matches() method that will do this for you, and returns a collection of successful matches. Depending on your needs and the input this might be fine, but for added flexibility you may want to check Match.Success in a loop and use the Match.NextMatch() method to keep looking for matches (an example of this is available in the NextMatch link).