在C语言中,并没有一个名为 strrstr 的标准库函数,我们可以根据它的命名和常见用法来推断它的功能。

(图片来源网络,侵删)
strrstr 这个名字可以理解为 "string reverse string" 或 "string right string",它的功能通常是:在一个字符串(haystack)中,从后向前查找,最后一次出现另一个字符串(needle)的位置。
这与标准库中的 strstr 函数形成对比:
strstr(haystack, needle): 从haystack的开头开始,查找needle第一次出现的位置。strrstr(haystack, needle): 从haystack的末尾开始,查找needle最后一次出现的位置。
如何实现 strrstr 函数?
由于C标准库中没有这个函数,我们需要自己实现,实现 strrstr 最直接的方法是:
- 使用
strstr在一个循环中不断查找子字符串。 - 每次找到子字符串后,记录下它的起始位置。
- 然后从该位置的下一个字符继续查找,直到
strstr返回NULL(表示再也找不到子字符串了)。 - 最后返回记录下的最后一个位置。
下面是一个完整的实现示例:

(图片来源网络,侵删)
循环调用 strstr
这种方法最直观,易于理解。
#include <stdio.h>
#include <string.h>
/**
* @brief 在字符串中查找子字符串最后一次出现的位置
*
* @param haystack 被搜索的字符串
* @param needle 要查找的子字符串
* @return char* 返回一个指向 haystack 中 needle 最后一次出现的起始位置的指针。
* 如果未找到 needle,则返回 NULL。
*/
char* my_strrstr(const char* haystack, const char* needle) {
// 1. 处理边界情况:needle 是空字符串
// 根据标准 strstr 的行为,needle 是空字符串,返回 haystack
if (*needle == '\0') {
return (char*)haystack;
}
char* last_found = NULL;
char* current_pos = (char*)haystack;
// 2. 循环查找,直到再也找不到 needle
while ((current_pos = strstr(current_pos, needle)) != NULL) {
// 3. 记录本次找到的位置
last_found = current_pos;
// 4. 从找到位置的下一个字符继续查找
current_pos++;
}
// 5. 返回最后一次找到的位置,如果从未找到则为 NULL
return last_found;
}
int main() {
const char* text = "this is a test string, this is only a test.";
const char* word1 = "test";
const char* word2 = "is";
const char* word3 = "nonexistent";
const char* empty_str = "";
// 测试1: 查找 "test"
char* result1 = my_strrstr(text, word1);
if (result1) {
printf("'%s' 的最后一次出现位置: %ld\n", word1, result1 - text);
// 输出: "test" 的最后一次出现位置: 31
} else {
printf("未找到 '%s'\n", word1);
}
// 测试2: 查找 "is"
char* result2 = my_strrstr(text, word2);
if (result2) {
printf("'%s' 的最后一次出现位置: %ld\n", word2, result2 - text);
// 输出: "is" 的最后一次出现位置: 23
} else {
printf("未找到 '%s'\n", word2);
}
// 测试3: 查找不存在的字符串
char* result3 = my_strrstr(text, word3);
if (result3) {
printf("'%s' 的最后一次出现位置: %ld\n", word3, result3 - text);
} else {
printf("未找到 '%s'\n", word3); // 输出: 未找到 'nonexistent'
}
// 测试4: 查找空字符串
char* result4 = my_strrstr(text, empty_str);
if (result4) {
printf("空字符串的查找结果: %ld\n", result4 - text); // 应该是 0
} else {
printf("未找到空字符串\n");
}
return 0;
}
手动实现(不依赖 strstr)
如果你想在不使用 strstr 的情况下实现 strrstr,可以手动遍历字符串进行比较。
#include <stdio.h>
/**
* @brief 手动实现 strrstr
*
* @param haystack 被搜索的字符串
* @param needle 要查找的子字符串
* @return char* 返回一个指向 haystack 中 needle 最后一次出现的起始位置的指针,否则返回 NULL。
*/
char* my_strrstr_manual(const char* haystack, const char* needle) {
if (*needle == '\0') {
return (char*)haystack;
}
const char* h_ptr = haystack;
const char* last_found = NULL;
int needle_len = 0;
// 计算 needle 的长度
while (needle[needle_len] != '\0') {
needle_len++;
}
// 外层循环遍历 haystack
while (*h_ptr != '\0') {
const char* h_temp = h_ptr;
const char* n_temp = needle;
int match = 1;
// 内层循环比较字符
while (*n_temp != '\0') {
if (*h_temp != *n_temp) {
match = 0;
break;
}
h_temp++;
n_temp++;
}
// 如果匹配成功
if (match) {
last_found = h_ptr;
// 跳过已匹配的部分,继续向后查找
h_ptr += needle_len;
} else {
// 如果不匹配,只前进一个字符
h_ptr++;
}
}
return (char*)last_found;
}
int main() {
const char* text = "this is a test string, this is only a test.";
const char* word = "test";
char* result = my_strrstr_manual(text, word);
if (result) {
printf("手动实现的 '%s' 最后一次出现位置: %ld\n", word, result - text);
} else {
printf("未找到 '%s'\n", word);
}
return 0;
}
| 特性 | strstr |
strrstr (自定义) |
|---|---|---|
| 功能 | 查找子字符串第一次出现的位置 | 查找子字符串最后一次出现的位置 |
| 标准库 | 是 (<string.h>) |
否,需要自己实现 |
| 实现思路 | 从头开始线性查找 | 循环调用 strstr 或手动从后向前/从前向后查找 |
| 常见用途 | 解析配置文件、URL、日志等,查找特定标记 | 获取文件扩展名(查找最后一个 )、从路径中提取文件名等 |
对于大多数情况,方法一(循环调用 strstr) 是最佳选择,因为它代码简洁、可读性高,并且复用了标准库已经高度优化的代码。
