Working with C-Style Strings

Searching for Substrings in C-Strings

How can I efficiently search for a substring within a C-style string?

Abstract art representing computer programming

Searching for a substring within a C-style string can be done efficiently using the strstr() function from the <cstring> library. This function returns a pointer to the first occurrence of the substring within the main string, or a null pointer if the substring is not found.

Here's a basic example of how to use strstr():

#include <iostream>
#include <cstring>

int main() {
  const char* haystack{
    "Hello, World! How are you?"};
  const char* needle{"World"};

  const char* result{
    std::strstr(haystack, needle)
  };  

  if (result) {
    std::cout << "Substring found at position: "
      << (result - haystack) << '\n';
    std::cout << "Remaining string: "
      << result << '\n';
  } else {
    std::cout << "Substring not found.\n";
  }
}
Substring found at position: 7
Remaining string: World! How are you?

In this example, strstr() efficiently finds "World" within our main string. The function returns a pointer to the start of the found substring, which we can use to calculate its position or print the remaining string.

However, strstr() has limitations:

  1. It's case-sensitive.
  2. It only finds the first occurrence.
  3. It doesn't allow for more complex search patterns.

For more advanced use cases, we might need to implement our own search function. Here's an example of a case-insensitive search that finds all occurrences:

#include <iostream>
#include <cctype>
#include <vector>

std::vector<const char*> findAll(
  const char* haystack,
  const char* needle
) {
  std::vector<const char*> results;
  const char* ptr{haystack};
  while (*ptr) {
    const char* start{ptr};
    const char* n{needle};
    while (*ptr && *n &&
      (std::tolower(*ptr) == std::tolower(*n))) {
      ptr++;
      n++;
    }
    if (!*n) {  // Found a match
      results.push_back(start);
      // Move past this match
      ptr = start + 1;
    } else {
      // No match, move to next character
      ptr = start + 1;
    }
  }
  return results;
}

int main() {
  const char* text{
    "The quick brown fox jumps over the lazy dog. "
    "The FOX is quick."};
  const char* search{"the"};

  auto results{findAll(text, search)};

  std::cout << "Found " << results.size()
            << " occurrences:\n";
  for (const auto& result : results) {
    std::cout << "Position: " << (result - text)
              << ", Context: " << result << '\n';
  }
}
Found 3 occurrences:
Position: 0, Context: The quick brown fox jumps over the lazy dog. The FOX is quick.
Position: 31, Context: the lazy dog. The FOX is quick.
Position: 41, Context: The FOX is quick.

This custom findAll() function demonstrates:

  1. Case-insensitive matching using std::tolower().
  2. Finding all occurrences, not just the first.
  3. Returning the positions and contexts of all matches.

While this approach works, it's worth noting that for more complex string operations or when performance is critical, you might want to consider using more advanced string matching algorithms like Knuth-Morris-Pratt or Boyer-Moore. These algorithms can provide better efficiency, especially for longer strings or repeated searches.

Remember that when working with C-style strings, you always need to be cautious about buffer overflows and ensure proper null-termination. In practice, using std::string and its member functions like find() and find_first_of() can often be safer and more convenient for string searching operations in C++.

Answers to questions are automatically generated and may not have been reviewed.

A computer programmer
Part of the course:

Professional C++

Comprehensive course covering advanced concepts, and how to use them on large-scale projects.

Free, unlimited access

This course includes:

  • 124 Lessons
  • 550+ Code Samples
  • 96% Positive Reviews
  • Regularly Updated
  • Help and FAQ
Free, Unlimited Access

Professional C++

Comprehensive course covering advanced concepts, and how to use them on large-scale projects.

Screenshot from Warhammer: Total War
Screenshot from Tomb Raider
Screenshot from Jedi: Fallen Order
Contact|Privacy Policy|Terms of Use
Copyright © 2024 - All Rights Reserved