C语言核心字符串与内存函数详解及模拟实现

木白
木白
发布时间:2026-10-16 | 5人浏览过
原创

深入解析C语言中核心的字符串与内存操作函数,包括strlen、strcmp、strcpy、strcat、strstr以及memcpy、memmove和memcmp。文章不仅阐述了各函数的功能特性与安全使用规范,还通过手写模拟实现代码,剖析底层字节拷贝与地址越界问题,是理解C语言底层机制的实用指南。

一、核心字符串函数

C语言标准库提供了丰富的字符串处理工具,使用它们的前提是必须理解其内部机制,尤其是以 '\0' 作为结束标志的特性。

第1步:获取长度 - strlen

size_t strlen ( const char * str ) 用于计算字符串长度。其返回值为无符号整数 size_t,统计的是从起始地址到第一个 '\0' 之前的字符数量(不包含 '\0' 本身)。

关键注意点:

  • 传入的指针必须指向以 '\0' 结尾的有效字符串。
  • 由于返回类型是无符号类型,计算长度时若涉及减法运算需防止下溢。

模拟实现

size_t my_strlen(const char* str)
{ 
  size_t count = 0;
  while(*str) // 遇到 '\0' 时循环停止
  {
   str++;
   count++;
  }
  return count;
}

第2步:比较大小 - strcmp

int strcmp ( const char * str1, const char * str2 ) 从左至右逐个比较两个字符串的 ASCII 码值,直到发现不相等的字符或其中一个字符串结束。

返回值规则:

  • str1 > str2:返回大于 0 的值。
  • str1 = str2:返回 0。
  • str1 < str2:返回小于 0 的值。

模拟实现

int my_strcmp(const char* str1, const char* str2)
{
   while (*str1 == *str2)
   {
    if (*str1 == '\0') // 两者同时到达末尾,相等
     return 0;
    *str1++;
    *str2++;
   }
   // 此时 str1 != str2,直接返回差值
   return *str1 - *str2;
}

第3步:拷贝字符串 - strcpy

char* strcpy(char * destination, const char * source) 将源字符串连同末尾的 '\0' 一起复制到目标空间,并返回目标字符串的起始地址。

安全约束:

  • 目标空间必须足够大,足以容纳源字符串。
  • 目标空间必须是可修改的左值(如数组,而非指针常量)。

模拟实现

char *my_strcpy(char *dest, const char*src)
{ 
 char *ret = dest;
 while((*dest++ = *src++))
 {
  ; // 利用赋值表达式的返回值进行循环判断,包含复制 '\0'
 }
 return ret;
}

第4步:追加字符串 - strcat

char * strcat ( char * destination, const char * source ) 将源字符串追加到目标字符串后面。它会先找到目标字符串末尾的 '\0',然后开始覆盖写入源字符串内容(包含最后的 '\0')。

约束:目标空间必须有足够的剩余空间,且必须可修改。

模拟实现

char* my_strcat(char* dest, const char* src)
{ 
 // 定位到dest末尾的 '\0'
 char* start = dest;
 while (*dest) dest++;
 // 开始追加
 while ((*dest++ = *src++) != '\0') { 
   ; 
 }
 return start;
}

第5步:查找子串 - strstr

char * strstr ( const char * str2, const char * str1 ) 在 str2(母串)中查找 str1(子串)。若找到,返回子串在母串中的首地址;否则返回 NULL。

**注意**:该算法为暴力匹配,时间复杂度较高,但在日常使用中已足够应对多数场景。

模拟实现

char* my_strstr(const char* haystack, const char* needle)
{
 if (!*needle) return (char*)haystack; // 空串是任意串的子串

 const char* ret1 = haystack;
 while (*ret1)
 {
  const char* cp = ret1;
  const char* ret2 = needle;
  // 逐字符匹配
  while (*cp && *ret2 && *cp == *ret2) { 
      cp++; ret2++; 
  }
  if (!*ret2) return (char*)ret1; // 子串遍历完,匹配成功
  ret1++; // 失败则母串后移一位重试
 }
 return NULL;
}

二、内存操作函数

当需要处理非字符串的二进制数据或对象时,内存函数比字符串函数更通用。

第6步:内存复制 - memcpy

void * memcpy ( void * destination, const void * source, size_t num ) 负责从源内存地址复制 num 个字节到目标内存地址。它基于字节进行拷贝,不关心数据类型。

模拟实现:

void * my_memcpy(void * dst, const void * src, size_t count)
{
  void * ret = dst;
  char * d = (char *)dst;
  const char * s = (const char *)src;
  while (count--) {
    *d++ = *s++; // 按字节移动
  }
  return(ret);
}

第7步:安全内存复制 - memmove

memmove 同样复制 num 个字节,但设计初衷是为了处理源和目标内存区域重叠的情况。

为什么需要 memmove?
当使用 memcpy 对重叠区域(如数组向前或向后搬移)进行操作时,如果拷贝方向不当,可能会破坏尚未被拷贝的原始数据。

例如:将数组前面的部分搬到后面 memcpy(arr+2, arr, 16):
[1,2,3,4,5,6...] → 前两个字节被改写为 [1,2,1,2,3,4...],导致原本位于位置3,4的数据丢失。

对于这种情况,C语言提供了一个更安全的替代者 memmove。

memmove 的实现策略:根据源地址和目标地址的相对关系决定拷贝方向。

  • 若 dest < src:从前向后拷贝。
  • 若 dest >= src:从后向前拷贝(避免覆盖未读数据)。

模拟实现

void* my_memmove(void* dest, const void* src, size_t num)
{
 char* ret = (char*)dest;
 if ((char*)dest <= (const char*)src) {
  // 正常顺序拷贝(从前向后)
  while (num--)
  {
   *(char*)dest++ = *(char*)src++;
  }
 }
 else {
  // 逆序拷贝(从后向前),防止高地址数据被低地址覆盖
  char* d = (char*)dest + num - 1;
  const char* s = (const char*)src + num - 1;
  while(num--)
  {
   *d-- = *s--;
  }
 }
 return ret;
}

第8步:内存比较 - memcmp

int memcmp ( const void * ptr1, const void * ptr2, size_t num ) 比较两块内存的前 num 个字节。与 strcmp 类似,ptr1 对应的字节大于 ptr2 则返回正值,相等返回 0,小于返回负值。

三、总结与安全建议

掌握 C 语言字符串与内存函数,关键在于理解指针操作与内存布局。实际开发中需注意以下几点:

  • 缓冲区溢出:使用 strcpy、strcat 前务必确保目标空间足够大,优先使用 strncpy、strncat 等 safer 版本。
  • 重叠内存:只要涉及同一内存块的操作,一律优先选用 memmove。
  • 指针有效性:所有指针在使用前应确保非空,且指向合法的读写权限内存。

以上就是C语言核心字符串与内存函数详解及模拟实现的详细内容,更多关于C语言字符串与内存函数实操的资料请关注本站其它相关文章!

相关标签:

本站声明

本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。

Python 相关产品和应用

全部下载

专题列表