《C 语言字符串操作从入门到实战(下篇):strncpy/strncat/strstr 等函数原理与实现》

发布于:2025-05-22 ⋅ 阅读:(13) ⋅ 点赞:(0)

目录

七. strncpy函数的使用与模拟实现

7.1  strncpy函数理解

7.2  strncpy函数使用示例

7.3  strncpy函数模拟实现

八. strncat函数的使用与模拟实现

8.1 strncat函数理解

8.2 strncat函数使用示例

8.3 strncat函数模拟实现

九. strncmp函数的使用

9.1 strncmp函数理解

9.2 strncmp函数使用示例

十. strstr函数的使用与模拟实现

10.1 strstr函数理解

10.2 strstr函数使用示例

10.3 strstr函数模拟实现

十一. strtok函数的使用与模拟实现

11.1 strtok函数理解

11.2 strtok函数使用示例

11.3 strtok注意事项

十二. strerror函数的使用与模拟实现

12.1 strerror函数理解

12.2 strerror函数使用

12.3 perror函数


七. strncpy函数的使用与模拟实现

7.1  strncpy函数理解

strncpy 是 C 标准库中用于复制字符串的函数,定义在 <string.h> 头文件中。相比 strcpy,它提供了长度限制,可以防止缓冲区溢出。

函数原型

char *strncpy(char *dest, const char *src, size_t n);

参数说明

  • dest: 目标字符数组,用于存储复制的内容

  • src: 源字符串,将被复制的字符串

  • n: 最多复制的字符数(包括 ‘\0’)

返回值

返回目标字符串 dest 的指针

功能特点

  1. 复制最多 n 个字符 从 src 到 dest

  2. 两种终止条件:

    • 遇到 src 的 ‘\0’ 终止符

    • 达到最大字符数 n

7.2  strncpy函数使用示例

#include<stdio.h>
#include<string.h>
int main()
{
	char arr1[20] = { 0 };
	char arr2[] = "hello,worldCCCCCCC";
	char* p = strncpy(arr1, arr2, 11);
	printf("%s\n", p);
	printf("%s\n", arr1);
	return 0;
}

7.3  strncpy函数模拟实现

#include<stdio.h>   // 标准输入输出库
#include<string.h>  // 字符串操作库
#include<assert.h>  // 断言库

// 自定义的strncpy函数
// 参数:arr1 - 目标字符串,arr2 - 源字符串,num - 要拷贝的字符数
// 返回值:指向目标字符串的指针
char* my_strncpy(char* arr1, const char* arr2, size_t num)
{
    // 使用断言确保目标指针和源指针都不为NULL
    assert(arr1 && arr2);
    
    // 保存目标字符串的起始地址,用于返回
    char* p = arr1;
    int i = 0;
    
    // 循环拷贝字符,直到达到指定数量或遇到源字符串的结束符
    for (i = 0; i < num && arr2[i]; i++)
    {
        arr1[i] = arr2[i];
    }
    
    // 如果拷贝的字符数少于指定数量,则在目标字符串后添加结束符
    if (i < num)
    {
        arr1[i] = 0;
    }
    
    // 返回目标字符串的起始地址
    return p;
}

int main()
{
    char arr1[20] = { 0 };        // 初始化目标字符串数组,全部置为0
    char arr2[] = "abcdefg";      // 源字符串
    char* ret = my_strncpy(arr1, arr2, 5);  // 调用自定义函数,拷贝前5个字符
    
    printf("%s", ret);            // 输出结果:abcde
    return 0;
}

八. strncat函数的使用与模拟实现

8.1strncat函数理解

strncat 是 C 标准库中的一个字符串拼接函数,用于将源字符串的前 n 个字符追加到目标字符串的末尾,并自动添加终止符 \0

函数原型

char *strncat(char *dest, const char *src, size_t n);
  • dest:目标字符串(必须足够大以容纳追加后的结果)。
  • src:源字符串(不会被修改)。
  • n:最多追加的字符数(如果 src 长度小于 n,则只追加 src 的全部内容)。
  • 返回值:返回 dest 的指针。

8.2 strncat函数使用示例

#include<stdio.h>
#include<string.h>
int main()
{
	char arr1[20] = "hello";
	char arr2[] = "world";
	char*p=strncat(arr1, arr2,5);
	printf("%s\n", p);
	printf("%s\n", arr1);
	return 0;
}

8.3 strncat函数模拟实现

#include<stdio.h>   // 标准输入输出库
#include<assert.h>  // 断言库

// 自定义的 strncat 函数
// 参数:arr1 - 目标字符串,arr2 - 源字符串,num - 要追加的字符数
// 返回值:指向目标字符串的指针
char* mystrncat(char* arr1, const char* arr2, size_t num)
{
    assert(arr1 && arr2);  // 确保目标指针和源指针都不为 NULL

    char* p = arr1;        // 保存目标字符串的起始地址,用于返回

    // 找到目标字符串的末尾(即 '\0' 的位置)
    while (*arr1)
    {
        arr1++;
    }

    // 从源字符串复制最多 num 个字符到目标字符串的末尾
    int i = 0;
    for (i = 0; arr2[i] && i < num; i++)
    {
        arr1[i] = arr2[i];
    }

    // 如果 num 小于 0,则在目标字符串后添加结束符(但 num 是 size_t,不可能小于 0)
    if (num < 0)
    {
        arr1[i] = 0;
    }

    return p;  // 返回目标字符串的起始地址
}

int main()
{
    char arr1[20] = "hello ";      // 目标字符串
    char arr2[] = "worldCCCCC";        // 源字符串
    char* ret = mystrncat(arr1, arr2, 5);  // 调用自定义函数,追加前 3 个字符

    printf("%s", ret);            // 输出结果:hellowor
    return 0;
}

九. strncmp函数的使用

9.1 strncmp函数理解

strncmp 是 C 标准库中的一个字符串比较函数,用于比较两个字符串的前 n 个字符。它的主要作用是判断两个字符串是否相等,或者在字典序(ASCII 码顺序)上的大小关系。


函数原型

int strncmp(const char *str1, const char *str2, size_t n);
  • str1:第一个字符串(不会被修改)。
  • str2:第二个字符串(不会被修改)。
  • n:最多比较的字符数。
  • 返回值
    • < 0str1 的前 n 个字符在字典序上小于 str2
    • = 0str1 的前 n 个字符与 str2 完全相同。
    • > 0str1 的前 n 个字符在字典序上大于 str2

strncmp 的工作原理:

  1. 逐个字符比较
    • 从 str1 和 str2 的第一个字符开始比较,直到遇到不同的字符或比较完 n 个字符。
  2. 比较规则
    • 如果 str1 的字符 ASCII 码值 < str2 的字符,返回 负数
    • 如果 str1 的字符 ASCII 码值 > str2 的字符,返回 正数
    • 如果前 n 个字符完全相同,返回 0
  3. 提前终止条件
    • 遇到 \0(字符串结束符)时停止比较。
    • 比较完 n 个字符时停止。

9.2 strncmp函数使用示例

#include<stdio.h>
#include<string.h>
int main()
{
	char arr1[] = "abcdef";
	char arr2[] = "abcggg";
	int ret = strncmp(arr1, arr2, 5);
	if (ret > 0)
		printf("abcdef>abcggg\n");
	else if (ret < 0)
		printf("abcdef<abcggg\n");
	else
		printf("=\n");
	return 0;
}

十. strstr函数的使用与模拟实现

10.1 strstr函数理解

strstr 是 C 标准库中的一个字符串查找函数,用于在一个字符串中查找另一个字符串的首次出现位置。

函数原型

char *strstr(const char *haystack, const char *needle);
    • 参数
      • haystack:被搜索的主字符串
      • needle:要查找的子字符串
    • 返回值
      • 如果找到,返回指向主字符串中子字符串首次出现位置的指针
      • 如果未找到,返回 NULL

    功能说明:

    strstr 函数会扫描 haystack 字符串,查找 needle 字符串的第一次出现。查找是区分大小写的。

    10.2 strstr函数使用示例

    #include<stdio.h>
    #include<string.h>
    int main()
    {
    	char arr1[] = "I LOVE CHAIN";
    	char arr2[] = "LOVE";
    	char* p = strstr(arr1, arr2);
    	if (p != NULL)
    		printf("查找成功: %s\n", p);
    	else
    		printf("抱歉 查找失败\n");
    }

    10.3 strstr函数模拟实现

    #include<stdio.h>   // 标准输入输出库
    #include<string.h>  // 字符串操作库
    #include<assert.h>  // 断言库
    
    // 自定义的 strstr 函数
    // 参数:str1 - 被查找的字符串,str2 - 要查找的子串
    // 返回值:如果找到,返回子串在 str1 中的起始地址;否则返回 NULL
    char* my_strstr(const char* str1, const char* str2)
    {
        assert(str1 && str2);  // 确保 str1 和 str2 都不为 NULL
    
        char* p = (char*)str1;  // 用于遍历 str1
        char* s1 = NULL;        // 用于临时记录 str1 的当前位置
        char* s2 = NULL;        // 用于遍历 str2
    
        // 如果要查找的子串是空字符串,直接返回 str1
        if (*str2 == '\0')
            return (char*)str1;
    
        // 遍历 str1
        while (*p)
        {
            s1 = p;            // 记录当前查找的起始位置
            s2 = (char*)str2;  // 每次从 str2 的开头开始匹配
    
            // 逐个字符比较,直到字符不匹配或任一字符串结束
            while (*s1 && *s2 && *s1 == *s2)
            {
                s1++;
                s2++;
            }
    
            // 如果 str2 已经遍历完(即找到完整匹配),返回起始位置 p
            if (*s2 == '\0')
                return p;
    
            p++;  // 继续查找下一个位置
        }
    
        return NULL;  // 遍历完 str1 仍未找到,返回 NULL
    }
    
    int main()
    {
        char arr1[] = "I LOVE CHINA";  // 被查找的字符串
        char arr2[] = "LOVE";      // 要查找的子串
    
        char* ret = my_strstr(arr1, arr2);  // 调用自定义查找函数
    
        if (ret != NULL)
        {
            printf("查找成功:%s", ret);  // 
        }
        else
        {
            printf("查找失败");
        }
    
        return 0;
    }

    十一. strtok函数的使用与模拟实现

    11.1 strtok函数理解

    strtok 是 C 标准库中的一个字符串分割函数,用于将一个字符串按照指定的分隔符(delimiters)拆分成多个子字符串(tokens)。


    函数原型

    #include <string.h>  // 需要包含头文件
    
    char *strtok(char *str, const char *delimiters);
    
    • str:待分割的字符串(首次调用时传入,后续调用传 NULL)。

    • delimiters:分隔符集合(如 ", \t \n" 表示按空格、逗号、制表符、换行符分割)。

    • 返回值

      • 成功时返回下一个子字符串(token)的指针。

      • 如果没有更多子字符串,返回 NULL

    strtok 的工作原理

    1. 首次调用

      • 传入待分割的字符串 strstrtok 找到第一个分隔符,将其替换为 \0,并返回第一个子字符串的指针。

    2. 后续调用

      • 传入 NULLstrtok 会从上次结束的位置继续查找下一个分隔符,并返回下一个子字符串。

    3. 结束条件

      • 当所有子字符串都被提取后,返回 NULL

    为什么后续调用传入NULL?

    原因如下:

    1. strtok 的工作原理

    strtok 是一个状态ful(stateful)函数,它会记住上一次处理的位置。具体来说:

    • 首次调用时,strtok 接收一个字符串(如 str)和分隔符(如 delimiters),它会从该字符串的起始位置开始扫描,找到第一个不包含分隔符的子字符串(token),并返回它。

    • 后续调用时,strtok 需要继续从上次结束的位置开始扫描剩余的部分。为了告诉 strtok 继续处理同一个字符串,需要传入 NULL 作为第一个参数。如果传入一个新的字符串,strtok 会重置内部状态,开始处理新的字符串。

    2. 为什么传入 NULL

    • 内部静态指针:strtok 内部使用一个静态指针(或全局变量)来记录当前处理的位置。首次调用时,这个指针被初始化为传入字符串的地址;后续调用时,传入 NULL 表示“继续处理上次的字符串”。

    • 避免重置状态:如果后续调用传入一个新的字符串(非 NULL),strtok 会重置内部指针,导致之前的分割状态丢失。

    11.2 strtok函数使用示例

    #define _CRT_SECURE_NO_WARNINGS
    #include <stdio.h>
    #include <string.h>
    
    int main() {
        char str[] = "hello,world;this|is-a.test";
        const char* delimiters = ",;|-.";  // 分隔符可以是逗号、分号、竖线、横线、点
    
        // 首次调用,传入 str
        char* token = strtok(str, delimiters);
        while (token != NULL) {
            printf("Token: %s\n", token);
            token = strtok(NULL, delimiters);  // 后续调用传 NULL
        }
    
        return 0;
    }
    

    11.3 strtok注意事项

    1. 修改原字符串

      • strtok 会直接修改传入的字符串,将分隔符替换为 \0。因此,不能对常量字符串(如 "hello,world")使用 strtok,否则会导致段错误(Segmentation Fault)。

      • ✅ 正确:char str[] = "hello,world";(可修改)

      • ❌ 错误:char *str = "hello,world";(字符串常量,不可修改)

    2. 连续分隔符

      • 如果字符串中有连续的分隔符(如 "a,,b"),strtok 会跳过它们,不会返回空字符串。

    3. 不能嵌套调用

      • 由于 strtok 使用静态存储,不能同时用于多个字符串的分割。例如:
        char str1[] = "a,b";
        char str2[] = "1;2";
        char *token1 = strtok(str1, ",");  // 第一次调用
        char *token2 = strtok(str2, ";");  // 会破坏 str1 的分割状态!

    十二. strerror函数的使用与模拟实现

    12.1 strerror函数理解

    strerror 是 C 标准库中的一个函数,用于将错误代码(errno)转换为可读的错误信息字符串。它定义在 <string.h> 头文件中,通常与 errno(定义在 <errno.h>)一起使用,以便在程序出错时提供更友好的错误提示。


    函数原型

    #include <string.h>
    char *strerror(int errnum);
    
    • 参数

      • errnum:错误代码(通常是 errno 的值)。

    • 返回值

      • 返回一个指向错误描述字符串的指针(静态存储区,不可修改)。

    strerror 的用途

    • 在不同的系统和C语言标准库的实现中都规定了⼀些错误码,⼀般是放在 errno.h 这个头文件中说明的,C语言程序启动的时候就会使用⼀个全局的变量 errno 来记录程序的当前错误码,只不过程序启动的时候errno是 0,表示没有错误,当我们在使用标准库中的函数的时候发生了某种错误,就会将对应的错误码,存放在 errno 中,而⼀个错误码的数字是整数很难理解是什么意思,所以每⼀个错误码都是有对应的错误信息的。strerror函数就可以将错误对应的错误信息字符串的地址返回

    12.2 strerror函数使用

    #include <errno.h>
    #include <string.h>
    #include <stdio.h>
    //打印0~10这些错误码对应的信息
    int main()
    {
    	int i = 0;
    	for (i = 0; i <= 10; i++) {
    		printf("%d.%s\n",i, strerror(i));
    	}
    	return 0;
    }

    示例

    #include <stdio.h>
    #include <string.h>
    #include <errno.h>
    int main()
    {
    	//C语言可以打开文件
    	//fopen
    	//如果以读的形式打开文件,文件是必须要存在的,如果文件不存在,则打开文件失败
    	//fopen函数就会将错误码放在errno
    	//同时函数就会返回NULL
    	FILE* pFile;
    	pFile = fopen("5_20.text", "r");
    	if (pFile == NULL)
    		printf( %s\n", strerror(errno));
    	return 0;
    }

    12.3 perror函数

    perror 是 C 标准库(<stdio.h>)中的一个函数,用于打印与 errno 相关的错误信息。它的原型如下:

    void perror(const char *s);
    

    功能

    • 根据全局变量 errno(通常由系统调用或库函数设置)打印对应的错误描述。
    • 如果 s 不是 NULL 或空字符串,perror 会先输出 s,后跟一个冒号 : 和空格,然后输出 errno 对应的错误信息。
    • 如果 s 是 NULL 或空字符串,则只输出 errno 的错误信息。

    使用示例

    int main() {
        FILE* fp = fopen("nonexistent_file.txt", "r");
        if (fp == NULL) {
            perror("Failed to open file");
        }
        return 0;
    }

    与 strerror(errno) 的区别

    • perror 直接打印错误信息到 stderr(标准错误输出)。
    • strerror(errno) 返回错误信息的字符串,可以自定义输出方式:
    fprintf(stderr, "Error: %s\n", strerror(errno));

    以上就是字符函数和字符串函数上篇的全部内容 希望能够为您提供帮助

    往期回顾

    《C 语言字符串操作从入门到实战(上篇):字符分类、转换及strlen/strcpy等函数详解》


    网站公告

    今日签到

    点亮在社区的每一天
    去签到