strcount 这个名称并不是 C 标准库中自带的函数,它更像是一个自定义函数的名称,通常用于实现以下两种常见的功能之一:

(图片来源网络,侵删)
- 统计一个字符在字符串中出现的次数,这是最常见的理解。
- 统计一个子字符串在字符串中出现的次数。
下面,我将分别对这两种实现方式进行详细说明,并提供完整的代码示例。
统计单个字符的出现次数
这是最简单、最直接的 strcount 实现,它的功能是:在一个字符串中查找某个特定字符,并返回它出现的总次数。
实现思路
- 函数签名:函数需要接收两个参数:源字符串
str和要查找的字符c,返回值类型应为int,用于表示计数值。 - 初始化计数器:创建一个整型变量(如
count),并将其初始化为 0。 - 遍历字符串:使用一个循环(通常是
for循环)来遍历源字符串str的每一个字符,直到遇到字符串结束符\0。 - 比较字符:在循环的每一步,使用
if语句判断当前字符是否等于目标字符c。 - 增加计数:如果字符匹配,就将计数器
count的值加 1。 - 返回结果:循环结束后,返回计数器
count的最终值。
代码实现
#include <stdio.h>
/**
* @brief 统计字符 c 在字符串 str 中出现的次数
* @param str 要搜索的字符串
* @param c 要查找的字符
* @return 字符 c 在 str 中出现的次数
*/
int strcount(const char *str, char c) {
int count = 0;
// 使用指针遍历字符串,直到遇到空字符 '\0'
while (*str != '\0') {
if (*str == c) {
count++;
}
str++; // 移动到下一个字符
}
return count;
}
int main() {
char my_string[] = "Hello, World! This is a test string.";
char char_to_find = 'l';
char char_to_find2 = 'i';
int occurrences = strcount(my_string, char_to_find);
int occurrences2 = strcount(my_string, char_to_find2);
printf("字符串: \"%s\"\n", my_string);
printf("字符 '%c' 出现了 %d 次,\n", char_to_find, occurrences); // 应该输出 3
printf("字符 '%c' 出现了 %d 次,\n", char_to_find2, occurrences2); // 应该输出 4
return 0;
}
代码解释
const char *str:使用const是一个好习惯,因为它表明函数不会修改传入的字符串内容,这既是安全性的保证,也是对调用者的承诺。while (*str != '\0'):这是遍历字符串的标准方式。*str解引用指针会得到当前指针指向的字符,当这个字符是字符串结束符\0时,循环终止。if (*str == c):比较当前字符和目标字符是否相同。str++:指针自增,使其指向字符串的下一个字符,这是 C 语言中遍历数组和字符串的常用技巧。
统计子字符串的出现次数
这个功能稍微复杂一些,它需要在一个字符串中查找另一个(可能较长的)字符串,并返回其出现的次数。
实现思路
- 函数签名:函数需要接收两个参数:源字符串
haystack(草垛,我们要在其中查找)和子字符串needle(针,我们要查找的目标),返回值类型为int。 - 处理特殊情况:如果子字符串
needle是空字符串 ,它的出现次数可以认为是无限的或未定义的,我们约定返回 0 或者进行特殊处理,这里我们按返回 0 处理。 - 外层循环:遍历
haystack的每一个可能作为子字符串起始点的位置。 - 内层循环:对于
haystack的每一个起始点,尝试将needle的每个字符与haystack中对应位置的字符进行逐一比较。 - 匹配成功:如果在内层循环中,
needle的所有字符都匹配成功,说明找到了一个完整的子字符串,计数器加 1,并跳过已经匹配的部分,继续查找下一个可能的匹配。 - 匹配失败:如果在内层循环中,有任何字符不匹配,说明当前起始点不是有效匹配,立即中断内层循环,继续从
haystack的下一个位置开始查找。 - 返回结果:当遍历完整个
haystack后,返回最终的计数。
代码实现
#include <stdio.h>
#include <string.h> // 为了使用 strlen()
/**
* @brief 统计子字符串 needle 在字符串 haystack 中出现的次数
* @param haystack 要搜索的字符串
* @param needle 要查找的子字符串
* @return 子字符串 needle 在 haystack 中出现的次数
*/
int strcount(const char *haystack, const char *needle) {
int count = 0;
int haystack_len = strlen(haystack);
int needle_len = strlen(needle);
// needle 是空字符串,直接返回 0
if (needle_len == 0) {
return 0;
}
// 遍历 haystack,直到剩余长度不足以匹配 needle
for (int i = 0; i <= haystack_len - needle_len; i++) {
int j;
// 检查从 haystack[i] 开始的子串是否与 needle 匹配
for (j = 0; j < needle_len; j++) {
if (haystack[i + j] != needle[j]) {
break; // 不匹配,跳出内层循环
}
}
// 如果内层循环正常结束(j == needle_len),说明匹配成功
if (j == needle_len) {
count++;
// 可以选择跳过已匹配部分,i += needle_len - 1;
// 但这里我们继续查找重叠的情况,"aaaa" 中 "aa" 出现 3 次
}
}
return count;
}
int main() {
char text[] = "abababababab";
char sub1[] = "aba";
char sub2[] = "bab";
char sub3[] = "xyz";
printf("字符串: \"%s\"\n", text);
printf("子串 \"%s\" 出现了 %d 次,\n", sub1, strcount(text, sub1)); // 应该输出 3
printf("子串 \"%s\" 出现了 %d 次,\n", sub2, strcount(text, sub2)); // 应该输出 3
printf("子串 \"%s\" 出现了 %d 次,\n", sub3, strcount(text, sub3)); // 应该输出 0
return 0;
}
代码解释
strlen():需要包含<string.h>头文件,用于获取字符串长度。for (int i = 0; i <= haystack_len - needle_len; i++):外层循环的终止条件是i的值使得haystack剩余的长度已经不足以容纳needle。haystack长为 10,needle长为 3,那么当i为 8 时,haystack[8..10]只剩 3 个字符,这是最后一个可能的起始位置。i最大为10 - 3 = 7,所以循环条件是i <= 7。for (j = 0; j < needle_len; j++):内层循环逐个字符比较。if (j == needle_len):这个判断非常关键,只有当内层循环的for循环完整执行完毕(即没有因为break而中途退出),j的值才会等于needle_len,这代表needle的所有字符都成功匹配了。
更高效的实现(使用标准库 strstr)
对于统计子字符串,C 标准库提供了 strstr 函数,它可以在一个字符串中查找另一个字符串的第一次出现,我们可以利用 strstr 来简化代码,并且通常效率更高(因为标准库的实现可能经过高度优化)。

(图片来源网络,侵删)
实现思路
- 初始化计数器
count和一个指针pos,pos初始指向haystack的开头。 - 在一个循环中,调用
strstr(pos, needle)来查找needle。 strstr返回NULL,说明从pos开始再也找不到needle了,循环结束。- 如果找到了,将
count加 1,然后将pos更新为找到的位置的下一个字符,即pos = found_pos + 1,以便继续查找后续的匹配(包括重叠的匹配)。 - 循环结束后返回
count。
代码实现
#include <stdio.h>
#include <string.h>
/**
* @brief 使用 strstr 函数统计子字符串的出现次数
* @param haystack 要搜索的字符串
* @param needle 要查找的子字符串
* @return 子字符串 needle 在 haystack 中出现的次数
*/
int strcount_strstr(const char *haystack, const char *needle) {
int count = 0;
const char *pos = haystack;
if (strlen(needle) == 0) {
return 0;
}
while ((pos = strstr(pos, needle)) != NULL) {
count++;
// 将搜索位置移动到找到的位置的下一个字符,以查找重叠的匹配
pos++;
}
return count;
}
int main() {
char text[] = "abababababab";
char sub1[] = "aba";
char sub2[] = "bab";
printf("字符串: \"%s\"\n", text);
printf("子串 \"%s\" (使用 strstr) 出现了 %d 次,\n", sub1, strcount_strstr(text, sub1)); // 3
printf("子串 \"%s\" (使用 strstr) 出现了 %d 次,\n", sub2, strcount_strstr(text, sub2)); // 3
return 0;
}
| 功能 | 函数名 | 实现方式 | 优点 | 缺点 |
|---|---|---|---|---|
| 统计字符 | strcount |
while 循环遍历 |
简单、直观、高效 | 功能单一 |
| 统计子串 | strcount |
双重 for 循环 |
不依赖额外库,逻辑清晰 | 效率相对较低,代码复杂 |
| 统计子串 | strcount_strstr |
使用标准库 strstr |
代码简洁,效率高 | 依赖 <string.h> |
在实际开发中,如果你需要统计子字符串,强烈推荐使用 strstr 的实现方式,因为它更简洁、更可靠,并且性能通常更好,而统计单个字符则完全可以自己实现一个简单的循环函数。

(图片来源网络,侵删)
