ZetCode

C strstr 函数

最后修改:2025 年 4 月 8 日

字符串操作在 C 编程中至关重要,而 strstr 是查找子字符串的关键函数。本教程将深入探讨 strstr,包括其语法、用法和潜在的陷阱。我们将探讨实际示例,并讨论对关键应用程序更安全的替代方法。理解 strstr 有助于在保持程序安全性和可靠性的同时高效地搜索字符串。

什么是 strstr?

strstr 函数用于定位字符串中子字符串的第一次出现。它在 string.h 中声明,并接受两个参数:文本字符串和要查找的子字符串。strstr 返回指向找到的子字符串的指针,如果未找到则返回 NULL。对于安全关键代码,请考虑使用带边界检查的替代方法或仔细验证输入。

基本的 strstr 用法

此示例演示了使用 strstr 查找子字符串。

basic_search.c
#include <stdio.h>
#include <string.h>

int main() {
    const char *text = "The quick brown fox jumps over the lazy dog";
    const char *sub = "fox";
    
    char *result = strstr(text, sub);
    
    if (result != NULL) {
        printf("Found '%s' at position: %ld\n", sub, result - text);
    } else {
        printf("'%s' not found\n", sub);
    }
    
    return 0;
}

在这里,strstr 在示例文本中搜索“fox”。该函数返回指向找到的子字符串第一个字符的指针。我们通过从文本指针中减去结果指针来计算位置。这是在 C 字符串中查找子字符串的简单有效的方法。请务必检查 NULL 返回值。

不区分大小写的搜索

此示例展示了如何使用 strstr 实现不区分大小写的搜索。

case_insensitive.c
#include <stdio.h>
#include <string.h>
#include <ctype.h>

char* stristr(const char *haystack, const char *needle) {
    do {
        const char *h = haystack;
        const char *n = needle;
        
        while (tolower(*h) == tolower(*n) && *n) {
            h++;
            n++;
        }
        
        if (*n == 0) {
            return (char*)haystack;
        }
    } while (*haystack++);
    
    return NULL;
}

int main() {
    const char *text = "C Programming Language";
    const char *sub = "PROGRAMMING";
    
    char *result = stristr(text, sub);
    
    if (result) {
        printf("Found '%s' at position: %ld\n", sub, result - text);
    } else {
        printf("'%s' not found\n", sub);
    }
    
    return 0;
}

这实现了 strstr 的不区分大小写的版本,称为 stristr。它在比较之前将字符转换为小写。该函数遵循与 strstr 相同的模式,但忽略大小写。请注意,这不是标准 C 库的一部分。对于生产代码,请考虑更有效的算法,如 Boyer-Moore,用于处理大文本。

查找多个出现

此示例演示了查找子字符串的所有出现。

multiple_occurrences.c
#include <stdio.h>
#include <string.h>

int main() {
    const char *text = "apple orange apple banana apple";
    const char *sub = "apple";
    
    const char *ptr = text;
    int count = 0;
    
    while ((ptr = strstr(ptr, sub)) {
        printf("Found '%s' at position: %ld\n", sub, ptr - text);
        ptr += strlen(sub);
        count++;
    }
    
    printf("Total occurrences: %d\n", count);
    return 0;
}

此代码在文本中查找“apple”的所有出现。每次找到后,它会将搜索指针移到找到的子字符串之后。循环继续,直到 strstr 返回 NULL。此技术对于计数或处理字符串中的所有匹配项很有用。请注意不要使用零长度子字符串创建无限循环。

提取分隔符之间的文本

此示例展示了如何使用 strstr 提取分隔符之间的文本。

extract_between.c
#include <stdio.h>
#include <string.h>

int main() {
    const char *text = "Data: [important] and [secret]";
    const char *start_delim = "[";
    const char *end_delim = "]";
    
    const char *start = text;
    const char *end;
    
    while ((start = strstr(start, start_delim))) {
        start += strlen(start_delim);
        end = strstr(start, end_delim);
        
        if (!end) break;
        
        int length = end - start;
        char extracted[256];
        strncpy(extracted, start, length);
        extracted[length] = '\0';
        
        printf("Extracted: %s\n", extracted);
        
        start = end + strlen(end_delim);
    }
    
    return 0;
}

此代码提取方括号之间的文本。它首先找到开始分隔符,然后查找结束分隔符。计算它们之间的长度并将子字符串复制到缓冲区。此模式对于解析结构化文本很有用。请务必确保您的缓冲区足够大以容纳提取的内容。

安全字符串搜索注意事项

此示例演示了带长度检查的安全字符串搜索。

safe_search.c
#include <stdio.h>
#include <string.h>

char* safe_strstr(const char *haystack, size_t haystack_len,
                 const char *needle, size_t needle_len) {
    if (!haystack || !needle || needle_len == 0 || haystack_len < needle_len) {
        return NULL;
    }
    
    for (size_t i = 0; i <= haystack_len - needle_len; i++) {
        if (strncmp(haystack + i, needle, needle_len) == 0) {
            return (char*)(haystack + i);
        }
    }
    
    return NULL;
}

int main() {
    char buffer[256] = "Safe string handling is important";
    char search[] = "string";
    
    char *result = safe_strstr(buffer, sizeof(buffer), 
                             search, strlen(search));
    
    if (result) {
        printf("Found '%s' at position: %ld\n", search, result - buffer);
    } else {
        printf("'%s' not found\n", search);
    }
    
    return 0;
}

这实现了 strstr 的更安全版本,其中包含长度检查。通过了解最大长度,它可以防止潜在的缓冲区溢出。当输入无效或要查找的字符串长于文本字符串时,该函数返回 NULL。对于安全关键应用程序,这种边界检查至关重要。这种方法比标准的 strstr 更健壮。

使用 strstr 的最佳实践

来源

C strstr 文档

本教程从基本用法到高级注意事项,探讨了 strstr 函数。尽管它功能强大,但请始终小心使用字符串操作,以防止程序中的安全漏洞和未定义行为。

作者

我叫 Jan Bodnar,是一名敬业的程序员,对编码充满热情。自 2007 年以来,我通过 1,400 多篇文章和 8 本电子书分享了我的专业知识。凭借十多年的教学经验,我努力让编程变得易于访问且引人入胜。

列表 C 标准库