目录

    • 方法一:使用计数器循环遍历
    • 方法二:使用指针算术
    • 方法三:递归
      • 重要注意事项
    • 更高效的写法 (方法二的变种)
    • 总结

在不使用标准库函数 “strlen” 的情况下,C++ 中计算字符串长度(特指 C 风格字符串)的核心方法是遍历字符数组,直到遇到字符串结束符 “’\0’”。C 风格字符串以空字符 “’\0’” 作为结束标志,其长度不包括这个结束符。

方法一:使用计数器循环遍历

这是最直观的方法。初始化一个计数器为 0,然后从字符串的第一个字符开始,逐个检查字符是否为 “’\0’”,如果不是,计数器加一并继续检查下一个字符,直到遇到 “’\0’” 为止。

#include <iostream>

int stringLength(const char* str) {
    int count = 0; // 初始化长度计数器
    while (str[count] != '\0') { // 检查当前字符是否为字符串结束符
        count++;
    }
    return count; // 返回计数结果
}

int main() {
    const char* myString = "Hello, World!";
    int len = stringLength(myString);
    std::cout << "The length of the string is: " << len << std::endl; // 输出 13
    return 0;
}

方法二:使用指针算术

这种方法利用指针的移动和算术运算。使用一个指针 “start” 记录字符串的起始地址,然后让另一个指针 “ptr” 从头开始向后移动,直到指向 “’\0’”。字符串的长度就是 “ptr” 和 “start” 之间的差值。

#include <iostream>

int stringLength(const char* str) {
    const char* start = str; // 保存字符串的起始地址
    while (*str != '\0') { // 检查当前指针所指的字符是否为结束符
        str++; // 指针移动到下一个字符
    }
    return str - start; // 指针相减得到字符个数,即长度
}

int main() {
    const char* myString = "Hello, C++!";
    int len = stringLength(myString);
    std::cout << "The length of the string is: " << len << std::endl; // 输出 11
    return 0;
}

方法三:递归

递归方法通过将大问题分解为小问题来求解。如果当前字符不是 “’\0’”,那么字符串的长度就是 “1” 加上 “从下一个字符开始的子串的长度”。

#include <iostream>

int stringLength(const char* str) {
    if (*str == '\0') { // 基准情况:如果当前字符是结束符
        return 0;
    } else {
        return 1 + stringLength(str + 1); // 递归计算剩余子串的长度并加1
    }
}

int main() {
    const char* myString = "Recursion";
    int len = stringLength(myString);
    std::cout << "The length of the string is: " << len << std::endl; // 输出 9
    return 0;
}

注意:递归写法代码简洁,但递归调用会有函数调用开销,对于非常长的字符串可能导致栈溢出,性能通常不如循环。

重要注意事项

  • 空指针检查:在实际代码中,如果传入的字符指针可能是
    “nullptr”,应在函数开始处进行检查,以避免解引用空指针导致未定义行为(如程序崩溃)。
int stringLength(const char* str) {
    if (str == nullptr) { // 检查空指针
        return 0;
    }
    int count = 0;
    while (str[count] != '\0') {
        count++;
    }
    return count;
}
  • 确保字符串以 ‘\0’ 结尾:这些方法都依赖于字符串以空字符 “’\0’” 正确终止。如果传入的字符数组没有以 “’\0’” 结尾,函数将会一直遍历下去,导致缓冲区溢出,访问未分配的内存,产生不可预知的结果(如崩溃、错误数据)。

更高效的写法 (方法二的变种)

方法二的逻辑可以写得更加简洁:

int stringLength(const char* str) {
    const char* ptr = str;
    while (*ptr) { // '\0' 的 ASCII 值为 0, while(*ptr != '\0') 等价于 while(*ptr)
        ptr++;
    }
    return ptr - str;
}

总结

方法 优点 缺点 适用场景
计数器循环 直观易懂,效率高 需要维护一个计数器变量 一般场景,最常用
指针算术 代码相对简洁,效率高 需要理解指针运算 追求代码简洁和效率的场景
递归 代码形式简洁,不创建局部变量计数器 递归开销大,可能栈溢出,性能较差 对代码简洁性有要求且字符串长度可控的场景

这些方法本质上都是遍历字符串直到遇到空字符
“’\0’”,时间复杂度都是 O(n),其中 n 是字符串的长度。

对于 C++ “std::string” 对象,不应使用上述方法。直接使用其 “length()” 或 “size()” 成员函数即可,它们能在常数时间 O(1) 内返回结果,且更安全。

#include <iostream>
#include <string>

int main() {
    std::string str = "Hello, World!";
    std::cout << "The length of the string is: " << str.length() << std::endl; // 或者 str.size()
    return 0;
}

希望这些解释和示例能帮助你理解如何在不使用
“strlen” 的情况下计算 C 风格字符串的长度。

更多推荐