当前位置: 首页 > news >正文

C 语言12:字符串函数全解析

一、引言

在 C 语言中,字符串就是以 '\0'(空字符)结尾的 char 数组

C 标准库 <string.h> 提供了大量字符串处理函数,掌握它们能极大提升代码效率。

但如果不了解原理,很容易写出有 bug 或不安全的代码(比如缓冲区溢出)。

二、常用字符串函数分类

我将它们分为几类:

  1. 求长度
    • strlen
  2. 比较
    • strcmpstrncmp
  3. 拷贝
    • strcpystrncpy
  4. 拼接
    • strcatstrncat
  5. 查找
    • strchrstrrchrstrstrstrpbrkstrspnstrcspn
  6. 分割
    • strtok
  7. 内存操作(二进制安全)
    • memcpymemmovememset


三、函数详解

1. strlen —— 获取字符串长度

size_t strlen(const char *s);

功能:返回字符串 s 的长度,不包括结尾的 '\0'

源码的实现:

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

解析

  • 遍历字符串直到遇到 '\0'
  • 时间复杂度 O (n)。

实例:

#include <stdio.h>
#include <string.h>int main() 
{char str[] = "Hello";printf("%zu\n", strlen(str)); // 输出 5
}

使用场景

  • 分配内存时计算所需空间。
  • 循环遍历字符串。

常见问题

  • 忘记 '\0' 不算在长度里。
  • 参数必须是合法的以 '\0' 结尾的字符串,否则会越界访问。

2. strcmp —— 比较字符串

int strcmp(const char *s1, const char *s2);

功能:按字典序比较两个字符串。

返回值

  • 等于 0:s1 == s2
  • 小于 0:s1 < s2
  • 大于 0:s1 > s2

源码实现:

int my_strcmp(const char *s1, const char *s2) 
{while (*s1 && (*s1 == *s2)) {s1++;s2++;}return *(unsigned char *)s1 - *(unsigned char *)s2;
}

解析

  • 逐个字符比较,直到不同或遇到 '\0'
  • 返回的是字符 ASCII 码的差值。

实例:


char* str1 ="hello world";
char* str2 ="hello world";if (strcmp(str1, str2) == 0) 
{printf("相等\n");
}

使用场景

  • 排序字符串数组。
  • 判断用户输入是否匹配某个关键字。

常见问题

  • 用 == 比较字符串是错误的,应使用 strcmp

3. strcpy —— 拷贝字符串

char *strcpy(char *dest, const char *src);

功能:将 src 拷贝到 dest,包括结尾的 '\0'

源码实现

char *my_strcpy(char *dest, const char *src) 
{char *ret = dest;while ((*dest++ = *src++));return ret;
}

解析

  • 循环赋值,直到 src 的 '\0' 被复制。
  • 必须保证 dest 足够大,否则会缓冲区溢出。

示例:

char dest[20];
strcpy(dest, "Hello");

使用场景

  • 字符串赋值。

常见问题

  • 缓冲区溢出(安全版本:strncpy)。

4. strncpy —— 拷贝指定长度

原型:

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

功能:拷贝最多 n 个字符,不一定会自动加 '\0'

源码实现:

char *my_strncpy(char *dest, const char *src, size_t n) 
{char *ret = dest;while (n && (*dest++ = *src++)){n--;}while (n--) {*dest++ = '\0';}return ret;
}

解析

  • 如果 src 长度 >= n,则不会自动加 '\0'
  • 如果 src 长度 < n,则剩余部分填充 '\0'

常见问题

  • 忘记手动加 '\0' 会导致字符串没有结束符。


5. strcat —— 拼接字符串

char *strcat(char *dest, const char *src);

功能:将 src 追加到 dest 的末尾。

源码实现

char *my_strcat(char *dest, const char *src) 
{char *ret = dest;while (*dest) dest++;while ((*dest++ = *src++));return ret;
}

解析

  • 先找到 dest 的末尾 '\0',再追加 src
  • 必须保证 dest 足够大。

常见问题

  • 缓冲区溢出。

6. strncat —— 拼接指定长度

原型:

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

功能追加最多 n 个字符,并自动加 '\0'

示例:

char dest[20] = "Hello";
strncat(dest, "World", 3); // dest = "HelloWor"

7. strchr / strrchr —— 查找字符

char *strchr(const char *s, int c);
char *strrchr(const char *s, int c);

功能

  • strchr:从左到右查找第一个匹配字符。
  • strrchr:从右到左查找。

示例

char *p = strchr("Hello", 'l');
printf("%s\n", p); // 输出 "llo"

8. strstr —— 查找子串

char *strstr(const char *haystack, const char *needle);

功能:查找子串 needle 在 haystack 中首次出现的位置。

源码实现(KMP 简化版)

char *my_strstr(const char *haystack, const char *needle) 
{if (*needle == '\0') return (char *)haystack;for (; *haystack; haystack++) {const char *h = haystack;const char *n = needle;while (*h && *n && *h == *n) {h++;n++;}if (*n == '\0') return (char *)haystack;}return NULL;
}

使用场景

  • 判断一个字符串是否包含另一个子串。

9. strcspn / strspn —— 计算连续字符跨度

size_t strcspn(const char *s, const char *reject);
size_t strspn(const char *s, const char *accept);
  • strspn:从 s 的开头开始,统计连续出现的、且都属于 accept 集合的字符个数。

s:  H e l l o   W o r l d
accept: H e l
过程: H✓ → e✓ → l✓ → l✓ → o✗ → 停止,返回 4
  • strcspn:从 s 的开头开始,统计连续出现的、且都不属于 reject 集合的字符个数。

s:  H e l l o   W o r l d
reject:  (空格)
过程: H✓ → e✓ → l✓ → l✓ → o✓ → (空格)✗ → 停止,返回 5

示例:

size_t len = strcspn("Hello World", " ");
printf("%zu\n", len); // 输出 5

使用场景:

strspn

  • 前缀合法性检查:比如判断一个字符串是否以某些允许的字符开头。
  • 协议解析:从数据流中读取固定字符集的字段。
  • 提取固定字符集组成的子串

strcspn

  • 查找分隔符位置:找到字符串中第一个出现的分隔符位置。
  • 跳过不需要的字符:例如读取一行时,跳过行首的非法字符。
  • 判断字符串中是否包含非法字符(通过返回值判断)。

10. strtok —— 分割字符串

char *strtok(char *str, const char *delim);

功能:按分隔符 delim 分割字符串(会修改原字符串)。

实例:

char str[] = "a,b;c";char *p = strtok(str, ",;");while (p) 
{printf("%s\n", p);         //输出:a b cp = strtok(NULL, ",;");
}

常见问题

  • 线程不安全(内部有静态变量)。
  • 会破坏原字符串。

四、安全使用建议

  1. 避免缓冲区溢出:尽量使用 strncpystrncatsnprintf
  2. 检查返回值:如 strstrstrchr 找不到会返回 NULL
  3. 初始化缓冲区:避免未定义行为。
  4. 处理重叠内存:用 memmove 而不是 memcpy

五、函数速查表

http://www.dtcms.com/a/469403.html

相关文章:

  • 国家城乡建设规划部网站邢台专业网站建设价格
  • 三层架构:解耦 JavaWeb 开发的核心范式
  • MySQL————表的约束
  • 速度达24.3MB/s,最新精简可用版!
  • 分业务采用差异化模式:全面提升 SQL Server 系统的并发性能、可靠性与数据准确性
  • 【Linux】应用层自定义协议与序列化
  • 文件上传漏洞: .htaccess文件
  • 【GD32】软件I2C
  • 温州产品推广网站服务网站建设方案
  • 08-docker综合应用
  • 电商网站建设与运营哦在线图片编辑助手
  • 十一款c++小游戏
  • 15-verilog的延时打拍问题记录
  • skynet.newservice接口分析
  • C# 中 Excel 工作表打印前页面边距的设置方法
  • uniapp学习【vue3在uniapp中语法,使用element】
  • 网站建设的基本流程和技术规范懒人免费建站模板
  • Linux的Ext文件系统:硬盘理解和inode及软硬链接
  • 可靠的媒体发稿网有哪些
  • 鸿蒙剪贴板服务的新特性
  • 上海外贸营销网站建设做app的模板下载网站
  • Linux中Tomcat部署项目
  • kanass入门到实战(16) - 如何管理产品
  • CAT-M:蜂窝物联网的基石与通信工程的精妙平衡
  • Flink 状态模式演进(State Schema Evolution)从原理到落地的一站式指南
  • 网站建设游戏开发专门做物理的网站
  • 计算机网络【第五章-传输层】
  • 打工人日报#20251011
  • 电子电气架构 ---安全车控操作系统介绍
  • python 网站开发入门wordpress获取文章