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

目录

[七. strncpy函数的使用与模拟实现](#七. strncpy函数的使用与模拟实现)

[7.1 strncpy函数理解](#7.1 strncpy函数理解)

[7.2 strncpy函数使用示例](#7.2 strncpy函数使用示例)

[7.3 strncpy函数模拟实现](#7.3 strncpy函数模拟实现)

[八. strncat函数的使用与模拟实现](#八. strncat函数的使用与模拟实现)

[8.1 strncat函数理解](#8.1 strncat函数理解)

[8.2 strncat函数使用示例](#8.2 strncat函数使用示例)

[8.3 strncat函数模拟实现](#8.3 strncat函数模拟实现)

[九. strncmp函数的使用](#九. strncmp函数的使用)

[9.1 strncmp函数理解](#9.1 strncmp函数理解)

[9.2 strncmp函数使用示例](#9.2 strncmp函数使用示例)

[十. strstr函数的使用与模拟实现](#十. strstr函数的使用与模拟实现)

[10.1 strstr函数理解](#10.1 strstr函数理解)

[10.2 strstr函数使用示例](#10.2 strstr函数使用示例)

[10.3 strstr函数模拟实现](#10.3 strstr函数模拟实现)

[十一. strtok函数的使用与模拟实现](#十一. strtok函数的使用与模拟实现)

[11.1 strtok函数理解](#11.1 strtok函数理解)

[11.2 strtok函数使用示例](#11.2 strtok函数使用示例)

[11.3 strtok注意事项](#11.3 strtok注意事项)

[十二. strerror函数的使用与模拟实现](#十二. strerror函数的使用与模拟实现)

[12.1 strerror函数理解](#12.1 strerror函数理解)

[12.2 strerror函数使用](#12.2 strerror函数使用)

[12.3 perror函数](#12.3 perror函数)


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

7.1 strncpy函数理解

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

函数原型

cpp 复制代码
char *strncpy(char *dest, const char *src, size_t n);

参数说明

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

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

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

返回值

返回目标字符串 dest 的指针

功能特点

  1. 复制最多 n 个字符 从 srcdest

  2. 两种终止条件:

    • 遇到 src 的 '\0' 终止符

    • 达到最大字符数 n

7.2 strncpy函数使用示例

cpp 复制代码
#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函数模拟实现

cpp 复制代码
#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

函数原型

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

8.2 strncat函数使用示例

cpp 复制代码
#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函数模拟实现

cpp 复制代码
#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 码顺序)上的大小关系。


函数原型

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

9.2 strncmp函数使用示例

cpp 复制代码
#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 标准库中的一个字符串查找函数,用于在一个字符串中查找另一个字符串的首次出现位置。

函数原型

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

功能说明:

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

10.2 strstr函数使用示例

cpp 复制代码
#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函数模拟实现

cpp 复制代码
#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)。


函数原型

cpp 复制代码
#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 会重置内部状态,开始处理新的字符串。

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

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

11.2 strtok函数使用示例

cpp 复制代码
#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 使用静态存储,不能同时用于多个字符串的分割 。例如:

      cpp 复制代码
      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>)一起使用,以便在程序出错时提供更友好的错误提示。


函数原型

cpp 复制代码
#include <string.h>
char *strerror(int errnum);
  • 参数

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

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

strerror 的用途

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

12.2 strerror函数使用

cpp 复制代码
#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;
}

示例

cpp 复制代码
#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 相关的错误信息。它的原型如下:

cpp 复制代码
void perror(const char *s);

功能

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

使用示例

cpp 复制代码
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) 返回错误信息的字符串,可以自定义输出方式:
cpp 复制代码
fprintf(stderr, "Error: %s\n", strerror(errno));

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

往期回顾

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

相关推荐
geneculture19 分钟前
《黄帝内经》数学建模与形式化表征方式的重构
人工智能·算法·机器学习·数学建模·重构·课程设计·融智学的重要应用
玉带湖水位记录员38 分钟前
Qt+线段拖曳示例代码
开发语言·c++·qt
_WndProc1 小时前
【C++】控制台小游戏
开发语言·c++·vscode
Vic101011 小时前
GaussDB(PostgreSQL)查询执行计划参数解析技术文档
算法·哈希算法·gaussdb
小王同学的C++1 小时前
C++中的菱形继承问题
开发语言·c++
煤灰2421 小时前
简单用c++的类实现的string
java·开发语言·c++
小喵要摸鱼2 小时前
【软考向】Chapter 3 数据结构
数据结构·算法·排序算法
vegetablesssss2 小时前
QGrphicsScen画布网格和QGrphicsItem对齐到网格
c++·qt
chen_song_2 小时前
CUDA的设备,流处理器(Streams),核,线程块(threadblock),线程,网格(‌gridDim),块(block)和多gpu设备同步数据概念
c++·人工智能·计算机视觉·数据挖掘·cuda编程·并行化计算·并行化计算与cuda编程
vibag2 小时前
第十六届蓝桥杯复盘
java·算法·蓝桥杯·竞赛