C语言——字符和字符串函数

目录

前言

一、字符函数

二、strlen函数

2.1 strlen 函数使用 

2.2 模拟实现strlen函数

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

2.1strcpy函数

2.strcat函数

3.strcmp

三、长度受限制的字符串函数

1.strncpy

2.strncat

3.strncmp

四、字符串查找

1.strstr

2.strtok

3.strerror

五、总结


前言

在我们进行编程的过程中,我们经常要处理字符和字符串,为了⽅便操作字符和字符串,C语⾔标准库中提供了 ⼀系列库函数,使用字符函数和字符串函数分别包含头文件 <ctype.h>头文件<strling.h>。下面我就简单介绍一下常用的字符和字符串函数。
(本篇文章参考 cplusplus.com - The C++ Resources Network

一、字符函数

C 语言中有一系列的函数是专门做分类的,简单来说就是判断这个字符是属于什么类型的,而使用这些函数都需要包含一个 下面我们就简单介绍一下这些函数(可点击直接跳跃查看具体介绍)

函数

所给参数若符合下列的条件,返回真

iscntrl任何控制字符
isspace空白字符:空格' ',换页'\f',换行 '\n',回车 '\r',制表符 '\t' ,垂直制表符'\v'
isdigit十进制数字0~9
isxdigit十六进制数字,包括所有十进制数字,小写字母a~f,大写字母A~F
islower小写字母a~Z
isupper大写字母A~Z
isalpha字母a~z或A~Z
isalnum字母或者数字,a~z,A~Z,0~9
ispunct标点符号,任何不属于数字或者字母的图形字符(可打印)
isgraph任何图形字符
isprint任何可打印字符,包括图形字符和空白字符

这些函数的使用方法非常类似,且较为简单,这里就不介绍了,大家可以直接点击这个函数去具体了解。

二、strlen函数

2.1 strlen 函数使用 

strlen函数是用来求字符串长度的函数,返回 '\0' 之前字符的个数,不包含'\0'。size_t strlen ( const char * str ); strlen函数可以用来求字符串数组或者是字符串常量的长度,我们需要注意的是参数所指向的字符串必须要以'\0'结尾,不然所返回的值就是一个随机值,函数的返回值是size_t类型的,是为无符号。下面是使用代码

#include <stdio.h>
#include <string.h>

int main()
{
	char arr1[] = "csdn";//存放 'c' 's' 'd' 'n' '\0'共五个字符
	char arr2[] = { 'c','s','d','n','6' };//arr2数组中无'\0'
	char* p = "abcdef";
	printf("%d\n", strlen(arr1));//返回4,strlen不统计'\0',但是以'\0'为结束标志
	printf("%d\n", strlen(arr2));//返回值为随机值,每次运行结果都不一样
	printf("%d\n", strlen(p));//返回6

	return 0;
}

2.2 模拟实现strlen函数

结合前面我们已经学过的知识,我们可以有多种方式来模拟实现strlen函数。在模拟实现之前我们先来思考一下strlen函数的具体细节,首先,strlen函数是以'\0'为结尾的,返回的参数类型是size_t类型,传递的参数是一个指针类型,所以在使用之前我们要用assert函数来断言一下是否指向NULL,而使用assert函数要包含头文件<assert.h>,下面我就以三种方式来模拟实现streln函数:

主函数

#include <stdio.h>
#include <assert.h>


//函数调用


int main()
{
	char arr[] = "csdn666";
	size_t n = Strlen3(arr);
	printf("%zd\n", n);
	return 0;
}

方式一:计数器累加

//计数器累加
size_t Strlen1(const char* p)
{
	size_t count = 0;//计数器初始值为0
	assert(p != NULL);//断言所传递过来的地址是否为NULL
	while (*p)//所指向的不为'\0',进入while循环
	{
		p++;//遍历数组或字符串常量
		count++;//计数
	}
	return count;//返回计数器的值
}

方式二:递归

//不使用临时变量,递归
size_t Strlen2(const char* p)
{
	assert(p != NULL);
	if (*p == '\0')//直到遇到'\0'返回0
	{
		return 0;
	}
	else//否则就递归
	{
		return 1 + Strlen3(p + 1);//1+下一个字符的strlen函数
	}
}

方式三:指针相减

//指针相减
size_t Strlen3(const char* p)
{
	assert(p != NULL);
	char* p0 = p;//将初始地址赋值给p0
	while (*p)
	{
		p++;
	}//找到'\0'的地址
	return p - p0;//两个地址相减即为字符的个数
}

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

2.1strcpy函数

1. strcpy 函数

strcpy函数是字符串复制函数,char * strcpy ( char * destination, const char * source ); 其复制格式为将后一个source所指向的复制到前一个dest所指向的数组里,以 '\0' 为结束标志,会拷贝结束标志,函数最后返回dest的地址。需要注意的是,目标指向的应该为一个数组,允许修改,同时数组的大小应足够长,以确保能存放源字符串。

2. strcpy 函数的模拟实现

我们已经知道了strcpy函数是将一个字符串全部复制的另一个数组里,第一个参数是要复制到的地址,第二个参数是被复制的地址,复制过去的下标是从 0 开始的,从第一个字符开始复制,直到 '\0' ,一共有 n+1 个字符,所以所复制过去的数组的大小至少为 n+1 ,或者设置为足够大即可。这个函数的返回值为函数指针地址,那么在函数里面我们需要知道复制过去的函数的初始地址,下面是代码实现:

主函数:

#include <stdio.h>
#include <assert.h>

//Strcpy函数

int main()
{
	char arr1[] = "csdn";
	char arr2[10] = "666666666";
	Strcpy1(arr2, arr1);//目标空间必须是可以修改的,不可以指向常量
	printf("%s\n", arr2);
	return 0;
}

普通方式:

//基础,最简单的
char* Strcpy1(char* p2, char* p1)
{
	assert(p1 && p2);
	char* p = p2;
	while(*p1)
	{
		*p2 = *p1;
		p1++;
		p2++;
	}
	*p2 = '\0';
	return p;
}

优化后:

//进一步优化
char* Strcpy2(char* p2, char* p1)
{
	assert(p1 && p2);
	char* p = p2;
	while (*p1)
	{
		*p2++ = *p1++;//先解引用,赋值,再加加
	}
	*p2 = '\0';
	return p;
}

再优化

//再优化
char* Strcpy3(char* p2, char* p1)
{
	assert(p1 && p2);
	char* p = p2;
	while (*p2++ = *p1++)//做条件,当p2值为\0时,结束
	{
		;
	}
	return p;
}

运行结果:

可以看到当程序运行完后,arr2数组中的前5位都变了,其中arr2[4]的值为'\0',这证明了strcpy函数会一直复制,直到遇到'\0'结束,并将'\0'给复制过来。

2.strcat函数

1. strcat 函数

strcat函数是字符串追加函数,即在一个字符串的后面增添新的内容。其格式为char * strcat ( char * destination, const char * source );第一个参数为目标数组,第二个参数为源数组,返回类型为指针。要实现这个函数我们需要保证源字符串和目标字符串都必须以'\0'结束,这个可以直到从哪里开始追加,追加多少结束,同时还需要保证目标空间足够大,能够容纳源字符串的内容。

2. strcat 函数的模拟实现

通过上面的介绍,我们要实现strcat函数,首先要找到目标数组的结尾,然后将原数组开始从目标数组的'\0'位置开始复制追加,直到遇到源数组的'\0',然后返回目标数组的初始位置。下面我们就来实现这个函数:

#include <stdio.h>
#include <assert.h>

//两个函数追加,无法进行自我追加
char* Strcat(char* p1, const char* p2)
{
	char* p = p1;
	assert(p1 && p2);
	while (*p1)
	{
		p1++;
	}
	while (*p1++ = *p2++)
	{
		;
	}
	return p;
}

int main()
{
	char arr1[20] = "csdn";
	char arr2[20] = "6666";
	Strcat(arr1, arr2);
	printf("%s\n", arr1);
	return 0;
}

运行结果:

3.strcmp函数

1. strcmp 函数

strcmp函数是字符串比较函数,用于比较两个字符串的大小。其格式为int strcmp ( const char * str1, const char * str2 );这两个参数是两个字符串的地址,返回的是一个int型的数字。将字符串 str1 与字符串 str2 进行比较。此函数比较这两个字符串的每一个字符,如果当前字符相等,则继续比较下一个字符,直至比较出结果,第⼀个字符串⼤于第⼆个字符串,则返回⼤于0的数字 ;如果第⼀个字符串⼩于第⼆个字符串,则返回⼩于0的数字;或者是遇到null,则两个字符串相等,返回0。

2. strcmp 函数的模拟实现

因为我们比较的字符串,所以在函数里直接比较字符串里每一个字符的大小即可,同时要注意字符串是否结束,我写出了两种方法,一种是普通的循环,另一种则采用了递归,下面是实现的代码:

#include <stdio.h>
#include <assert.h>

//普通模式
int Strcmp1(const char * p1,const char * p2)
{
	assert(p1 && p2);
	while (*p1 == *p2)
	{
		if (*p1 == '\0')
			return 0;
		p1++;
		p2++;
	}
	if (*p1 > *p2)
		return 1;
	else
		return -1;
}

//优化模式,递归
int Strcmp2(const char* p1, const char* p2)
{
	assert(p1 && p2);
	while (*p1 == *p2)
	{
		if (*p1 == '\0')
			return 0;
		p1++;
		p2++;
	}
	return *p1 - *p2;
}


int main()
{
	char arr1[] = "csdn66abc";
	char arr2[] = "csdn66aaa";
	int ret = Strcmp2(arr1, arr2);
	if (ret > 0)
	{
		printf("大于\n");
	}
	else if (ret == 0)
	{
		printf("等于\n");
	}
	else
	{
		printf("小于\n");
	}
	return 0;
}

三、长度受限制的字符串函数

1.strncpy函数

1. strncpy 函数

strncpy函数是一个字符串选择复制函数,和strcpy函数基本一样,但是这个函数多了一个参数,可以限制复制的字符的个数,其格式为char * strncpy ( char * destination, const char * source, size_t num );将源数字的的前num个字符复制到目标函数,如果在复制 num 个字符之前找到 C 字符串的末尾(由 null 字符表示),则 destination 将用零填充,直到总共写入 num 个字符。如果 source 的长度大于 num,则不会在目标函数的末尾追加 null 字符。因此,在这种情况下,destination 不应被视为以 null 结尾的 C 字符串(这样读取它会溢出)。

2. strncpy 函数的模拟实现

strncpy函数实现和strcpy函数非常类似,就不具体说了,直接上代码:

#include <stdio.h>
//             目的位置 从哪拷贝  拷贝个数
char* Strncpy(char* p2, char* p1, int n)
{
	char* ret = p2;
	int i = 0;
	//拷贝的个数过多,超过数组的个数,所以 != '\0'
	// 且拷贝数量小于数组数,条件即为i<n
	for (i = 0; p1[i] != '\0' && i < n; i++)
	{
		p2[i] = p1[i];
	}
	//在拷贝过程中不会拷贝'\0',需要手动拷贝
	if (i < n)
	{
		p2[i] = '\0';
	}
	return ret;
}

int main()
{
	char arr1[20] = "csdn6789";
	char arr2[20] = { 0 };
	char* ret=Strncpy(arr2, arr1, 4);
	printf("%s\n",ret);
	return 0;
}

2.strncat函数

1. strncat 函数

strncat函数是一个字符串选择追加函数,可以指定追加的个数,和strcat函数基本一样。其格式为​​​​​​​char * strncat ( char * destination, const char * source, size_t num );将源数组的前 num 个字符附加到目标数组,外加一个终止 null 字符。如果 source 中 C 字符串的长度小于 num,则仅复制终止 null 字符之前的内容。

2. strncat 函数的模拟实现

strncat函数的实现和strcat函数非常类似,就不具体说了,直接上代码:

#include <stdio.h>
//             目的位置 从哪拷贝  拷贝个数
char* Strncat(char* p2, char* p1, int n)
{
	//记录拷贝到的初始位置
	char* ret = p2;
	//找到'\0'的位置
	while (*p2!='\0')
	{
		p2++;
	}//此时p2所指向的位置就是arr2中'\0'的地址
	int i = 0;
	//for循环拼接,拼接的个数小于n个,且第n个不为'\0'
	for (i = 0; i < n && p1[i] != '\0'; i++)
	{
		p2[i] = p1[i];
	}
	//当所要拼接的字符串的个数小于n时,末尾手动赋值'\0'
	if (i < n)
	{
		p2[i] = '\0';
	}
	//返回拼接到的函数的初始地址
	return ret;
}


int main()
{
	char arr1[20] = "csdn";
	char arr2[20] = "123456";
	char* ret = Strncat(arr2, arr1, 6);//接收初始地址
	printf("%s\n", ret);//打印
	return 0;
}

3.strncmp函数

1. strncmp 函数

strncmp函数是字符串选择比较函数,可以限定比较字符串的个数。其格式为:​​​​​​​int strncmp ( const char * str1, const char * str2, size_t num );其实现过程是将字符串str1和str2的字符数进行比较,从第一个开始,如果相等则继续向下比较,直至字符不相等或者到达限定的个数,返回相应的结果。

2. strncmp 函数的模拟实现

strncmp函数的实现和strcmp函数非常类似,就不具体说了,直接上代码:

#include <stdio.h>
#include <assert.h>

//以null结尾的字符串 const修饰防止字符串被修改,进行保护
int Strncmp(const char* p1, const char* p2, int n)
{
	assert(p1 && p2);
	if (!n)   //n=0时,无字符要比,直接返回0
		return 0;
	while (--n && *p1 && *p2 == *p1) //当字符相等且不为’\0‘时比较下个字符
	{
		p2++;
		p1++;
	}
	return *p1 - *p2;//字符不相等时,采用递归相减
}

int main()
{
	char arr1[] = "csdn66a";
	char arr2[] = "csdn66b";
	int ret = Strncmp(arr1, arr2,8);
	if (ret > 0)
	{
		printf("大于\n");
	}
	else if (ret == 0)
	{
		printf("等于\n");
	}
	else
	{
		printf("小于\n");
	}
	return 0;
}

四、字符串查找

1.strstr函数

1. strstr 函数

​​​​​​​strstr函数是查找子字符串函数,是在一个字符串中查找是否有另一个字符串。其格式为const char * strstr ( const char * str1, const char * str2 );返回指向 str2 中第一次出现的 str1 的指针,如果 str2 不是 str1 的一部分,则返回一个 null 指针。匹配过程不包括终止 null 字符('\0'),但它会停止到此为止。

2. strstr 函数的模拟实现

strstr函数还是比较容易理解的,代码里面有注释,话不多说直接上代码

#include<stdio.h>
#include<string.h>

char* Strstr(const char* str1, const char* str2)
{
	const char* p = str1;//程序运行过程中会改变数组的地址,采用变量来进行计算
	const char* s2 = str2;
	const char* s1 = str1;
	if (str2 == NULL)//如果子字符串地址为空
	{
		return (char*)str1;//返回str1
	}
	while (*p)//当str1当前值不为'\0'时
	{
		s2 = str2;//每次循环之后都初始为str2的地址
		s1 = p;//s1同样
		while (*s1 != '\0' && *s2 != '\0' && *s1 == *s2)//解引用str1,str2不为0且相等
		{
			s1++;
			s2++;
		}
		if (*s2 == '\0')//若str2当前的值为0
		{
			return (char*)p;//返回从p地址开始往后的str1
		}
		p++;//p++,str1向后比较
	}
	return NULL;
}

int main()
{
	char arr1[10] = { "abcddEFgh" };
	char arr2[4] = { "bcd" };
	char* p = Strstr(arr1, arr2);
	if (p == NULL)
	{
		printf("找不到子字符串\n");
	}
	else
	{
		printf("%s\n", p);
	}
	return 0;
}

2.strtok函数

1. strtok 函数

strtok函数是将字符串拆分为标记函数,其格式为:char * strtok ( char * str, const char * delimiters );对此函数的一系列调用将str拆分为标记,这些标记是由分隔符中的任何字符分的连续字符序列。在第一次调用时,该函数需要一个 C 字符串作为 str 的参数,str的第一个字符用作扫描令牌的起始位置。在后续调用中,该函数需要一个 null 指针,并使用最后一个标记末尾之后的位置作为扫描的新起始位置。
为了确定标记的开头和结尾,该函数首先从起始位置扫描分隔符中未包含的第一个字符(该字符成为标记的开头)。然后从标记的开头开始扫描分隔符中包含的第一个字符,该字符成为标记的末尾。如果找到终止 null 字符,扫描也会停止。

strtok函数的第⼀个参数不为 NULL ,函数将找到str中第⼀个标记,strtok函数将保存它在字符串 中的位置。strtok函数的第⼀个参数为 NULL ,函数将在同⼀个字符串中被保存的位置开始,查找下⼀个标记。在对 strtok 的调用中找到 str 的终止 null 字符后,对此函数的所有后续调用(以 null 指针作为第一个参数)将返回 null 指针。
 

2. strtok 函数的使用

这个就不模拟实现了,直接上使用的代码

#include <stdio.h>
#include <string.h>

int main()
{
	char arr1[] = "1666888999@qq.com";
	char arr2[20] = { 0 };
	strcpy(arr2, arr1);
	const char* p = "@.";

	//采用for循环优化
	char* s = NULL;
	//利用for循环初始化值只执行一次
	for (s = strtok(arr2, p); s != NULL; s = strtok(NULL, p))
	{
		printf("%s\n", s);
	}
	return 0;
}

运行结果

3.strerror函数

1. strerror 函数

strerror函数是一个获取指向错误消息字符串的指针的函数,其格式为为:char * strerror ( int errnum );strerror函数可以把参数部分错误码对应的错误信息的字符串地址返回来。

在不同的系统和C语⾔标准库的实现中都规定了⼀些错误码,⼀般是放在 errno.h 这个头⽂件中说明 的,C语⾔程序启动的时候就会使⽤⼀个全⾯的变量errno来记录程序的当前错误码,只不过程序启动 的时候errno是0,表⽰没有错误,当我们在使⽤标准库中的函数的时候发⽣了某种错误,就会讲对应 的错误码,存放在errno中,⽽⼀个错误码的数字是整数很难理解是什么意思,所以每⼀个错误码都是 有对应的错误信息的。strerror函数就可以将错误对应的错误信息字符串的地址返回。

2. strerror 函数的使用

这个就不模拟实现了,直接上使用的代码

#include <stdio.h>
#include <string.h>
#include <errno.h>

int main()
{
	FILE* pfile;
	pfile = fopen("unexit.txt", "r");
	if (pfile == NULL)
		//printf("错误是:%s\n", strerror(errno));
		perror("错误是");
	else
		printf("打开文件成功\n");
}

//常用错误序号
//0 : No error
//1 : Operation not permitted
//2 : No such file or directory
//3 : No such process
//4 : Interrupted function call
//5 : Input / output error
//6 : No such device or address
//7 : Arg list too long
//8 : Exec format error
//9 : Bad file descriptor
//10 : No child processes

运行结果

五、总结

以上就是今天的全部内容了,主要是介绍了一些字符和字符串相关的函数,种类还是挺多的,可以仔细看一看。如有不足欢迎家人们评论区批评指正,如果这篇文章对你有用的话,可以给我来个一键三连嘛

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

根本学不会_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值