当前位置: 首页 > news >正文

【C语言】字符函数的易错点及其模拟实现

在上一章为大家简单介绍了字符函数的种类和基础运用,语法。那么在本章为大家分享一些易错点和自己如何编写一个自定义函数来实现相同的作用。(点个关注呗)

一·strlen:计算字符串长度

1. 函数原型

size_t strlen(const char *str);

2. 核心功能

  • 计算从str指向地址到第一个'\0'的字符数

  • 不包含终止符'\0'本身

3. 使用示例

char s[] = "Hello";
printf("%zu", strlen(s)); // 输出5

 4.易错点

  • 未初始化指针:传入未初始化的指针导致段错误

  • 非字符串参数:传入没有'\0'结尾的字符数组

  • 修改const数据:错误使用非常量指针修改只读区字符串

  • 格式化输出:在使用 printf 函数输出 size_t 类型的值时,应使用 %zu 格式说明符,而不是 %d 或 %u。这是因为 %zu 是专门为 size_t 类型设计的格式说明符。

  • 由于 strlen 的返回值是 size_t 类型,这是一个无符号整数,因此在进行比较或算术运算时需要注意。例如,以下代码可能会导致意外的结果:
  •     if (strlen(x) - strlen(y) >= 0) {
            // 这个条件总是为真,因为 size_t 类型不可能是负数
        }

#include <stdio.h>
#include <string.h>
int main()
{
	char arr1[] = "abcdef";
	char arr2[] = "abcde";
	if (strlen(arr1) - strlen(arr2) > 0)//这里比较字符串的长度大小,无法直接比较,所以需要strlen函数。
	{
		printf("arr1>arr2\n");
	}
	else
	{
		printf("arr1 <= arr2\n");
	}
	return 0;
}

   5.模拟实现 

这里用递归的方法来实现。(还有计算器,指针-指针)

函数是求字符串的长度的,我们是从str指向的字符串中,统计\0之前的字符个数的
函数本身是不期望,修改str指向的字符串的
my_strlen("abcdef");
1 + my_strlen("bcdef")
1 + 1 + my_strlen("cdef")
1 + 1 + 1 + my_strlen("def")
1 + 1 + 1 + 1 + my_strlen("ef")
...
1 + 1 + 1 + 1 + 1 + 1 + my_strlen("");
a   b   c   d   e   f   0
递归

#include <assert.h>

size_t my_strlen(const char* str)
{
	assert(str != NULL);//断言输入的是正确的。
	if (*str == '\0')
		return 0;
	else
		return 1 + my_strlen(str+1);
}

int main()
{
	char arr[] = "abcdef";
	size_t len = my_strlen(arr);
	printf("%zu\n", len);

	return 0;
}

二.strcpy:字符串拷贝

1. 函数原型

char *strcpy(char *dest, const char *src);

2. 核心功能

  • src指向的字符串(包含'\0')拷贝到dest

  • 返回dest指针

3. 使用示例

char src[] = "Hello";
char dest[6];
strcpy(dest, src); // dest内容为"Hello\0"

4. 易错点

  • 缓冲区溢出:目标数组空间不足

  • 地址重叠:源与目标内存区域重叠导致未定义行为

  • 忘记终止符:手动实现时漏拷贝'\0'

5. 模拟实现

1.

char *my_strcpy(char *dest, const char *src)
 {
    char *ret = dest;
    while((*dest++ = *src++)); // 包含'\0'的拷贝
    return ret;
}

2.

char* my_strcat( char* dest,  char* src)
{
    //assret(dest != NULL);
    char* ret = dest;
   
    while (*dest++ = *src++)//1.数据的拷贝 2.拷贝完\0 循环停止
    {
        ;// 这里是一个空语句
    }
    return ret;//返回的是目标空间的地址
}
int main()
{
    char e1[] = "qwerti";
    char e2[20] = "hhhhhhhhhhhh";
    my_strcat(e2, e1);
    printf("%s", e2);
    return 0;
}

 

三.strcat :字符串拼接

1. 函数原型

char *strcat(char *dest, const char *src);

2. 核心功能

  • src字符串追加到dest末尾(覆盖原'\0'

  • 返回dest指针

3. 使用示例

char str[20] = "Hello";
strcat(str, " World!"); // 结果:"Hello World!\0"

4. 易错点

  • 缓冲区溢出:目标剩余空间不足,目标空间一定要大

  • 未初始化目标:目标字符串没有正确初始化

  • 多次拼接忘记重置:重复使用导致意外结果

5. 模拟实现

*dest 等价于 *dest != '\0''\0'的ASCII值为0,即逻辑假)) 

char* my_strcat(char* dest, const char* src) 
{
    char* ret = dest;
    // 定位到dest结尾
    while (*dest) dest++;
    // 执行拷贝
    while ((*dest++ = *src++));
    //或者是
    //while(*dest++ = *src++)
    //{
    //    ;
   // }
    return ret;
}
int main()
{
	char arr1[] = "hello";
	char arr2[] = "ge wei xiong di ";
	//stract(arr2, arr1);
	printf("%s",my_strcat(arr1, arr2));
	return 0;
}

 

四.strcmp:字符串比较 

1. 函数原型

int strcmp(const char *s1, const char *s2);

2. 核心功能

  • 按ASCII码值比较字符串内容

  • 返回值:

    • <0:s1 < s2

    • =0:s1 == s2

    • >0:s1 > s2

3. 使用示例

printf("%d", strcmp("apple", "banana")); // 输出负数

4. 易错点

  • 误解返回值:认为返回-1/0/1(负数表示小于,0表示等于,正数表示大于)

  • 比较非字符串:参数未以'\0'结尾

  • 忽略大小写:A(65)与a(97)会被认为不同

  • 比较内容:不是比较字符串长短,而是字符对应的ASCLL值

5. 模拟实现 

#include <assert.h>
int my_strcmp(const char* str1, const char* str2)
{
	assert(str1 && str2);

	while (*str1 == *str2)
	{
		if (*str1 == '\0')
			return 0;//相等
		str1++;
		str2++;
	}
	if (*str1 > *str2)
		return 1; //大于
	else
		return -1;//小于
}
int main()
{
	//abc\0
	//abc\0
	int r = my_strcmp("abcdef", "abq");
	if (r > 0)
		printf("abcdef > abq\n");
	else if(r == 0)
		printf("abcdef == abq\n");
	else
		printf("abcdef < abq\n");
	int w = my_strcmp("abr", "abq");
	if (w > 0)
		printf("abr > abq\n");
	else if (w == 0)
		printf("abr == abq\n");
	else
		printf("abr < abq\n");

	return 0;
}

通过这两个比较,可以清楚的理解比较的内容了吧。 

五.对比总结表

函数功能关键点风险点时间复杂度
strlen计算长度不包含'\0'非字符串输入O(n)
strcpy字符串拷贝包含'\0'的完整拷贝缓冲区溢出O(n)
strcat字符串连接覆盖原终止符目标空间不足O(n+m)
strcmp字符串比较ASCII值逐字符比较误解返回值含义O(n)

六.优化方案 

一、字符串拷贝函数组 

strcpychar* strcpy(char* dest, const char* src) 完全拷贝src到dest(含'\0')
strncpychar* strncpy(char* dest, const char* src, size_t n)  最多拷贝n个字符

关键区别

  • strncpy不会自动添加终止符,需手动保证:

    char buf[10];
    strncpy(buf, src, sizeof(buf)-1);
    buf[sizeof(buf)-1] = '\0'; // 强制终止

    经典错误案例

    // 错误:缓冲区溢出 规定的大小为5,实际输入大于5
    char dest[5];
    strcpy(dest, "HelloWorld"); // 崩溃!
    
    // 错误:未终止字符串 无\0
    char dest[10];
    strncpy(dest, "Hello", 5); // dest内容为'H','e','l','l','o',?,?,?,?,?

    二、字符串连接函数组

strcatchar* strcat(char* dest, const char* src)将src追加到dest末尾
strncatchar* strncat(char* dest, const char* src, size_t n)最多追加n个字符+自动补'\0'

安全用法公式

// 安全追加算法
size_t free_space = dest_size - strlen(dest) - 1; // 计算剩余可用空间
strncat(dest, src, free_space);

示例对比

// 危险操作
char buf[10] = "Hello";
strcat(buf, "World!"); // 需要11字节空间(溢出)

// 安全操作
char buf[10] = "Hello";
strncat(buf, "World!", sizeof(buf)-strlen(buf)-1); // 追加4字符+"\0"

三、字符串比较函数组

strcmpint strcmp(const char* s1, const char* s2)比较到任意字符串出现'\0'为止
strncmpint strncmp(const char* s1, const char* s2, size_t n)只比较前n个字符

七.结语

好嘞,本章就到此结束啦,感谢观看,代码不仅要多看,还要多敲。希望大家自己去实现一下模拟实现。

 

 

 

 

 

 

相关文章:

  • SQL在线格式化 - 加菲工具
  • WINDOWS 2019 2022 服务器安装了更新补丁 自动重启 分析
  • 第6章 与学习相关的技巧(鱼书)
  • (二)机器学习---常见任务及算法概述
  • 3.31 代码随想录第三十一天打卡
  • 第十章 VGA显示圆
  • # 使用 OpenCV 和神经网络实现图像风格化
  • AISEO中的JSON 如何部署?
  • 为 MinIO AIStor 引入模型上下文协议(MCP)服务器
  • kafka副本同步时HW和LEO
  • Linux驱动开发 中断处理
  • IP-PBX(IP专用交换机)
  • 《HarmonyOS Next开发实战:从零构建响应式Todo应用的基石》
  • 车载以太网网络测试-25【SOME/IP-报文格式-1】
  • RabbitMQ简单介绍和安装
  • OkHttp的拦截器是如何工作的?
  • 【Django】教程-7-分页,默认使用django的
  • LiteDB 数据存储与检索效率优化的最佳实践指导
  • Linux内核内存管理 ARM32页表映射流程和案例分享
  • 华三交换机配置常用命令
  • 龙口做网站价格/网络推广是以企业产品或服务
  • 厦门百度整站优化服务/淘宝指数网址
  • 互联网趋势发展前景/网站关键词优化排名怎么做
  • 数据网站怎么做的/nba最新新闻
  • 邀请码网站怎么做/体验营销
  • 装置艺术那个网站做的好/脚本外链平台