【C语言基础】:字符函数和字符串函数

文章目录

    • 一、字符函数
      • 1. 字符分类函数
      • 2. 字符转化函数
    • 二、字符串函数
      • 1. strlen函数的使用和模拟实现
        • strlen函数的使用
        • strlen函数的模拟实现
      • 2. strcpy函数的使用和模拟实现
        • strcpy函数的使用
        • strcpy函数的模拟实现
      • 3. strcat函数的使用和模拟实现
        • strcat函数的使用
        • strcat函数的模拟实现
      • 4. strcmp函数的使用和模拟实现
        • strcmp函数的使用
        • strcmp函数的模拟实现

一、字符函数

1. 字符分类函数

C语言中有一系列的函数是对字符进行分类的,就是对判断一个字符属于什么类型的字符,这类字符函数的使用都要包含一个头文件ctype.h

在这里插入图片描述
这些函数的使用方法非常类似,这里我们就只举一个例子。

 int islower ( int c );

在C语言中,islower是一个用于判断字符是否为小写字母的函数。该函数接受一个整数参数c,它应该是无符号字符或EOF(常量)。如果参数c是小写字母,则返回非零值(真);否则返回0(假)。

【示例】将字符串中的小写字母转大写,其他字符不变。

#include<stdio.h>
#include<ctype.h>
int main()
{
	char str[] = "Test String.\n";
	int i = 0;
	char c;
	while (str[i])
	{
		c = str[i];
		if (islower(c))
			c -= 32;  // 小写字母的ASCII码值减去32就等于它对应的大写字母的ASCII码
		putchar(c);
		i++;
	}
	return 0;
}

在这里插入图片描述

2. 字符转化函数

C语言提供了2个字符转换函数:

int tolower ( int c ); //将参数传进去的⼤写字⺟转⼩写 
int toupper ( int c ); //将参数传进去的⼩写字⺟转⼤写

在上面的示例中,我们将小写转大写,是-32完成的效果,有了转换函数,就可以直接使用 tolower 函
数。

#include<stdio.h>
#include<ctype.h>
int main()
{
	char str[] = "Test String.\n";
	int i = 0;
	char c;
	while (str[i])
	{
		c = str[i];
		if (islower(c))
			c = toupper(c);
		putchar(c);
		i++;
	}
	return 0;
}

在这里插入图片描述

二、字符串函数

1. strlen函数的使用和模拟实现

函数原型:

size_t strlen ( const char * str );
  • 字符串以 ‘\0’ 作为结束标志,strlen函数返回的是在字符串中 ‘\0’ 前⾯出现的字符个数(不包含 ‘\0’ )。
  • 参数指向的字符串必须要以 ‘\0’ 结束。
  • 注意函数的返回值为 size_t,是无符号的( 易错 )
  • strlen的使用需要包含头文件
  • 学会strlen函数的模拟实现
strlen函数的使用

计算字符串的长度

#include<stdio.h>
#include<string.h>
int main()
{
	char str1[] = "abcdef";
	size_t len = strlen(str1);
	printf("%zu\n", len);
	return 0;
}

在这里插入图片描述

strlen函数的模拟实现

方法一:计数器的方式实现

#include<stdio.h>
#include<assert.h>
int my_strlen(const char* str)  // const修饰,使其不能被修改
{
	int count = 0;
	assert(str);  // 断言,避免传入空指针
	while (*str)
	{
		count++;  // 进入循环,说明不为空
		str++;
	}
	return count;
}
int main()
{
	char str1[] = "abcdef";
	int len = my_strlen(str1);
	printf("%d\n", len);
	return 0;
}

在这里插入图片描述
方法二:递归实现

#include<stdio.h>
#include<assert.h>
int my_strlen(const char* str1)
{
	assert(str1);   // 断言,避免传入空指针
	if (*str1 == '\0')
		return 0;  // 等于'\0',说明字符串结束,直接返回
	else
		return 1 + my_strlen(str1 + 1);
}
int main()
{
	char str1[] = "abcdef";
	int len = my_strlen(str1);
	printf("%d\n", len);
	return 0;
}

在这里插入图片描述
方法三:指针 - 指针的方式实现

#include<stdio.h>
int my_strlen(char* s)
{
	char* p = s;
	while (*p != '\0')
		p++;
	return p - s;
}
int main()
{
	int len = my_strlen("abcdef");
	printf("%d\n", len);
	return 0;
}

在这里插入图片描述

2. strcpy函数的使用和模拟实现

函数原型:

char* strcpy(char * destination, const char * source );

将source指向的C字符串复制到destination指向的数组中,包括结束的null字符(并在该点停止)。

strcpy函数的使用

将str1中的内容拷贝到str2中去

#include<stdio.h>
#include<string.h>
int main()
{
	char str1[] = "hello world";
	char str2[20] = { 0 };
	strcpy(str2, str1);  // 将str1中的内容拷贝到str2中去
	printf("%s\n", str2);
	return 0;
}

在这里插入图片描述
注意:这里str2的空间必须得能够装下str1中的内容,也就是str2的空间要足够大

strcpy函数的模拟实现

在模拟实现之前,首先我们要了解strcpy的实现原理,只有这样才会更加方便我们去模拟实现。那么,strcpy的实现原理是怎样的呢?
这里我们根据上面的代码进行修改再调试一下:

#include<stdio.h>
#include<string.h>
int main()
{
	char str1[] = "hello world";
	char str2[20] = "xxxxxxxxxxxxxxxxxx";
	strcpy(str2, str1);
	printf("%s\n", str2);
	return 0;
}

str1加上空格和字符串的结束标志 ‘\0’ 一共有12个字符,如果在str2中第12(下标为11)个字符也变成了 ‘\0’,那就说明是把str1中的 ‘\0’ 搬到了str2中。
在这里插入图片描述
事实证明strcpy的确是这样实现字符串拷贝的,所以我们在模拟实现时要一直将字符串拿到 ‘\0’ 才能结束。
注意

  • 源字符串必须以 ‘\0’ 结束。
  • 会将源字符串中的 ‘\0’ 拷贝到目标空间。
  • 目标空间必须足够大,以确保能存放源字符串。
  • 目标空间必须可修改。

接下来我们来一步一步模拟strcpy函数

void my_strcpy(char* dest, char* src)
{
	while (*src != '\0')  // 拷贝'\0'之前的内容
	{
		*dest = *src;
		dest++;
		src++;
	}
	*dest = *src;  // 拷贝'\0'
}

这样其实也能模拟实现,但这样的代码明显还有很多缺陷,还有很多优化的空间。

char* my_strcpy(char* dest, const char* src)
{
	assert(dest != NULL);
	assert(src != NULL);
	char* ret = dest;
	while (*dest++ = *src++)
		;
	return ret;
}

这是最终优化后的代码,大家看到这里可能会有点懵,别急,我们慢慢来:

  1. 首先为了确保安全,我们得判断传入进来的dest和src是否为空指针,所以这里要断言一下,一旦他们为空指针就直接报错。
  2. 其次,为了确保src不被修改,可以用const进行修饰。在while循环*dest++ = *src++作为判断条件,这里因为++的优先级高于 * ,但他是后置++,先使用再自增,所以也就是先解引用再++。
  3. 第一次判断会将src中的第一个字符给dest,因为while循环里的是空语句,执行了也不会有任何效果,然后就这样一直判断,一直将src中的字符给到dest,知道将’\0’给到dest,这时whlie循环括号里的表达式为0,跳出循环,但src中包括’\0’全部给到了dest。
  4. 因为原strcpy函数的返回值是char * 类型的,我们这里为了模拟也改成char * 类型的,原本我们是要返回dest的,但由于在while循环里面dest已经后置++不在指向首地址,所以在这之前我们先用一个指针ret来存放dest的首地址,最后我们直接返回ret就行了。
#include<assert.h>
#include<stdio.h>
#include<ctype.h>
char* my_strcpy(char* dest, const char* src)
{
	assert(dest != NULL);
	assert(src != NULL);
	char* ret = dest;
	while (*dest++ = *src++)
		;
	return ret;
}
int main()
{
	char str1[] = "hello world";
	char str2[20] = "xxxxxxxxxxxxxxxxxx";
	my_strcpy(str2, str1);
	printf("%s\n", str2);
	char * ret = my_strcpy(str2, str1);
	printf("%s\n", ret);
	return 0;
}

在这里插入图片描述

3. strcat函数的使用和模拟实现

函数原型:

char * strcat ( char * destination, const char * source );

连接字符串
将原字符串的副本追加到目标字符串。destination中的结束null字符被source的第一个字符覆盖,并且在destination中由两者串联形成的新字符串的末尾包含一个空字符。

  • 源字符串必须以 ‘\0’ 结束。
  • ⽬标字符串中也得有 \0 ,否则没办法知道追加从哪⾥开始。
  • ⽬标空间必须有⾜够的⼤,能容纳下源字符串的内容。
  • ⽬标空间必须可修改。
  • 字符串⾃⼰给⾃⼰追加,如何?
strcat函数的使用

将arr2中的字符串追加到arr2后面去。

#include<stdio.h>
#include<string.h>
int main()
{
	// 注意数组空间大小,要足以容纳追加后的字符数量
	char arr1[20] = "hello ";  
	char arr2[] = "world";
	strcat(arr1, arr2);
	printf("%s\n", arr1);
	return 0;
}

在这里插入图片描述
注意:这里arr1的空间必须得能够装下arr2追加到arr1后中的内容,也就是arr1的空间要足够大。

strcat函数的模拟实现

和之前一样,在模拟实现之前我们先要了解strcat函数的实现原理。这里我们同样调试一下看看。
在这里插入图片描述
调试之后可以看到,追加的过程是从arr1中的 \0开始追加,但是arr2中的 \0并没有拷贝到arr1中。
根据strcat函数的实现原理我们来进行模拟实现:

#include<stdio.h>
#include<assert.h>
char* my_strcat(char* dest, const char* src)
{
	assert(dest && src);  // 断言判断传入的是否为空指针
	char* ret = dest;  // 记录dest的起始地址
	// 找到目标空间的\0
	while (*dest != '\0')
		dest++;
	// 拷贝追加
	while (*dest++ = *src++)
		;
	return ret;
}
int main()
{
	// 注意数组空间大小,要足以容纳追加后的字符数量
	char arr1[20] = "hello ";  
	char arr2[] = "world";
	// my_strcat(arr1, arr2);
	char* ret = my_strcat(arr1, arr2);
	printf("%s\n", arr1);
	printf("%s\n", ret);
	return 0;
}

在这里插入图片描述
和上面一样,调试之后我们知道被追加的字符串从 \0开始,但追加的字符串并不会将 \0给追加进来。

  1. 首先我们肯定要判断传入进来的指针是否为空指针,这里要断言一下,而且为了防止要追加的字符串被修改,我们要将它用const修饰一下。
  2. 因为被追加的字符串是从 \0开始追加的,所以我们在追加之前要将指针指向字符串结尾,这里用while循环判断,只要不是\0我们就加一,直到指向字符串结尾。
  3. 这里就和strcpy的模拟一样了,也是在while循环的条件那里判断*dest++ = *src++,只要 *src没到\0,那么这个表达式的结果就不会为0,循环就还会继续,知道\0为止。
  4. strcat函数原型的返回值的char * 类型的,这里我们也返回char * 类型的,但要注意这里返回的是被追加字符串的起始地址,由于我们在实现追加的过程中将指针往后进行了偏移不在指向起始地址,所以我们要创建一个指针变量来记录被追加字符串的起始地址,最后返回这个创建的指针变量就行了。

4. strcmp函数的使用和模拟实现

函数原型:

int strcmp ( const char * str1, const char * str2 );

比较两个字符串
比较C字符串str1和C字符串str2。这个函数执行字符的二进制比较。
这个函数开始比较每个字符串的第一个字符。如果它们彼此相等,则继续执行以下对,直到字符不同或达到终止空字符为止。

  • 标准规定:
    ◦ 第⼀个字符串大于第⼆个字符串,则返回大于0的数字
    ◦ 第⼀个字符串等于第⼆个字符串,则返回0
    ◦ 第⼀个字符串小于第⼆个字符串,则返回小于0的数字
    ◦ 那么如何判断两个字符串? 比较两个字符串中对应位置上字符ASCII码值的大小。
strcmp函数的使用

比较三个字符串

#include<stdio.h>
#include<string.h>
int main()
{
	char arr1[] = "abcdef";
	char arr2[] = "abd";
	char arr3[] = "abcdef";
	int ret1 = strcmp(arr1, arr2);
	int ret2 = strcmp(arr1, arr3);
	int ret3 = strcmp(arr2, arr3);
	printf("%d\n", ret1);
	printf("%d\n", ret2);
	printf("%d\n", ret3);
	return 0;
}

在这里插入图片描述
在这里插入图片描述
可以看到,标准里面的返回值是一个大于或小于0的数,但VS的编译器直接定为1和-1,其他编译器可能是返回一个大于0或小于0的数。

strcmp函数的模拟实现
#include<stdio.h>
#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()
{
	char arr1[] = "abcdef";
	char arr2[] = "abd";
	char arr3[] = "abcdef";
	int ret1 = my_strcmp(arr1, arr2);
	int ret2 = my_strcmp(arr1, arr3);
	int ret3 = my_strcmp(arr2, arr3);
	printf("%d\n", ret1);
	printf("%d\n", ret2);
	printf("%d\n", ret3);
	return 0;
}

在这里插入图片描述
模拟后发现结果是一样的。

  1. 还是和上面一样,因为函数中我们只是比较字符串,不需要进行修改,所以要对其进行const修饰,而且为了避免传入空指针,要对其进行断言处理。
  2. while循环中进行条件判断,相等就进入循环,并自增,不相等跳出循环,跳出循环后又分两种情况,一种是 *str1 > *str2,直接返回1,*str1 < *str2,直接返回-1。
  3. 相等的情况只可能出现在while循环中,因为不相等就直接跳出循环了,一旦当 *str1 == \0,也就说明 *str2也等于\0了,直接返回0就行了。

注意:这只是在模拟VS编译器里的结果,模拟其他编译器上的结果更加简单,不相等时直接返回他们对应的ASCII码的差值就行了。

#include<stdio.h>
#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++;
	}
	return *str1 - *str2;

}
int main()
{
	char arr1[] = "abcdef";
	char arr2[] = "abs";
	char arr3[] = "abcdef";
	int ret1 = my_strcmp(arr1, arr2);
	int ret2 = my_strcmp(arr1, arr3);
	int ret3 = my_strcmp(arr2, arr3);
	printf("%d\n", ret1);
	printf("%d\n", ret2);
	printf("%d\n", ret3);
	return 0;
}

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/466104.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

鸿蒙Harmony应用开发—ArkTS声明式开发(容器组件:Grid)

网格容器&#xff0c;由“行”和“列”分割的单元格所组成&#xff0c;通过指定“项目”所在的单元格做出各种各样的布局。 说明&#xff1a; 该组件从API Version 7开始支持。后续版本如有新增内容&#xff0c;则采用上角标单独标记该内容的起始版本。 子组件 仅支持GridItem…

MasterAlign视觉对位软件提示系统校准时间错误解决方案

MasterAlign视觉对位软件提示系统校准时间错误解决方案 一、问题现象 当运行软件时弹出“系统校准时间错误”的提示&#xff0c;如下图&#xff1a; 出现“系统校准时间错误”提示&#xff0c;说明当前系统时间比上一次软件运行时的系统时间提前了&#xff0c;需要修改当前系…

Windows系统搭建web网站并结合内网穿透实现公网访问本地站点

文章目录 使用工具1. 本地搭建web网站1.1 下载phpstudy后解压并安装1.2 打开默认站点&#xff0c;测试1.3 下载静态演示站点1.4 打开站点根目录1.5 复制演示站点到站网根目录1.6 在浏览器中&#xff0c;查看演示效果。 2. 将本地web网站发布到公网2.1 安装cpolar内网穿透2.2 映…

苹果MacOS电脑使用内网穿透轻松远程桌面本地Windows系统电脑

文章目录 1. 测试本地局域网内远程控制1.1 Windows打开远程桌面1.2 局域网远程控制windows 2. 测试Mac公网远程控制windows2.1 在windows电脑上安装cpolar2.2 Mac公网远程windows 3. 配置公网固定TCP地址 日常工作生活中&#xff0c;有时候会涉及到不同设备不同操作系统之间需要…

JetBrains全家桶激活,分享PyCharm 2024 激活的方案

大家好&#xff0c;欢迎来到金榜探云手&#xff01; PyCharm 公司简介 JetBrains 是一家专注于开发工具的软件公司&#xff0c;总部位于捷克。他们以提供强大的集成开发环境&#xff08;IDE&#xff09;而闻名&#xff0c;如 IntelliJ IDEA、PyCharm、和 WebStorm等。这些工具…

RP2040 VSCode C/C++开发环境快速部署

RP2040 VSCode C/C开发环境快速部署 &#x1f4cc;安装参考《树莓派(Raspberry Pi) Pico VSCode C/C开发环境配置(无需Visual Studio)》&#x1f4cd;Windows环境下 MSYS2一键式部署pico程序包&#xff0c;下载地址&#xff1a;https://github.com/raspberrypi/pico-setup-wind…

简单使用NSIS打包软件

NSIS是一个开源的打包工具. 官网: Download - NSIS (sourceforge.io) 使用这个编译 ​ 但是不建议使用这玩意写脚本,字体太难看了.我用vscode写的脚本,用这个编译的. ​ 写好脚本用这个软件打开, 然后选择这个编译,如果语法有错误 会编译不过,会提醒你哪一行不行,如果编译…

探讨NLP对行业大量数据信息抽取的技术实现

在本文中&#xff0c;为了实现高效的信息抽取&#xff0c;我们采用了一个自主研发的多模态AI的大模型NLP平台。 这个平台的使用过程分为以下几个步骤&#xff1a; 数据收集&#xff1a;我们收集了与项目相关的100条数据样本&#xff0c;这些样本涵盖了各种商品描述&#xff0c…

一口气看完明朝276年历史

明朝是中国历史上最后一个由汉人建立的大一统封建王朝&#xff0c;建立于公元1368年&#xff0c;亡于公元1644年&#xff0c;国祚276年&#xff0c;传12世16帝。 太祖建国 太祖&#xff08;1368~1398&#xff09; 公元1368年&#xff0c;朱元璋在南京应天府建元称帝&#xff…

多行业预约小程序源码系统:单多门店一键切换 带完整的安装教程以及安装代码包

在当今数字化时代&#xff0c;小程序以其便捷、高效的特点&#xff0c;成为企业连接用户、提升服务体验的重要工具。下面&#xff0c;罗峰给大家分享一款多行业预约小程序源码系统&#xff0c;该系统支持单多门店一键切换&#xff0c;并附带完整的安装教程及安装代码包&#xf…

【日本語】N2考试湖北报名笔记

阅读资料 视频&#xff1a;JLPT报名技巧 使用浏览器调试模式快速报名&#xff1b; 1 报名流程 【考场选择】 1.1 春季报名&#xff1a;03-19 07:00:00 1.2 预习网站登录信息 1.3 登录验证码&#xff1a;06:55 &#xff08;图片来自视频《教日语的阿飞老师 - 担心能力考抢…

QY-02-W2 无线雨量监测站 防洪防汛 大坝水库雨水情实时监测

无线雨量监测站配置&#xff1a; 不锈钢支架、雨量传感器、太阳能板、数据采集发送器。 产品概述 无线雨量监测站是一款无线传输数据的雨量监测设备&#xff0c;由不锈钢支架、ABS雨量筒、不锈钢防护箱、主机采集器、无线数据发送装置、太阳能电池板、蓄电池等构成&#xff0c…

CSS基础笔记

第一课 CSS&#xff08;层叠式样式表&#xff09;&#xff1b;样式规则由 选择器、 属性 以及 属性值 组成 内联样式表、内嵌样式表、外部样式表 内联样式表 写在标签里 用 style 属性进行表示&#xff0c;优先级比 内嵌 和 外部 高 <h1 style"color: blue; text-…

java8:LinkedList的实现原理

概述 先来看看源码中的这一段注释&#xff0c;我们先尝试从中提取一些信息&#xff1a; Doubly-linked list implementation of the List and Deque interfaces. Implements all optional list operations, and permits all elements (including null).All of the operations …

ubuntu下摩尔线程s80配置ai绘图环境

首先我的桌面是gdm,然后安装github上的sdk&#xff0c;重启进不去桌面了 解决方法&#xff1a; 开机以后选ubuntu的高级选项&#xff0c;换旧一点的linux内核&#xff0c;然后卡在进程上&#xff0c;ctrlaltf2斤tty sudo apt remove musa 卸载完驱动就可以进系统了

Java SE 认识异常 (Java SE完结篇)

1. 异常的概念与体系结构 1.1 异常的概念 在我们的生活中,一个人如果表情痛苦,我们可能会问: 你是生病了吗? 需要我陪你去看医生吗? 程序也和人是一样的,均会发生一些"生病"的行为,比如: 数据格式不对, 数组越界,网络中断等, 我们把这种程序出现的"生病&qu…

ASO优化:App在App Store的权重影响因素

1.App的标题描述 App的标题、描述是能引导用户下载的重要部分&#xff0c;此处关键词占比的权重是最大的。比如说爱奇艺&#xff0c;最近主推的就是由任嘉伦、刑菲主演的《烈焰》。它就把主推的内容放在副标题处&#xff0c;获得很大的曝光量&#xff0c;娱乐榜直接排第一名了…

C语言学习笔记day8

一维数组冒泡排序法 1. 作用 将乱序的一维数组按照从小到大的顺序排列 2. 原理示意图 3. 代码 #include <stdio.h> #include <stdlib.h> #include <time.h>int main(void) {int a[5] {0};int len sizeof(a) / sizeof(a[0]);int i 0;int j 0;int tmp …

Vue工程化基础

一Ajax 1.1Ajax概述&#xff1a; 异步与同步 繁琐被淘汰了。 二Axios2 前后端混合开发&#xff1a; 前后端分离开发&#xff1a; YAPI 三前端开发工程化 四Vue脚手架 项目的认识 改变端口号 五Vue开发流程&#xff1a; 六Element组件 6.1快速入门 下载> npm install e…

Python数据分析-Matplotlib1

一、折线图的绘制 1.数据分析流程 2.运用Matplot绘制折线图 #encodingutf-8 import random from matplotlib import pyplot as plt #绘图工具库 from matplotlib import font_manager #解决中文显示问题 from cProfile import label #设置字体方式 my_font font_manager.Fon…