C语言常用字符串与内存库函数使用及模拟实现
C语言标准库提供了强大的字符串处理和内存操作接口,掌握这些库函数不仅有助于提升开发效率,更能通过模拟实现深入理解指针操作与内存模型。本文将逐一拆解 strlen、strcpy、strcmp、strcat、strstr、strtok 以及内存相关的 memcpy、memmove 等函数的原理与模拟代码,涵盖计数法、递归法及边界检查等关键实现细节。
字符串长度与拷贝:strlen 与 strcpy
第1步:理解并实现 strlen 计算字符串长度
strlen 返回字符串中 '\0' 之前的字符个数。模拟实现该函数有几种经典方法:
- 计数法:通过指针遍历直到遇到终止符。
int my_strlen(char* dest) { int count = 0; while (*dest) { count++; dest++; } return count; } - 指针减指针:记录起始位置,到达末尾后相减。
int my_strlen(char* dest) { char* arr = dest; while (*arr++) ; // 移动到结尾的'\0' return (arr - dest) - 1; // 减去最后的空字符偏移 } - 递归法:注意:递归版本在原文中存在逻辑错误(如参数传递不完整),在实际工程中应优先使用循环以实现栈安全。
第2步:掌握 strcpy 字符串拷贝
strcpy(destination, source) 将源串拷贝到目标空间,包含结束符 '\0'。使用前必须确保 destination 空间足够大且可写。
char* my_strcpy(char* dest, const char* str)
{
char* ret = dest;
while ((*dest++ = *str++) != '\0')
{
; // 空循环体,利用赋值表达式的副作用
}
return ret;
}
关键点:拷贝过程依赖赋值表达式返回值,当 '\0' 被复制后循环停止,确保目标串以 '\0' 结尾。
字符串比较与连接:strcmp 与 strcat
第3步:字符串字典序比较 strcmp
strcmp(str1, str2) 从左向右逐字符比较 ASCII 值:
- 若相等则继续;
- 遇到不同字符时,返回 str1[i] - str2[i];
- 若均为 '\0' 则返回 0。
int my_strcmp(const char* s1, const char* s2)
{
while (*s1 == *s2)
{
if (*s1 == '\0') return 0;
s1++; s2++;
}
return *(unsigned char*)s1 - *(unsigned char*)s2;
}
第4步:字符串拼接 strcat
strcat(dest, src) 会将 src 追加到 dest 的末尾(覆盖 dest 原有的 '\0')。务必保证 dest 有足够的剩余空间,防止缓冲区溢出。
char* my_strcat(char* dest, const char* src)
{
char* ret = dest;
while (*dest) dest++;
while ((*dest++ = *src++) != '\0');
return ret;
}
子串查找与分割:strstr 与 strtok
第5步:模式匹配 strstr
strstr 用于在主串中查找子串首次出现的位置并返回指针。其本质是比较窗口滑动,需小心处理指针越界与回溯问题。
排错提醒:原文给出的 my_strstr 实现中嵌套了 while(*dest==*str) 逻辑,这会导致指针跳过部分匹配位或无法正确重置游标。标准的 strstr 需要两个游标:主串游标和子串匹配游标,发现不匹配时主串游标回退是低效做法,通常采用 KMP 或双重循环(每轮不匹配时主串+1)。
第6步:分隔符拆分 strtok
strtok 是非线程安全的动态状态函数。第一次调用传入待拆分字符串,后续调用传 NULL 以获取下一段。
char buff[] = "www.example@qq.com";
char buf[50];
strcpy(buf, buff);
char* sep = ".@";
char* token = strtok(buf, sep);
while(token != NULL){
printf("%s\n", token);
token = strtok(NULL, sep);
}
内存块操作:memcpy、memmove 与 memcmp
第7步:处理内存重叠 memcpy vs memmove
memcpy 不考虑内存重叠,行为未定义。若目的地址与源地址存在重叠,必须使用 memmove,它内部会自动判断方向(从前向后或从后向前拷贝)以保证数据安全。
void* my_memmove(void* dest, void* src, size_t num)
{
assert(dest && src);
void* ret = dest;
if (dest < src || (char*)dest >= ((char*)src + num)) {
// 前向拷贝(无重叠或源在目的之后)
while (num--)
{
*(char*)dest = *(char*)src;
dest = (char*)dest + 1;
src = (char*)src + 1;
}
} else {
// 逆向拷贝(有重叠,防止源被覆盖)
while (num--)
{
*((char*)dest + num) = *((char*)src + num);
}
}
return ret;
}
第8步:二进制内存比较 memcmp
memcmp(ptr1, ptr2, num) 按字节逐个比较,遇到差异即返回差值,常用于结构体或整型数组的二进制对比,而非仅看数值大小。
字符属性分类判断
cctype 头文件中提供了诸多判断单字符性质的宏,使用时输入需为 unsigned char 或 EOF:
| 函数 | 功能描述 |
isalpha | 字母 (A-Z, a-z) |
isdigit | 数字 (0-9) |
isspace | 空白符 (空格, \t, \n 等) |
islower / isupper | 小写/大写英文字母 |
isxdigit | 十六进制字符 |
ispunct / isgraph / isprint | 标点 / 可见图形 / 全部可打印(含空格) |
以上就是C语言常用字符串与内存库函数使用及模拟实现的详细内容,更多关于C语言底层内存管理与字符处理的资料请关注本站其它相关文章!
免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。









