C语言-重构string.c系统库函数(3)

简介: 这是重写C语言string.c的部分函数的第3篇文章,前面2篇文章已经重写了部分函数,这篇文章介绍剩下的几个常用函数重写方法。

一、函数介绍

这是重写C语言string.c的部分函数的第3篇文章,前面2篇文章已经重写了下面几个函数:

strdup  字符串拷贝
strchr  字符查找函数 (从头开始)
strrchr 字符查找函数(从尾开始)
strcat strncat  字符串拼接函数
memset 内存初始化函数 (可用于赋初值)
strcmp  字符串比较
strlen  计算字符串长度
strstr  字符串查找
memcmp  内存比较
strcpy  字符串拷贝
memcpy  内存拷贝

这篇文章继续重新的函数如下:

strspn  字符查找 (详细介绍看重写的源码介绍和示例代码)
strpbrk 字符查找函数(查找第一个匹配的字符)
strtok、strsep  字符串分隔---字符串处理中非常常用
bcopy   内存拷贝 与memcpy() 功能相同
memscan、memchr 在内存区域中查找字符

二、重写函数源码

2.1 strspn字符查找

strspn 从参数s字符串的开头查找计算连续的字符,这些字符都是accept字符串中包含的字符。

size_t strspn(const char *s, const char *accept)
{
    const char *p;
    const char *a;
    size_t count = 0;

    for (p = s; *p != '\0'; ++p) {
        for (a = accept; *a != '\0'; ++a) {
            if (*p == *a)
                break;
        }
        if (*a == '\0')
            return count;
        ++count;
    }

    return count;
}

示例:
#include <stdio.h>
#include <string.h>
int main()
{
    int i;
    char str[] = "123";
    char accept[] = "1111123hhhhh123hhhhh123hhhhh123hhhh";
    i = strspn(str, accept);
    printf("查找的结果: %d\n", i);
    return 0;
}

2.2 strpbrk字符查找函数(顺序遍历)

strpbrk函数是在源字符串cs中查找最先含有搜索字符串ct中任一字符的位置并返回,如果找不到就返回空指针NULL。
比如: 查找的源字符串是 abcd
要查找的字符串还是78c,那么查找的结果返回就是c。 因为查找的字符串里c在源字符串里匹配。

char * strpbrk(const char * cs,const char * ct)
{
    const char *sc1,*sc2;

    for( sc1 = cs; *sc1 != '\0'; ++sc1) {
        for( sc2 = ct; *sc2 != '\0'; ++sc2) {
            if (*sc1 == *sc2)
                return (char *) sc1;
        }
    }
    return NULL;
}

示例:
#include <stdio.h>
#include <string.h>
int main()
{
    const char str1[] = "1234567890abcdefg";
    const char str2[] = "Mbc";
    const char *find_str =NULL;

    find_str = strpbrk(str1, str2);
    if (find_str)
    {
        printf("第一个匹配的字符是: %c\n", *find_str); //b
    }
    else
    {
        printf("未查找到字符");
    }
    return 0;
}

2.3 strtok 字符串分隔

strtok函数 用于字符串的分隔,可以根据特定的字符串、字符分隔字符串,字符串处理比较常用。

strtok函数第一次调用时会把ct字符串中所有在s中出现的字符替换为NULL。然后通过依次调用strtok(NULL, ct)得到各部分子串,详细使用方法看下面的示例代码。

/**
*strtok-将字符串拆分为标记
*/
char * ___strtok;
char * strtok(char * s,const char * ct)
{
    char *sbegin, *send;

    sbegin  = s ? s : ___strtok;
    if (!sbegin) {
        return NULL;
    }
    sbegin += strspn(sbegin,ct);
    if (*sbegin == '\0') {
        ___strtok = NULL;
        return( NULL );
    }
    send = strpbrk( sbegin, ct);
    if (send && *send != '\0')
        *send++ = '\0';
    ___strtok = send;
    return (sbegin);
}


示例代码:
#include <stdio.h>
#include <string.h>
int main()
{
    char str1[] = "123-456-789-abc";
    const char str2[] = "-";
    char *find_str =NULL;

    find_str = strtok(str1, str2);
    if (find_str)
    {
        printf("分隔的字符串: %s\n", find_str);
        while (1)
        {
            find_str = strtok(NULL, str2);
            if (find_str)
            {
                printf("分隔的字符串: %s\n", find_str);
            }
            else
            {
                break;
            }
        }
    }
    return 0;
}

/*
分隔的字符串: 123
分隔的字符串: 456
分隔的字符串: 789
分隔的字符串: abc
* */

strtok的升级版本是strsep函数。

char * strsep(char **s, const char *ct)
{
    char *sbegin = *s, *end;

    if (sbegin == NULL)
        return NULL;

    end = strpbrk(sbegin, ct);
    if (end)
        *end++ = '\0';
    *s = end;

    return sbegin;
}

2.4 bcopy 内存拷贝函数

bcopy 与memcpy 功能一样,但是不检查NULL结尾。

/**
*bcopy-将内存的一个区域复制到另一个区域
*@src:从何处复制
*@dest:复制到哪里
*@count:该区域的大小。
bcopy() 和 memcpy() 功能相同,用来复制内存块的前 n 个字节
需要注意的是 bcopy 与memcpy()相同,参数相反。
*/
char * bcopy(const char * src, char * dest, int count)
{
    char *tmp = dest;

    while (count--)
        *tmp++ = *src++;

    return dest;
}

2.5 memscan 在内存区域中查找字符

memscan 用于在内存区域中查找字符,addr是查找的内存首地址,c是查找的字符,size查找的区域范围.

如果查找成功就返回该字符在内存里的地址,如果没有查找到就返回查找的内存的首地址。

void * memscan(void * addr, int c, size_t size)
{
    unsigned char * p = (unsigned char *) addr;

    while (size) {
        if (*p == c)
            return (void *) p;
        p++;
        size--;
    }
    return (void *) p;
}

memchr功能:

从s所指内存区域的前n个字节查找字符c,当第一次遇到字符c时停止查找,如果成功,返回指向字符c的指针;否则返回NULL。

void *memchr(const void *s, int c, size_t n)
{
    const unsigned char *p = s;
    while (n-- != 0) {
        if ((unsigned char)c == *p++) {
            return (void *)(p-1);
        }
    }
    return NULL;
}
目录
相关文章
|
11天前
|
存储 算法 C语言
【C语言程序设计——函数】素数判定(头歌实践教学平台习题)【合集】
本内容介绍了编写一个判断素数的子函数的任务,涵盖循环控制与跳转语句、算术运算符(%)、以及素数的概念。任务要求在主函数中输入整数并输出是否为素数的信息。相关知识包括 `for` 和 `while` 循环、`break` 和 `continue` 语句、取余运算符 `%` 的使用及素数定义、分布规律和应用场景。编程要求根据提示补充代码,测试说明提供了输入输出示例,最后给出通关代码和测试结果。 任务核心:编写判断素数的子函数并在主函数中调用,涉及循环结构和条件判断。
49 23
|
11天前
|
算法 C语言
【C语言程序设计——函数】利用函数求解最大公约数和最小公倍数(头歌实践教学平台习题)【合集】
本文档介绍了如何编写两个子函数,分别求任意两个整数的最大公约数和最小公倍数。内容涵盖循环控制与跳转语句的使用、最大公约数的求法(包括辗转相除法和更相减损术),以及基于最大公约数求最小公倍数的方法。通过示例代码和测试说明,帮助读者理解和实现相关算法。最终提供了完整的通关代码及测试结果,确保编程任务的成功完成。
43 15
|
1月前
|
IDE 编译器 开发工具
【C语言】全面系统讲解 `#pragma` 指令:从基本用法到高级应用
在本文中,我们系统地讲解了常见的 `#pragma` 指令,包括其基本用法、编译器支持情况、示例代码以及与传统方法的对比。`#pragma` 指令是一个强大的工具,可以帮助开发者精细控制编译器的行为,优化代码性能,避免错误,并确保跨平台兼容性。然而,使用这些指令时需要特别注意编译器的支持情况,因为并非所有的 `#pragma` 指令都能在所有编译器中得到支持。
120 41
【C语言】全面系统讲解 `#pragma` 指令:从基本用法到高级应用
|
11天前
|
C语言
【C语言程序设计——函数】亲密数判定(头歌实践教学平台习题)【合集】
本文介绍了通过编程实现打印3000以内的全部亲密数的任务。主要内容包括: 1. **任务描述**:实现函数打印3000以内的全部亲密数。 2. **相关知识**: - 循环控制和跳转语句(for、while循环,break、continue语句)的使用。 - 亲密数的概念及历史背景。 - 判断亲密数的方法:计算数A的因子和存于B,再计算B的因子和存于sum,最后比较sum与A是否相等。 3. **编程要求**:根据提示在指定区域内补充代码。 4. **测试说明**:平台对代码进行测试,预期输出如220和284是一组亲密数。 5. **通关代码**:提供了完整的C语言代码实现
50 24
|
7天前
|
存储 C语言
【C语言程序设计——函数】递归求斐波那契数列的前n项(头歌实践教学平台习题)【合集】
本关任务是编写递归函数求斐波那契数列的前n项。主要内容包括: 1. **递归的概念**:递归是一种函数直接或间接调用自身的编程技巧,通过“俄罗斯套娃”的方式解决问题。 2. **边界条件的确定**:边界条件是递归停止的条件,确保递归不会无限进行。例如,计算阶乘时,当n为0或1时返回1。 3. **循环控制与跳转语句**:介绍`for`、`while`循环及`break`、`continue`语句的使用方法。 编程要求是在右侧编辑器Begin--End之间补充代码,测试输入分别为3和5,预期输出为斐波那契数列的前几项。通关代码已给出,需确保正确实现递归逻辑并处理好边界条件,以避免栈溢出或结果
46 16
|
6天前
|
存储 编译器 C语言
【C语言程序设计——函数】分数数列求和2(头歌实践教学平台习题)【合集】
函数首部:按照 C 语言语法,函数的定义首部表明这是一个自定义函数,函数名为fun,它接收一个整型参数n,用于指定要求阶乘的那个数,并且函数的返回值类型为float(在实际中如果阶乘结果数值较大,用float可能会有精度损失,也可以考虑使用double等更合适的数据类型,这里以float为例)。例如:// 函数体代码将放在这里函数体内部变量定义:在函数体中,首先需要定义一些变量来辅助完成阶乘的计算。比如需要定义一个变量(通常为float或double类型,这里假设用float。
18 3
|
6天前
|
存储 算法 安全
【C语言程序设计——函数】分数数列求和1(头歌实践教学平台习题)【合集】
if 语句是最基础的形式,当条件为真时执行其内部的语句块;switch 语句则适用于针对一个表达式的多个固定值进行判断,根据表达式的值与各个 case 后的常量值匹配情况,执行相应 case 分支下的语句,直到遇到 break 语句跳出 switch 结构,若没有匹配值则执行 default 分支(可选)。例如,在判断一个数是否大于 10 的场景中,条件表达式为 “num> 10”,这里的 “num” 是程序中的变量,通过比较其值与 10 的大小关系来确定条件的真假。常量的值必须是唯一的,且在同一个。
11 2
|
10天前
|
存储 编译器 C语言
【C语言程序设计——函数】回文数判定(头歌实践教学平台习题)【合集】
算术运算于 C 语言仿若精密 “齿轮组”,驱动着数值处理流程。编写函数求区间[100,500]中所有的回文数,要求每行打印10个数。根据提示在右侧编辑器Begin--End之间的区域内补充必要的代码。如果操作数是浮点数,在 C 语言中是不允许直接进行。的结果是 -1,因为 -7 除以 3 商为 -2,余数为 -1;注意:每一个数据输出格式为 printf("%4d", i);的结果是 1,因为 7 除以 -3 商为 -2,余数为 1。取余运算要求两个操作数必须是整数类型,包括。开始你的任务吧,祝你成功!
41 1
|
1月前
|
存储 编译器 C语言
【C语言】C语言的变量和声明系统性讲解
在C语言中,声明和定义是两个关键概念,分别用于告知编译器变量或函数的存在(声明)和实际创建及分配内存(定义)。声明可以多次出现,而定义只能有一次。声明通常位于头文件中,定义则在源文件中。通过合理组织头文件和源文件,可以提高代码的模块化和可维护性。示例包括全局变量、局部变量、函数、结构体、联合体、数组、字符串、枚举和指针的声明与定义。
58 12
|
1月前
|
存储 程序员 C语言
【C语言】文件操作函数详解
C语言提供了一组标准库函数来处理文件操作,这些函数定义在 `<stdio.h>` 头文件中。文件操作包括文件的打开、读写、关闭以及文件属性的查询等。以下是常用文件操作函数的详细讲解,包括函数原型、参数说明、返回值说明、示例代码和表格汇总。
62 9

热门文章

最新文章