C语言常用字符串与内存函数详解及实现

周末不加班
周末不加班
发布时间:2026-10-16 | 4人浏览过
原创

C语言标准库提供了丰富的字符串与内存操作接口。理解这些函数的底层实现原理、参数约束及潜在风险(如缓冲区溢出、重叠内存处理),是编写高质量C代码的关键。本文将详细讲解`strlen`、`strcpy`等字符串函数及`memcpy`、`memmove`等内存函数的用法与核心逻辑。

长度不受限制的字符串函数

第1步:使用 strlen 获取字符串长度

目的:计算以 '\0' 结尾的字符串中字符的数量。
入口:#include <string.h>
动作:调用 size_t strlen(const char *str)。
关键参数:str 必须指向以 '\0' 结束的合法字符串。
完成状态:返回无符号整数,表示 '\0' 之前的字符个数。

注意:若字符串不含 '\0',函数将越界访问导致未定义行为。返回值类型为 size_t,参与算术运算时需注意符号问题。

第2步:使用 strcpy 进行字符串复制

目的:将源字符串完整复制到目标缓冲区。
入口:char* strcpy(char *dest, const char *src)
动作:src 指向的内容被逐字节拷贝至 dest,包含终止符 '\0'。
关键约束:
1. dest 空间必须足够大以容纳 src(含 '\0')。
2. dest 必须是可修改的左值。
3. src 必须以 '\0' 结束。

char * strcpy(char *dest, const char*src)
{ 
 char *ret = dest;//记录下字符串dest的起始地址
 assert(dest != NULL);
 assert(src != NULL);
 while((*dest++ = *src++))//copy
 {
  ;
 }
 return ret;//返回起始地址
}

第3步:使用 strcat 拼接字符串

目的:将源字符串追加到目标字符串末尾。
入口:char* strcat(char *dest, const char *src)
动作:找到 dest 的 '\0' 位置,从该处开始拷贝 src 的内容(包括 src 自身的 '\0')。
关键约束:dest 必须有足够剩余空间;src 不得覆盖 dest 自身有效内容的前段(通常要求非重叠)。

char * strcat(char *dest, const char*src)
{
 char *ret = dest;
 assert(dest != NULL);
 assert(src != NULL);
//找到目标空间
 while(*dest)
 {
  dest++;
 }
//拷贝
 while((*dest++ = *src++))
 {
  ;
 }
 return ret;
}

第4步:使用 strcmp 比较字符串

目的:按字典序比较两个字符串。
入口:int strcmp(const char *s1, const char *s2)
动作:逐字符比较 s1 和 s2,直到字符不同或遇到 '\0'。
结果判断:
- 返回 >0:第一个不同字符中 s1 的值大于 s2。
- 返回 0:两字符串相等。
- 返回 <0:第一个不同字符中 s1 的值小于 s2。

int strcmp(const char* st1, const char* st2)
{
	int ret = 0;
	while (*st1 == *st2)
	{
		st1++;
		st2++;
		if(*st1 == *st2 && *st1 == '\0')
			return ret;//相等的时候返回0
	}
	return *st1 - *st2;
}

长度受限制的字符串函数

上述函数存在缓冲区溢出风险,标准库提供了带长度限制的安全变体:

  • strncpy:strncpy(char *dest, const char *src, size_t n)。最多拷贝 n 个字符。若 src 长度小于 n,dest 剩余部分将用 '\0' 填充。注意:strncpy 不保证 dest 以 '\0' 结尾(除非 n 大于 src 长度),需手动检查。
  • strncat:strncat(char *dest, const char *src, size_t n)。最多从 src 拷贝 n 个字符追加到 dest,并自动添加终止符 '\0'。
  • strncmp:strncmp(const char *s1, const char *s2, size_t n)。仅比较前 n 个字符,若未提前结束则继续比较直至发现差异或到达 n。

字符串查找与分割函数

第5步:使用 strstr 查找子串

目的:在字符串中寻找首次出现的子串。
入口:char* strstr(const char *haystack, const char *needle)
动作:返回指向 haystack 中第一次出现 needle 位置的指针;若未找到则返回 NULL。
逻辑:遍历主串,尝试匹配子串起始点。

char* strstr(const char* st1, const char* st2)
{
	//st1,st2标注起始位置
	char* s1 = st1;
	char* s2 = st2;
	char* cur = s1;
	while (*cur)
	{
		s1 = cur;
		while (*s1 == *s2 && *s1 && *s2)
		{
			s1++;
			s2++;
		}
		if (*s2 == '\0')
		{
			return cur;
		}
		cur++;
	}
	return NULL;//找不到
}

第6步:使用 strtok 分割字符串

目的:根据分隔符集合将字符串分解为标记(Token)。
入口:char* strtok(char *str, const char *sep)
动作:
1. 首次调用传入待分割字符串 str。
2. 后续调用传入 NULL 以继续分割同一字符串。
3. 函数会修改原字符串,将分隔符替换为 '\0'。
4. 返回当前标记的指针,若无更多标记则返回 NULL。

注意:由于函数具有内部静态状态且修改输入,不可用于多线程环境,也不适用于常量字符串。

第7步:使用 strerror 获取错误信息

目的:将系统错误码转换为可读字符串。
入口:char* strerror(int errnum)
头文件:#include <errno.h>
动作:根据 errnum(通常由全局变量 errno 设置)返回对应的标准错误描述字符串。

内存操作函数

第8步:使用 memcpy 复制内存块

目的:通用内存区域的数据拷贝。
入口:void* memcpy(void *dest, const void *src, size_t n)
动作:从 src 位置向后复制 n 个字节至 dest。
关键区别:不识别 '\0',严格按字节数拷贝。
风险:若源和目标内存区域重叠,结果未定义。此类场景应使用 memmove。

void* memcpy(void* dest, const void* src, size_t sz)
{
	assert(dest && src);
	void* ret = dest;
	size_t count = sz;
	while (count--)
	{
		*(char*)dest = *(char*)src;//拷贝
		dest = (char*)dest + 1;
		src = (char*)src + 1;
	}
	return ret;
}

第9步:使用 memmove 处理重叠内存

目的:安全地复制可能重叠的内存区域。
入口:void* memmove(void *dest, const void *src, size_t n)
逻辑:检测源和目标的重叠关系。若发生重叠且目标起始地址高于源起始地址,则从后向前拷贝以防止数据覆盖;否则从前向后拷贝。

void* memmove(void* dest, const void* src, size_t sz)
{
	assert(dest && src);//断言
	void* ret = dest;
	size_t count = sz;
	//判断是否重叠及方向
	if ((char*)dest > (char*)src && (char*)dest < (char*)src + count)
	{
		//后->前拷贝,防止覆盖未读取的源数据
		while (count--)
		{
			*((char*)dest + count) = *(char*)src + count;
		}
	}
	else
	{
		//前->后拷贝
		while (count--)
		{
			*(char*)dest = *(char*)src;
			dest = (char*)dest + 1;
			src = (char*)src + 1;
		}
	}
	return ret;
}

第10步:使用 memcmp 比较内存块

目的:比较两块内存区域的内容。
入口:int memcmp(const void *ptr1, const void *ptr2, size_t n)
动作:比较 ptr1 和 ptr2 前 n 个字节。
结果:同 strcmp,返回差值指示大小关系。

以上就是C语言字符串函数和内存函数详解的详细内容,更多关于C语言底层内存操作技巧的资料请关注本站其它相关文章!

相关标签:

本站声明

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

Python 相关产品和应用

全部下载

专题列表