strstr专为c风格字符串设计,返回子串首次出现地址,要求参数均为合法null-terminated字符串;c++中推荐用std::string::find或c++23的contains替代。

用 strstr 判断字符数组是否包含子串最直接
strstr 是 C 标准库函数,专为 C 风格字符串(即以 '\0' 结尾的 char 数组)设计,返回首次匹配子串的起始地址,没找到就返回 nullptr。它不支持宽字符或 std::string,也不检查内存越界——前提是传入的两个指针都指向合法、以 '\0' 结尾的字符串。
典型用法就是直接比较返回值是否非空:
char text[] = "hello world";
char substr[] = "world";
if (strstr(text, substr) != nullptr) {
// 找到了
}
- 必须确保
text和substr都是 null-terminated;否则行为未定义 -
substr为空字符串(即仅含'\0')时,strstr总是返回text的首地址,这符合标准但容易被误判为“找到了有意义的子串” - 不区分大小写——要忽略大小写得自己实现或用
strcasestr(POSIX 扩展,非 ISO C 标准)
在 C++ 中混用 std::string 时别直接传 c_str() 就完事
虽然 std::string::c_str() 返回 const char*,看起来能喂给 strstr,但要注意:如果 std::string 对象在 strstr 调用期间被修改或析构,c_str() 返回的指针可能失效。更隐蔽的问题是,strstr 的第一个参数类型是 char*,而 c_str() 返回的是 const char*,直接传会触发隐式丢弃 const 的警告或编译错误(取决于编译器设置和 C++ 标准)。
安全做法是显式转成非 const 指针(仅当确定底层内存不会变)或改用 std::string::find:
std::string s = "hello world";
std::string sub = "world";
// 推荐:用 find,语义清晰、类型安全、自动处理边界
if (s.find(sub) != std::string::npos) {
// 找到了
}
-
std::string::find返回size_t,找不到时是std::string::npos(通常是-1的无符号表示) - 它支持从指定位置开始搜索、支持
std::string_view(C++17 起),比strstr更灵活 - 若必须用
strstr(比如对接 C API),应确保std::string生命周期覆盖整个调用,并用const_cast显式转换(仅当底层数据确为可写且你承担风险)
strstr 的性能和兼容性实际影响不大,但别在嵌入式或严格 C++ 环境里默认依赖它
strstr 实现通常是朴素的两重循环(O(n×m)),对短子串和普通长度主串足够快;glibc 等现代实现会用更优算法(如 Two-Way),但不用刻意优化。真正要注意的是环境约束:
- 某些嵌入式平台或 freestanding C++ 环境(如裸机、RTOS)可能不提供完整 C 库,
strstr不可用 - C++20 起,
<string></string>提供了std::string::contains(C++23 进一步扩展到std::string_view::contains),语义更直白,推荐新项目优先使用 - Windows 上,
strstr在多字节编码(如 GBK)下仍按字节匹配,不会识别汉字边界;若需 Unicode 子串匹配,必须用 ICU 或std::wstring+wcsstr
常见错误:把字符数组当指针传,却忘了它是局部数组
最容易踩的坑不是函数用错,而是生命周期管理出问题。例如:
const char* get_pattern() {
char buf[] = "abc"; // 局部数组,函数返回后栈内存失效
return buf; // 危险!
}
// 后续调用 strstr(text, get_pattern()) —— 行为未定义
类似地,用 std::vector<char></char> 存储字符串但没保证末尾有 '\0',传给 strstr 也会读越界。
- 字符数组变量名本身是地址,但必须确认其内容以
'\0'结尾,且生存期覆盖整个strstr调用 - 用
std::vector<char></char>或动态分配内存时,记得预留并写入终止符:v.push_back('\0') - 调试时遇到奇怪崩溃或返回随机地址,先检查两个参数是否真的指向合法 C 字符串
真正麻烦的从来不是“怎么调用 strstr”,而是确认那两个 char* 指向的东西,既存在,又以 '\0' 结尾,还活得比这次调用久。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











