C语言手记3

1.计算字符串的长度,不要用内置函数

如果你想手动计算一个字符串的长度(即字符数组中从开头到第一个 '\0' 的字节数),可以不使用 strlen,自己写一个循环。

基础实现(按字节)

c

复制代码
int my_strlen(const char* str) {
    int len = 0;
    while (str[len] != '\0') {
        len++;
    }
    return len;
}

使用示例

c

复制代码
#include <stdio.h>

int my_strlen(const char* str) {
    int len = 0;
    while (str[len] != '\0') {
        len++;
    }
    return len;
}

int main() {
    const char* s = "Hello, world!";
    int length = my_strlen(s);
    printf("Length: %d\n", length);  // 输出 13
    return 0;
}

const 是 C 语言的关键字,表示"常量"或"只读"。用在指针声明中,如 const char* src,表示指针 src 指向的字符数据是不可修改 的(即通过 src 不能改变字符串的内容)。这样做有两个作用:

  1. 保护数据:防止函数内部意外修改源字符串。

  2. 提高代码安全性:让调用者知道该函数不会改变传入的字符串。

说明

  • 函数参数 const char* str 指向字符串。

  • 循环条件 str[len] != '\0' 判断当前字符是否为结束符。

  • 每次循环 len++ 计数,直到遇到 '\0' 为止。

  • 返回的 len 即为字符串的字节长度(不包括结尾的 '\0')。

如果字符串中包含多字节字符(如中文),这个函数返回的是字节数 ,而不是字符数。如果你需要统计实际的字符个数(而非字节数),则需要根据编码规则(如 UTF-8)逐个解析字符,但通常简单的 strlen 替代品只需统计字节数即可。

如果你不希望使用任何标准库函数,以上实现完全依赖指针运算和循环,满足要求。


2.C语言字符串的拼接,不要用内置函数

在 C 语言中,实现字符串拼接(连接)且不使用任何标准库函数(如 strlenstrcatstrcpy 等),需要手动定位目标字符串的结尾,然后将源字符串的字符逐个复制过去。

以下是一个完整的示例,包含详细注释:

c

复制代码
#include <stdio.h>  // 仅用于输出,拼接过程未使用任何库函数

// 自定义拼接函数:将 src 拼接到 dest 的末尾
// 注意:dest 必须拥有足够的空间容纳拼接后的字符串(包括 '\0')
void my_strcat(char *dest, const char *src) {
    // 1. 移动 dest 指针到其末尾(即 '\0' 的位置)
    while (*dest != '\0') {
        dest++;   // 逐个字符前进,直到遇到空字符
    }

    // 2. 将 src 中的字符逐个复制到 dest 的末尾
    while (*src != '\0') {
        *dest = *src;   // 复制当前字符
        dest++;         // 目标指针后移
        src++;          // 源指针后移
    }

    // 3. 在新字符串末尾添加结束符 '\0'
    *dest = '\0';
}

int main() {
    char buffer[50] = "Hello, ";   // 预留足够空间
    const char *suffix = "world!";

    my_strcat(buffer, suffix);
    printf("拼接结果:%s\n", buffer);   // 输出:Hello, world!
    
    return 0;
}

关键点说明

  1. 查找末尾 :通过循环 while (*dest != '\0') dest++; 找到目标字符串的结束位置,此时 dest 指向 '\0'

  2. 字符复制:然后循环复制源字符串的每个非空字符,同时移动两个指针。

  3. 添加结束符 :复制完成后,手动在目标字符串末尾添加 '\0',确保其符合 C 字符串规范。

  4. 安全性 :调用者必须确保 dest 指向的数组有足够空间容纳原有内容加上 src 的内容及末尾的 '\0'。若空间不足,会导致缓冲区溢出。

    #include<stdio.h>
    void my_strcat(char* dest,const char* src){
    while(*dest!='\0'){
    dest++;
    }
    while(*src!='\0'){
    *dest=*src;
    dest++;
    src++;
    }
    *dest='\0';

    }

    int main(){
    char arr[50]="hello";
    char* str="miaomiao";
    my_strcat(arr,str);
    printf("%s\n",arr);
    return 0;
    }


3.C语言字符串的查找,不要用内置函数

在 C 语言中实现字符串查找(例如查找子串第一次出现的位置),不使用任何标准库函数(如 strstr、strlen 等),需要手动遍历主串和子串进行匹配。下面提供一个朴素的实现方式,返回子串在主串中第一次出现的指针,若未找到则返回 NULL。c

复制代码
#include <stdio.h>   // 仅用于输出演示,查找过程未使用库函数

// 自定义查找函数:在 haystack 中查找 needle 第一次出现的位置
// 返回指向 haystack 中 needle 首字符的指针,如果未找到则返回 NULL
char* my_strstr(const char *haystack, const char *needle) {
    // 如果 needle 为空字符串,根据标准 strstr 行为返回 haystack
    if (*needle == '\0') {
        return (char*)haystack;
    }

    const char *h = haystack;   // 主串指针
    const char *n;              // 子串指针(内层循环用)

    // 外层循环:遍历主串的每个字符作为可能的起点
    while (*h != '\0') {
        // 检查从 h 开始的字符串是否与 needle 匹配
        n = needle;
        const char *start = h;   // 记录当前起点

        while (*n != '\0' && *start != '\0' && *start == *n) {
            start++;
            n++;
        }

        // 如果 n 已经到达子串末尾,说明完全匹配
        if (*n == '\0') {
            return (char*)h;   // 返回第一次出现的位置
        }

        // 否则,主串指针后移一个字符,继续检查
        h++;
    }

    // 未找到匹配
    return NULL;
}

int main() {
    char text[] = "Hello, world! Welcome to C programming.";
    char pattern[] = "world";

    char *result = my_strstr(text, pattern);
    if (result != NULL) {
        printf("找到子串 \"%s\",起始位置:%ld\n", pattern, result - text);
        printf("从该位置开始的剩余字符串:%s\n", result);
    } else {
        printf("未找到子串 \"%s\"\n", pattern);
    }

    return 0;
}

代码说明

边界处理:如果 needle 是空字符串,直接返回 haystack(模仿标准 strstr 行为)。

外层循环:用指针 h 遍历主串的每个字符,将其作为可能匹配的起点。

内层匹配:用指针 start 和 n 逐字符比较主串和子串,直到遇到不匹配或某一方结束。

匹配成功:如果内层循环结束后 n 指向了子串的结束符 '\0',说明完全匹配,返回当前的 h(起点)。

未匹配:若内层循环因不匹配而退出,则 h 后移一位继续尝试;若主串遍历完毕仍未找到,返回 NULL。

关键点

没有使用任何库函数(如 strlen、strcmp、strstr 等),仅用指针和循环完成。

时间复杂度为 O(n*m)(n 为主串长度,m 为子串长度),适用于一般场景。

如果需要更高性能,可考虑 KMP 等算法,但朴素方法清晰易懂,满足"不使用内置函数"的要求。

注意事项

函数返回的指针指向主串内部的某个位置,因此主串必须是可修改的(此处用 const char* 传入,但返回 char* 可能存在风险;若希望更安全,可以返回下标或使用非 const 版本)。实际使用时,若主串为常量字符串,不应通过返回的指针修改内容。

代码中使用了 printf 进行演示,这属于标准输入输出库,但查找逻辑本身不依赖任何字符串处理内置函数。

相关推荐
一杯美式 no sugar2 小时前
类和对象(中)
开发语言·c++
qq_416018722 小时前
实时数据可视化库
开发语言·c++·算法
2401_873204652 小时前
C++中的策略模式进阶
开发语言·c++·算法
HABuo2 小时前
【linux线程(一)】线程概念、线程控制详细剖析
linux·运维·服务器·c语言·c++·ubuntu·centos
xushichao19892 小时前
C++中的职责链模式实战
开发语言·c++·算法
清风徐来QCQ2 小时前
js中的模板字符串
开发语言·前端·javascript
2301_818419013 小时前
C++中的协程编程
开发语言·c++·算法
add45a3 小时前
C++中的工厂方法模式
开发语言·c++·算法
java1234_小锋3 小时前
Java高频面试题:Spring-AOP通知和执行顺序?
java·开发语言·spring