strcount函数如何实现字符串字符计数?

99ANYc3cd6
预计阅读时长 22 分钟
位置: 首页 C语言 正文

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

c语言strcount
(图片来源网络,侵删)
  1. 统计一个字符在字符串中出现的次数,这是最常见的理解。
  2. 统计一个子字符串在字符串中出现的次数

下面,我将分别对这两种实现方式进行详细说明,并提供完整的代码示例。


统计单个字符的出现次数

这是最简单、最直接的 strcount 实现,它的功能是:在一个字符串中查找某个特定字符,并返回它出现的总次数。

实现思路

  1. 函数签名:函数需要接收两个参数:源字符串 str 和要查找的字符 c,返回值类型应为 int,用于表示计数值。
  2. 初始化计数器:创建一个整型变量(如 count),并将其初始化为 0。
  3. 遍历字符串:使用一个循环(通常是 for 循环)来遍历源字符串 str 的每一个字符,直到遇到字符串结束符 \0
  4. 比较字符:在循环的每一步,使用 if 语句判断当前字符是否等于目标字符 c
  5. 增加计数:如果字符匹配,就将计数器 count 的值加 1。
  6. 返回结果:循环结束后,返回计数器 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 语言中遍历数组和字符串的常用技巧。

统计子字符串的出现次数

这个功能稍微复杂一些,它需要在一个字符串中查找另一个(可能较长的)字符串,并返回其出现的次数。

实现思路

  1. 函数签名:函数需要接收两个参数:源字符串 haystack(草垛,我们要在其中查找)和子字符串 needle(针,我们要查找的目标),返回值类型为 int
  2. 处理特殊情况:如果子字符串 needle 是空字符串 ,它的出现次数可以认为是无限的或未定义的,我们约定返回 0 或者进行特殊处理,这里我们按返回 0 处理。
  3. 外层循环:遍历 haystack 的每一个可能作为子字符串起始点的位置。
  4. 内层循环:对于 haystack 的每一个起始点,尝试将 needle 的每个字符与 haystack 中对应位置的字符进行逐一比较。
  5. 匹配成功:如果在内层循环中,needle 的所有字符都匹配成功,说明找到了一个完整的子字符串,计数器加 1,并跳过已经匹配的部分,继续查找下一个可能的匹配。
  6. 匹配失败:如果在内层循环中,有任何字符不匹配,说明当前起始点不是有效匹配,立即中断内层循环,继续从 haystack 的下一个位置开始查找。
  7. 返回结果:当遍历完整个 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 剩余的长度已经不足以容纳 needlehaystack 长为 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 来简化代码,并且通常效率更高(因为标准库的实现可能经过高度优化)。

c语言strcount
(图片来源网络,侵删)

实现思路

  1. 初始化计数器 count 和一个指针 pospos 初始指向 haystack 的开头。
  2. 在一个循环中,调用 strstr(pos, needle) 来查找 needle
  3. strstr 返回 NULL,说明从 pos 开始再也找不到 needle 了,循环结束。
  4. 如果找到了,将 count 加 1,然后将 pos 更新为找到的位置的下一个字符,即 pos = found_pos + 1,以便继续查找后续的匹配(包括重叠的匹配)。
  5. 循环结束后返回 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 的实现方式,因为它更简洁、更可靠,并且性能通常更好,而统计单个字符则完全可以自己实现一个简单的循环函数。

c语言strcount
(图片来源网络,侵删)
-- 展开阅读全文 --
头像
C语言isalnum函数如何判断字母数字?
« 上一篇 04-13
C语言instance是什么?实例与对象有何区别?
下一篇 » 04-14

相关文章

取消
微信二维码
支付宝二维码

目录[+]