☰
15.字符函数
2026/10/8 8:13:30 网站建设 项目流程

一、字符串函数(操作以 '\0' 结尾的字符串)

大白话前提:字符串背后一定藏着一个看不见的标记\0,它代表字符串到此结束。所有字符串函数干活,看到\0就停下。

1. strlen —— 求字符串有效长度

功能:数出\0前面有多少个字符。\0本身不算长度! 返回值:size_t,本质是无符号正数(不能小于 0)

三种实现方式

//方式1:计数器法(最容易看懂,新手首选) size_t My_strlen(char* arr) { size_t i = 0; while (arr[i] != '\0') { i++; } return i; } //方式2:指针‑指针(高级指针写法,考试高频) size_t My_strlen1(char* arr) { char* p = arr; // p记住字符串开头地址 while (*p) // *p不等于'\0'就往后走 p++; return p - arr; // 末尾地址 − 起始地址 = 字符个数 } //方式3:递归写法(理解即可,实际开发不推荐) size_t My_strlen2(char* arr) { if (*arr == '\0') return 0; else return 1 + My_strlen2(arr + 1); }

小白大坑 递归里面绝对不能写My_strlen2(arr++)。后置 ++ 是先把旧地址传进去,指针再往后走,永远访问同一个位置 → 死循环!只能写arr+1,代表传给下一层下一个字符的地址。

strlen 返回无符号数,不要写strlen(a)-strlen(b)<0。无符号数字永远 ≥ 0,永远不会小于零,判断失效。

推荐写法:if(strlen(a) < strlen(b)),避免减法。

2. strcpy 字符串拷贝

功能:把源字符串完完整整复制到目标数组,连看不见的结束符\0也要一起复制过去。

最简模拟实现

void My_strcpy(char* dest, char* src) { while (*dest++ = *src++); }

一步一步拆解循环:*dest = *src:把源当前字符赋值给目标位置 判断赋值完的值是不是\0,是就结束循环dest++、src++:两个指针同时向后挪一格

易错坑: 目标数组空间必须足够大!如果装不下源字符串 → 越界,程序直接崩溃。

3. strcat 字符串追加(拼接)

功能:找到目标字符串末尾看不见的\0,删掉这个\0,从这里开始把源字符串贴上去。

补充:目标数组必须本身自带\0,strcat 依靠目标原来的\0找到追加起点,没有\0会内存越界。

普通版本(❌不能自己追加自己 strcat (arr,arr))

void My_strcat(char* dest, char* src) { //第一步:指针一路走到dest末尾'\0'的位置 while (*dest) dest++; //第二步:开始拷贝字符串,连带\0 while (*dest++ = *src++); }

大白话解释:为什么自己拼接自己会翻车? 举个例子arr="abcde"一开始末尾有\0。刚开始拷贝第一个字符的时候,就直接把末尾\0覆盖掉了。源字符串和目标字符串是同一块空间,从此以后源字符串再也找不到结束标记\0,无限循环,程序卡死。

✅安全升级版(✅支持自己追加自己)

void My_strcat_pro(char arr[], char d[]) { //第一步:先把源字符串备份一份到临时数组,保护原字符串 char temp[1000]; int i = 0; while (temp[i] = d[i]) i++; //第二步:指针走到目标字符串末尾 while (*arr) arr++; //第三步:从备份数组往目标空间追加 i = 0; while (*arr++ = temp[i++]); }

原理:先复制一份副本,副本不受破坏,追加的时候就不怕把\0覆盖掉。

4. strcmp — 字符串比较【新增】

功能:按 ASCII 码逐字符对比,遇到不同字符或者\0停止 原型:int strcmp(const char *str1, const char *str2);

  • str1 > str2 → 返回大于 0 的数
  • str1 == str2 → 返回 0
  • str1 < str2 → 返回小于 0 的数

大坑:不能用==直接比较字符串数组!if(arr1 == arr2)比较的是地址,不是里面字符!

模拟实现

int My_strcmp(const char* str1, const char* str2) { //两个字符相等且不是'\0',继续往后比 while(*str1 == *str2) { if(*str1 == '\0') //同时到末尾,字符串完全相等 return 0; str1++; str2++; } //返回差值(ascii相减) return *str1 - *str2; }

二、内存函数(memcpy、memmove)

大白话:内存函数根本不认识\0!它就是一台 “字节复印机”。不管里面存的是字符、int 整数、小数,只看你要求复制多少个字节。可以复制任意类型的数据。

1. memcpy 内存拷贝

原型:void* memcpy(void* destination, const void* source, size_t num);destination:目标地址;source:源地址;num:复制多少个字节

基础实现(标准原版,没有重叠保护)

void* my_memcpy(void* destination, const void* source, size_t num) { //空指针安全检查:传入无效地址直接返回 if (destination == NULL || source == NULL) { return NULL; } void* ret = destination; //保存起始地址,最后返回 //void*万能指针不能直接解引用,强制转为char*,按1字节操作 char* dest = (char*)destination; const char* src = (const char*)source; //从前往后一个字节一个字节复制 for (size_t i = 0; i < num; i++) { dest[i] = src[i]; } return ret; }

memcpy 致命短板:不能处理内存重叠 大白话比喻:两本有一部分重合的书,你从前往后抄。前面刚抄走的内容还没读完就被覆盖掉,读到后面内容就错了。两块内存区域有重合,复制结果出错。

考试要点:部分编译器库 memcpy 可能兼容重叠,但做题严格按 C 标准,重叠就必须使用 memmove

2. memmove 可重叠的安全内存移动

memmove = memcpy + 重叠判断。重叠也不会出错。

完整正确模拟实现

void* my_memmove(void* destination, const void* source, size_t num) { if (destination == NULL || source == NULL) { return NULL; } void* ret = destination; char* dest = (char*)destination; const char* src = (const char*)source; //判断重叠:目标地址落在源数据的范围内,并且目标在源后面 if (dest > src && dest < src + num) { //从后往前拷贝,先抄最后一个字节,防止内容被提前覆盖 for (size_t i = num; i > 0; i--) { dest[i - 1] = src[i - 1]; } } else { //无重叠,或者目标地址在源前面 → 正常从前向后复制 for (size_t i = 0; i < num; i++) { dest[i] = src[i]; } } return ret; }

复制方向口诀 目标地址 > 源地址 并且两块内存重叠 → 从后往前拷 剩下所有别的情况 → 从前往后拷

memcpy vs memmove vs strcpy vs strcat vs strcmp 完整对比表

表格

函数特点遇到 '\0' 是否停下重叠内存是否安全适用场景
strcpy字符串拷贝✅停下❌不安全只拷贝字符串
strcat字符串追加✅停下❌不能自追加字符串拼接
strcmp字符串逐字符比较✅停下-比较两个字符串内容
memcpy按字节拷贝❌不会停下❌出错两块完全分开、互不重合的内存
memmove安全字节拷贝❌不会停下✅安全不确定是否重叠 / 已知内存重叠

三、小白做题必背区分口诀

操作字符串,依靠看不见的结束标记\0停止 → strlen、strcpy、strcat、strcmp(字符串函数) 复制 int 数组、结构体,不在乎有没有\0,指定复制字节数量 → memcpy /memmove(内存函数) 两块复制区域有可能重合打架 → 用 memmove 自己拼接自己(strcat (arr,arr))→ 先用临时数组备份源字符串 字符串相等判断别用 ==,strcmp 才对!

刷题坑点汇总

  1. strlen不算\0;sizeof算上\0(例char arr[]="abc",strlen=3,sizeof=4)
  2. 内存函数拷贝单位是字节,拷贝 int 数组,num 参数要写元素个数 * sizeof(int)
  3. void*万能指针,不能解引用、不能自增,必须强转 char * 逐字节操作
  4. strcat 追加前提:目标数组有足够空间 + 目标字符串自带\0
  5. strlen 返回无符号数,减法比较长度会踩坑

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询