IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> string.h和stype.h常用函数讲解,隔壁老王看了直呼eazy!【C语言】 -> 正文阅读

[C++知识库]string.h和stype.h常用函数讲解,隔壁老王看了直呼eazy!【C语言】

📌 本文作者: Foxny

📃 更新记录: 2021.7.20

? 勘误记录:

📜 本文声明: 由于作者水平有限,本文有错误和不准确之处在所难免,本人也很想知道这些错误,恳望读者批评指正!


前言

📚 在C语言中对字符和字符串的处理是很常见的,但是C语言本身是并没有字符串类型的,字符串通常放在 常量字符串 中或 字符数组 中。字符串常量 适用于那些对它不做修改的字符串函数。


一、求字符串长度

0x00 strlen 函数

📜 头文件: string.h

🔍 链接:http://www.cplusplus.com/reference/cstring/strlen/?kw=strlen

📚 说明:字符串以 \0 作为结束标志,strlen 返回的是在字符串中 \0 前面出现的字符个数

📌 注意事项:

????? ① 参数指向的字符串必须以? \0? 结束

????? ② 函数的返回值为 size_t ,无符号(unsigned)

💬 代码演示:

#include <stdio.h>
#include <string.h>

int main()
{
    int len = strlen("abcdef");
    printf("%d\n", len);

    return 0;
}

🚩? 6

二、长度不受限制的字符串函数

0x00 strcpy 函数

📜 头文件: string.h

🔍 链接:http://www.cplusplus.com/reference/cstring/strcpy/

📚 说明:字符串拷贝,将含有 \0 的字符串复制到另一个地址空间,返回值的类型为 char*

📌 注意事项:

????? ① 源字符串 src 必须以 \0 结束

????? ② 会将源字符串 src 中的 \0 一同拷贝到目标空间 dest

????? ③ 目标空间必须足够大,以确保能够存放源字符串 dest (下面讲 strncmp 的时候演示)

????? ④ 目标空间必须可变,即目标空间 dest 不可以被 const 声明

💬 代码演示:

#include <stdio.h>
#include <string.h>

int main()
{
    char arr1[] = "abcdefghi";
    char arr2[] = "123";
    printf("拷贝前:%s\n", arr1);

    strcpy(arr1, arr2); // 字符串拷贝(目标空间,源字符串)

    printf("拷贝后:%s\n", arr1);

    return 0;
}

🚩 运行结果如下:

?

0x02 strcat 函数

📜 头文件: string.h

🔍 链接: http://www.cplusplus.com/reference/cstring/strcat/

📚 说明:将 src 所指向的字符串复制到 dest 所指向的字符串后面(删除 *dest 原来末尾的 \0

📌 注意事项:

????? ① 源字符串 src 必须以 \0 结束

????? ② 会将源字符串 src 中的 \0 一同拷贝到目标空间 dest ,并删除 *dest 原来末尾的 \0

????? ③ 目标空间必须足够大,以确保能够存放源字符串 dest

????? ④ 目标空间必须可变,即目标空间 dest 不可以被 const 声明

💬 代码演示:

#include <stdio.h>
#include <string.h>

int main()
{
    char arr1[30] = "hello";
    char arr2[] = "world";
    
    strcat(arr1, arr2);
    printf("%s\n", arr1);

    return 0;
}

?🚩 hello world

0x03 strcmp 函数

📜 头文件: string.h

🔍 链接: http://www.cplusplus.com/reference/cstring/strcmp/

📚 说明:用于比较两个字符串并根据比较结果返回整数,?两个字符串自左向右逐个字符相比,按照 ASCII值 大小相比较,从第一对字符开始比,如果相等则比下一对,直到出现不同的字符或遇 \0 才停止。对比规则如下:

?💬 代码演示:

#include <stdio.h>
#include <string.h>

int main()
{   
    char *p1 = "abcdef";
    char *p2 = "aqwer";
    int ret = strcmp(p1, p2); // p1和p2比
    // a==a, 对比下一对,b<q,所以p2大
    printf("%d\n", ret);

    return 0;
}

🚩? -1( 返回负数,所以 p1< p2 )

🔑 解析:

📌 注意事项:根据编译器的不同,返回的结果也不同

VS2013 中,大于返回 1,等于返回 0,小于返回 -1。但在 Linux-gcc 中,大于返回正数,等于返回0,小于返回负数。因此,我们需要注意判断部分的写法:

// 不推荐 ?
    if(strcmp(p1, p2) == 1) {
        printf("p1 > p2");
    } else if(strcmp(p1, p2 == 0)) {
        printf("p1 == p2");
    } else if(strcmp(p1, p2) == -1) {
        printf("p1 < p2");
    }
    
// 推荐 ?
    if(strcmp(p1, p2) > 0) {
        printf("p1 > p2");
    } else if(strcmp(p1, p2 == 0)) {
        printf("p1 == p2");
    } else if(strcmp(p1, p2) < -1) {
        printf("p1 < p2");
    }

三、长度受限制的函数字符串

0x00 strncpy 函数

📜 头文件: string.h

🔍 链接: http://www.cplusplus.com/reference/cstring/strncpy/

📚 说明:从源字符串中拷贝 n 个字符到目标空间

📌 注意事项:

????? ① 如果源字符串的长度小于 n,则拷贝完源字符串之后,在目标的后面追加 0,填充至 n

????? ② dest 和 src 不应该重叠(重叠时可以用更安全的 memmove 替代)

????? ③ 目标空间必须足够大,以确保能够存放源字符串 dest

????? ④ 目标空间必须可变,即目标空间 dest 不可以被 const 声明

💬 代码演示:

#include <stdio.h>
#include <string.h>

int main()
{
    char arr1[5] = "abc";
    char arr2[] = "hello world";
    strncpy(arr1, arr2, 4); // 从arr2中拷贝4个到arr1
    printf("%s\n", arr1);

    return 0;
}

🚩 hell

? 目标空间不够大会导致报错:

#include <stdio.h>
#include <string.h>

int main()
{
    char arr1[5] = "abc"; // 大小为5的数组
    char arr2[] = "hello world";
    strncpy(arr1, arr2, 6); // 要求拷贝6个字节
    printf("%s\n", arr1);

    return 0;
}

🚩 运行结果如下:

?

0x01 strncat 函数

📜 头文件: string.h

🔍 链接: http://www.cplusplus.com/reference/cstring/strncat/

📚 说明:追加 n 个字符到目标空间

📌 注意事项:如果源字符串的长度小于 n,则只复制 \0 之前的内容。

💬 代码演示:

#include <stdio.h>
#include <string.h>

int main()
{
    char arr1[30] = "hello";
    char arr2[] = "world";
    strncat(arr1, arr2, 3); // 从arr2中取3个追加到arr1中
    printf("%s\n", arr1);

    return 0;
}

🚩 hellowor

0x02 strncmp 函数

🔍 链接: http://www.cplusplus.com/reference/cstring/strncmp/

📚 说明:比较到出现另个字符不一样或者一个字符串结束或者 n 个字符全部比较完。

( 除了增了了个 n,其他和 strcmp 一样 )

💬 代码演示:

#include <stdio.h>
#include <string.h>

int main()
{
    const char* p1 = "abczdef";
    const char* p2 = "abcqwer";
    // int ret = strcmp(p1, p2);
    int ret = strncmp(p1, p2, 1);
    int ret2 = strncmp(p1, p2, 4);
    printf("%d %d\n", ret, ret1);

    return 0;
}

🚩? 0? 1

四、字符串查找

0x00 strstr 函数

📜 头文件: string.h

🔍 链接: http://www.cplusplus.com/reference/cstring/strstr/

📚 说明:返回字符串中首次出现子串的地址。若 str2 str1 的子串,则返回 str2str1 中首次出现的地址。如果 str2 不是 str1 的子串,则返回 NULL

?

💬 代码演示:是子串,返回首次出现的地址

#include <stdio.h>
#include <string.h>

int main()
{
    char* p1 = "abcdef";
    char* p2 = "def";
    char* ret = strstr(p1, p2); // 判断p2是否是p1的子串
    printf("%s\n", ret);

    return 0;
}

🚩? def ( p2 是 p1 的子串,所以返回 def )

💬 代码演示:不是子串,返回 NULL

#include <stdio.h>
#include <string.h>

int main()
{
    char* p1 = "abcdef";
    char* p2 = "zzz";
    char* ret = strstr(p1, p2);
    printf("%s\n", ret);

    return 0;
}

🚩? (null)

💬 我们用 if 判断来添加描述,更好地呈现:

#include <stdio.h>
#include <string.h>

int main()
{
    char* p1 = "abcdef";
    char* p2 = "def";
    char* ret = strstr(p1, p2);
    if ( ret == NULL ) {
        printf("子串不存在\n");
    } else {
        printf("%s\n", ret);
    }
    return 0;
}

0x01 strtok 函数

📜 头文件: string.h

🔍 链接: http://www.cplusplus.com/reference/cstring/strtok/

📚 说明:

📌 注意事项:strtok 会破坏原字符串,分割后原字符串保留第一个分割符前的字符

💬 代码演示:分割ip

#include <stdio.h>
#include <string.h>

int main()
{
    //192.168.0.1
    //192 168 0 1 - strtok

    char ip[] = "192.168.0.1";
    // const char* sep = ".";
    // char* ret = strtok(ip, sep);
    char* ret = strtok(ip, ".");
    printf("%s\n", ret);

    ret = strtok(NULL, ".");
    printf("%s\n", ret);

    ret = strtok(NULL, ".");
    printf("%s\n", ret);

    ret = strtok(NULL, ".");
    printf("%s\n", ret);

    return 0;
}

🚩? 运行结果如下:

💬 代码演示:分割邮箱

#include <stdio.h>
#include <string.h>

int main()
{
    //1300300100@qq.com
    //1300300100 qq com
    char arr[] = "1300300100@qq.com";
    printf("原字符串: %s\n", arr);
    
    const char* sep = "@."; // 创建sep
    char arr1[30];
    char* ret = NULL;
    strcpy(arr1, arr); // 将数据拷贝一份,保留arr数组的内容

    // 分行打印切割内容
    for (ret = strtok(arr, sep); ret != NULL; ret = strtok(NULL, sep)) {
        printf("%s\n", ret);
    }

    printf("保留的原内容:%s\n", arr1); // 保存的arr数组的内容
    printf("分割后原字符串被破坏: %s\n", arr); // 分割后原字符串保留第一个分割符前的字符

    return 0;
}

🚩 运行结果如下:

0x02 strerror 函数

📜 头文件: string.h

🔍 链接: http://www.cplusplus.com/reference/cstring/strerror/

📚 说明:返回错误码,返回错误码所对应的错误信息

💬 代码演示:

#include <string.h>
#include <stdio.h>
#include <errno.h>

int main()
{
     // 错误码       错误信息
     // 0 -          No error
     // 1 -          Operation not permitted
     // 2 -          No such file or directory
     // ...

    //errno 是一个全局的错误码变量
    //当c语言的库函数在执行过程中,发生了错误,
    //就会把对应的错误码赋值到errno中
    char* str = strerror(errno);
    printf("%s\n", str);

    return 0;
}

🚩? No error

📚 关于 errno:查看 errno 的详细介绍? [百度百科]

errno 是记录系统的最后一次错误代码。代码是一个 int 型的值,在 errno.h 中定义

💬 文件操作的时候可以使用(后面会讲文件操作)

FILE* pf = fopen("test.txt", "r");
if ( pf == NULL ) {
    printf("%s\n", strerror(errno));
} else {
    printf("*****open file success*****\n")
}

五、字符操作

0x00 字符分类

📜 头文件: stype.h

?💬 代码演示:islower

#include <stdio.h>
#include <ctype.h>

int main()
{
    char ch1 = 'a';
    int ret = islower(ch1); // 判断ch1是否为小写
    printf("%d\n", ret);

    char ch2 = 'B';
    int res = islower(ch2); // 判断ch2是否为小写
    printf("%d\n", res);

    return 0;
}

?🚩 运行结果如下:

0x01 字符转换

📜 需引入头文件 stype.h

?

💬 代码演示:tolower

int main()
{
    char ch = tolower('Q'); // 大写转小写
    putchar(ch);

    return 0;
}

🚩? q

💬 代码演示:toupper

int main()
{
    char ch = toupper('q'); // 小写转大写
    putchar(ch);
    
    return 0;
}

🚩? Q

💬 代码演示:字符串内容全部大写转小写( 利用 while 循环 )

#include <stdio.h>
#include <ctype.h>

int main()
{
    char arr[] = "I Am A Student";
    int i = 0;
    while(arr[i]) {
        if ( isupper(arr[i]) ) {
            arr[i] = tolower(arr[i]);
        } 
        i++;
    }
    printf("%s\n", arr);

    return 0;
}

🚩? i am a student

💬 模拟实现 Python 中的 swapcase 函数 ( 字符串大小写互换 )

#include <stdio.h>
#include <ctype.h>
#include <assert.h>

void swapcase(char arr[]) 
{
    assert(arr != NULL); // 断言防止传空
    int i = 0;
    while (arr[i] != '\0') {
        if (islower(arr[i])) { //是小写吗?
            arr[i] = toupper(arr[i]); //如果是,让它变成大写
        } else {  //不是小写
            arr[i] = tolower(arr[i]); //把它变成小写
        }
        i++;
    }
}

int main()
{
    char arr[] = "AaBbCcDdEeFf";
    swapcase(arr);
    printf("%s\n", arr);

    return 0;
}

🚩?? aAbBcCdDeEfF

六、字符操作函数

0x00 memcpy 函数

📜 头文件: string.h

🔍 链接: http://www.cplusplus.com/reference/cstring/memcpy/

📚 说明:从源内存地址 src 的起始位置开始拷贝 n 个字节到目标内存地址 dest

📌 注意事项:

????? ① memcpy 没有刹车,这个函数遇到 \0 并不会停下来

????? ② 如果 src dest 有任何的重叠,复制的结果都是未定义的

?

💬 代码演示:

#include <stdio.h>
#include <string.h>

int main()
{
    int arr1[] = {1, 2, 3, 4, 5};
    int arr2[5] = {0};
    memcpy(arr2, arr1, sizeof(arr1));

    // 打印 arr2 的内容
    int i = 0;
    for(i=0; i<5; i++) {
        printf("%d ", arr2[i]);
    }

    return 0;
}

🚩 ? 1 2 3 4 5

💬 代码演示:拷贝结构体

#include <stdio.h>
#include <string.h>

struct S
{
    char name[20];
    int age;
};

int main()
{
    struct S arr3[] = { {"张三", 20}, {"李四", 30} };
    struct S arr4[3] = { 0 };

    memcpy(arr4, arr3, sizeof(arr3));

    return 0;
}

🔑 调试一下看看是否拷贝成功:

?

0x02 memmove 函数

📜 头文件: string.h

🔍 链接: http://www.cplusplus.com/reference/cstring/memcpy/

📚 说明:用于拷贝字节,如果目标区域和源区域有重叠时,memmove 能够保证源串在被覆盖之前将重叠区域的字节拷贝到目标区域中,但复制后源内容会被更改。

📌 注意事项:

????? ① 和 memcpy 的差别就是 memmove 函数处理的源内存块和目标内存块时可以重叠的

????? ② 如果原空间和目标空间出现重叠,应使用 memmove 函数处理

C语言标准要求:

memcpy 用来处理不重叠的内存拷贝,而 memmove 用来处理重叠内存的拷贝。

💬 代码演示:

#include <stdio.h>
#include <string.h>

int main()
{
    int arr[] = {1,2,3,4,5,6,7,8,9,10};
    int i = 0;

    memmove(arr+2, arr, 20);

    for(i=0; i<10; i++) {
        printf("%d ", arr[i]);
    }

    return 0;
}

🚩 运行结果如下:

0x03 memcmp 函数

📜 头文件: string.h

🔍 链接: http://www.cplusplus.com/reference/cstring/memcmp/

📚 说明:比较 ptr1 ptr2 指针开始的 n 个字节,按字节比较

?

📌 注意事项:memcmp 不同于 strcmpmemcmp 遇到 \0 不会停止比较

💬 代码演示:

#include <stdio.h>
#include <string.h>

int main()
{
    float arr1[] = {1.0, 2.0, 3.0, 4.0};
    float arr2[] = {1.0, 3.0};
    int ret = memcmp(arr1, arr2, 8); // arr1是否比arr2大,比较8个字节
    printf("%d\n", ret);
    
    return 0;
}

🚩? -1 ( 说明 arr1 小于 arr2 )

0x04 memset 函数

📜 头文件: string.h

🔍 链接: http://www.cplusplus.com/reference/cstring/memset/

📚 说明:将某一块内存中的内容全部设置为指定的值,通常为新申请内存做初始化工作。

📌 注意事项:memset 是以字节为单位设置内存的

💬 代码演示:把整型数组将前 20 个字节全部设置为 1

#include <stdio.h>
#include <string.h>

int main()
{
    // 40
    int arr[10] = {0};
    memset(arr, 1, 20); // 将前20个字节全部设置为1

    return 0;
}

?

?


本章完

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2021-07-22 22:56:03  更:2021-07-22 22:56:08 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/2 0:37:29-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码