C语言常用字符串与内存处理函数底层实现解析
深入理解 C 语言核心库函数的内部机制,掌握 memcpy、memmove、strlen、strcpy、strcmp、strstr 与 strcat 的模拟实现。文章结合内存重叠等常见陷阱,提供多种算法思路(如递归、双指针)及完整代码片段。
一、内存拷贝:memcpy 与 memmove
memcpy 用于将 src 指向的内存区域向前拷贝到 dst,按字节操作,不涉及类型转换,遇到 "\0" 不会停止。由于它是简单的从左向右覆盖,当源地址与目标地址发生重叠时(即源起始地址低于目标起始地址),数据会被覆盖导致错误结果。此时应使用 memmove,它能智能处理内存重叠问题。
void *Mymemcpy(void *dst, const void *src, int len){
void *ret = dst;
assert(src);
assert(dst);
while (len--){
*(char *)dst = *(char *)src;
dst = (char *)dst + 1;
src = (char *)src + 1;
}
return ret;
}
int main(){
char str[100] = "ABCDE";
// 将第3个字符开始的2个字节覆盖到开头
Mymemcpy(str, str + 2, 2);
printf("%s", str);
return 0;
}
上述测试用例中,源字符串首地址 str+2 低于目标首地址 str,从左向右拷贝导致前两个字符被后续字符覆盖,产生意料之外的输出。
为解决此问题,引入 Mymemmove。当检测到来地址小于目标地址且存在重叠范围时,改为从右向左进行拷贝,从而保证数据不被意外覆盖。
二、memmove 的模拟实现
memmove 的核心在于判断地址重叠情况:if (_dst > _src && _dst < _src + len)。若满足条件,则从末尾开始倒序拷贝;否则保持正向拷贝。
void * Mymemmove(void *dst, const void *src, int len){
char *_src = (char*)src;
char *_dst = (char*)dst;
// 检查是否发生重叠且源在目标之前
if (_dst > _src && _dst < _src + len){
_dst = _dst + len - 1;
_src = _src + len - 1;
while (len--){
*_dst = *_src;
_dst--;
_src--;
}
} else {
while (len--){
*_dst = *_src;
_dst++;
_src++;
}
}
return dst;
}
三、strlen 长度计算的三种实现
第1步:计数器法
使用整型变量逐个遍历直到结束符,适用于基础教学场景。
int Mystrlen(char *str){
int count = 0;
while (*str != '\0'){
str++;
count++;
}
return count;
}
第2步:递归方式
利用递归调用自身,每次减一并加 1,直到遇到 '\0' 返回 0。
int Mystrlen(char *str){
if (*str == '\0') return 0;
else return (1 + Mystrlen(str + 1));
}
第3步:双指针相减法
记录起始指针,移动指针直至尾部,两者相减即为长度,效率高且符合 strlen 源码常见实现逻辑。
int Mystrlen(char *str){
char *p = str;
while (*p) p++;
return (p - str);
}
四、字符串复制 strcpy 的实现
strcpy 需要确保目标空间足够大,并在复制完毕后包含 '\0'。以下实现将源内容拷贝至目标并返回目标指针。
char *Mystrcpy(char *dst, const char *src){
assert(dst != NULL && src !=NULL);
char *ret = dst;
while((*dst++ = *src++) != '\0');
return ret;
}
五、字符串比较 strcmp 的实现
按字典序比较两个字符串,相同返回 0,前者大于后者返回正数,反之返回负数。代码中约定前者大返回 1。
int Mystrcmp(const char* dst, const char *src){
while (*dst && *src && (*dst == *src)){
dst++;
src++;
}
if (*dst > *src) return 1;
else if (*dst < *src) return -1;
else return 0;
}
六、子串查找 strstr 的实现
在长串 dst 中查找短串 src 首次出现的位置。采用双重循环,外层遍历目标串,内层逐一比对。
char *mystrstr( const char *dst, const char *src){
assert(dst);
assert(src);
const char *p = dst;
while (*p){
const char *movep = p;
const char *sp = src;
while(*movep && *sp && *sp== *movep){
sp++;
movep++;
}
if (*sp == '\0') return (char *)p;
p++;
}
return NULL;
}
七、字符串拼接 strcat 的实现
将 src 追加到 dst 末尾,需先找到 dst 的结束符位置再行写入。
char *mystrcat(char*dst, const char*src){
assert(src);
assert(dst);
char*ret = dst;
while (*dst) dst++;
while (*src){
*dst = *src;
dst++; src++;
}
return ret;
}
以上为C语言底层实现常用字符串与内存处理函数的详细内容,更多关于C语言库函数原理的资料请关注本站其它相关文章!
本站声明
本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。













