字符函数和字符串函数使用

目录

一、字符函数

1.1 字符分类函数

1.2 字符转换函数

二、字符串函数

2.1 strcpy

2.1.1 strcpy库函数的使用

2.1.2 strcpy库函数的模拟实现

2.2 strcat

2.2.1 strcat库函数的使用

2.2.2 strcat函数的模拟实现

2.3 strcmp模拟

2.4 strncpy、strncat和strncmp

2.4.1 介绍

2.4.2 strncpy模拟

2.4.3 与strcpy、strcat、strcmp比较

2.5 strlen 3种模拟

2.6 strstr

2.6.1 strstr库函数使用

2.6.2 strstr库函数的模拟

2.7 strtok库函数使用

2.8strerror函数使用


一、字符函数

1.1 字符分类函数

        用于字符分类的函数(都需要头文件ctype.h),这里我用isdigit来举例,他用来判断是否为十进制数字字符,如果是则返回数字字符那就会返回非零数,而要是其他字符只返回零,格式为int isdigit ((int c)里面是整型);

        代码展示:

#include<stdio.h>
#include<ctype.h>
int main()
{	
	int i = 0;
	const char* str = "abcd123";
	while (str[i])
	{
		if (isdigit(str[i]))
		{
			printf("%d ", str[i]-48);//打印字符数字
		}
		str++;
	}
}

        再举一个islower判断小写字符,格式和isdigit是一样的直接代码展示 

#include<stdio.h>
#include<ctype.h>
int main()
{
	int i = 0;
	const char* str = "abcTHCefg";
	while (str[i])
	{
		if (islower(str[i]))
		{
			printf("%c ",str[i]);
		}
		str++;
	}
		return 0;
}

        其他字符分类函数格式也是一样的,想使用哪个就可以使用,都是用来判断字符是否为数字、大写、小写这些,判断什么主要看后面英文单词。需要注意的是判断的是整型不能直接写成字符,只能通过字符转换为ascll值才能使用,一般解析时会解析为ascll值

1.2 字符转换函数

        字符转换函数c语言种只有2种一种是tolower、另一种就是toupper,这两个格式是一样的,头文件也需要ctype.h,格式为(int)tolower((int)同样的是整型)

        代码展示:

#include<stdio.h>
#include<ctype.h>
int main()
{
	const char* str = "aThJbtuiKHGJop";
	int i = 0;
	while (str[i])
	{
		printf("%c", toupper(str[i]));
		i++;
	}
	
	return 0;
}

二、字符串函数

2.1 strcpy

2.1.1 strcpy库函数的使用

        strcpy这个库函数用来拷贝字符串,需要头文件string.h,格式为strcpy(拷贝地址(指针),字符 串(变量也可以)),他会识别\0这个停止符号,拷贝地址大小也要包含\0这个大小,内部被拷贝的字符串不能为空,否则会报错。(使用前提拷贝地址大小一定要大于被拷贝的地址,并且必须拷贝地址是可以修改的地址)

        代码:

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

2.1.2 strcpy库函数的模拟实现

        strcpy的原理很简单就是将被拷贝内元素一个一个的转移到拷贝地址中,并将内部\0最后字符也拷贝过来,直接代码展示:

#include<stdio.h>
char* my_strcpy(char* dest,char* src)
{
	char* ret = src;//拷贝地址
	while (*src != '\0')//条件
	{
		*dest = *src;
		src++;
		dest++;
	}
	*dest = *src;//拷贝\0
	return ret;
}
int main()
{
	char str1[20];//拷贝
	char* str2 = "abcdef";//被拷贝
	char* ret = my_strcpy(str1, str2);
	printf("%s\n", ret);
	return 0;
}

2.2 strcat

2.2.1 strcat库函数的使用

        strcat这个库函数是用来拼接字符或字符串的,需要头文件string.h,格式为strcat(拼接的地址(指针),字符串(该字符串拼接到前面那个指针地址后面))(前提是拼接的地址是可以修改的,并且两边都需要有\0,空间也必须大

#include<stdio.h>
#include<string.h>
int main()
{
	char str1[20] = "abcdefgh";//拼接数组
	const char* str2 = "abcde";//被拼接数组
	strcat(str1, str2);
	printf("%s\n", str1);
	return 0;
}

2.2.2 strcat函数的模拟实现

        strcat库函数的底层就是将拼接的地址移动到\0开始拼接(包括\0),strcat(str1,str2)然后就是不断改变str1,代码展示:

#include<stdio.h>
char* my_strcat(char* dest, char* src)
{
	char* ret = dest;//拷贝起始地址
	while (*dest != '\0')//移动到\0
	{
		dest++;
	}
	while (*src != '\0')//拼接
	{
		*dest = *src;
		dest++;
		src++;
	}
	*dest = *src;
	return ret;
}
int main()
{
	char str1[20] = "abcde";//拼接到这
	char* str2 = "fghyz";//拼接过去
	char* ret = my_strcat(str1, str2);
	printf("%s\n", str1);
	return 0;
}

 

2.3 strcmp模拟

        首先我们要知道strcmp的底层原理,strcmp是用于比较字符串大小的,它是通过对比两个字符串中一个一个字符进行对比,实际就是对比ascll值,然后返回值就是大于0、小于0或者等于0,我们知道这个原理后就可以开始模拟使用这个函数了。

#include<stdio.h>
#include<assert.h>
int my_strcmp(const char* cmp1, const char* cmp2)
{
	assert(cmp1 && cmp2);//断言是否为空指针
	while (*cmp1 != '\0'&& *cmp2 != '\0' && *cmp1 == *cmp2)//条件
	{
		cmp1++;
		cmp2++;
	
	}
	return *cmp1 - *cmp2;//返回大小

}
int main()
{
	const char* str1 = "abcdefabcd";
	const char* str2 = "abcdefa";
	int ret = my_strcmp(str1, str2);
	if (ret > 0)
	{
		printf("str1 > str2\n");
	}
	else if (ret < 0)
	{
		printf("str1 < str2\n");
	}
	else
	{
		printf("str1 == str2\n");
	}
	return 0;
}

2.4 strncpy、strncat和strncmp

2.4.1 介绍

        strncpy、strncat、和strncmp这些库函数是在前面函数的基础上加了一个控制拷贝(拼接、对比)字节个数功能,其他功能不变。

2.4.2 strncpy模拟

        这里我只写一个模拟,其他模拟都是类似的,可以类比,首先我们要知道strncpy这个库函数底层,(char*)strncpy((char* dest),(char* src),(size_t num));可以知道返回值是一个指针,多了一个字节个数,接下来直接开始模拟

#include<stdio.h>
char* my_strncpy(char* dest, char* src,size_t num)
{
	char* ret = dest;//拷贝
	while (num--)//用字节来控制
	{
		*dest = *src;
		dest++;
		src++;
	}
	*dest = '\0';//主动加
	return ret;
}
int main()
{
	char str1[20];//目标
	char str2[] = "abcdef";//源
	char* ret = my_strncpy(str1, str2,4);
	printf("%s\n", ret);
	return 0;
}

2.4.3 与strcpy、strcat、strcmp比较

        如果是比较的话,可以通过strcpy和strncpy:

        strncpy相比strcpy更加安全(也是用于拷贝字符串),格式为strncpy(用于拷贝地址(指针),字符串,允许复制的最大字符数)对于strncpy当用于拷贝的地址大小小于字符串大小时可以,这个函数会自动填充\0,大于等于时就不会将\0填充到拷贝地址内(这里大于等于是指单纯字符串不包括\0)。

        strcpy的优点:简单易用,只需要提供源字符串和目标字符串即可完成复制;自动在目标字符串末添加\0,确保字符串终止

        缺点:不检查目标字符串的大小,可能导致导致缓和区溢出:如果源字符串长度超过目标字符串大小,可能会导致未定义行为

        strncpy的优点:可以指定要复制的字符数,避免缓和区溢出的风险;可以手动控制目标字符串的终止符,增加了灵活性。

        缺点:如果源字符串长度小于指定的字符数,strncpy会在目标字符串中添加额外的\0,可能导致目标字符串过长;如果源字符串长度大于指定的字符串数,目标字符串可能不会以\0结尾,导致字符串未终止。

        同样的对于strcat和strcmp可以通过类比来比较。

2.5 strlen 3种模拟

        第一种通过循环寻找\0:

#include<stdio.h>
int my_strlen(const char* str)
{
	int count = 0;//计数
	while (*str != '\0')
	{
		count++;
		str++;
	}
	return count;
}
int main()
{
	const char str[] = "abcdef";
	int len = my_strlen(str);
	printf("%d\n", len);
	return 0;
}

        第二种通过指针减指针绝对值为元素个数:

#include<stdio.h>
int my_strlen( char* str1)
{
	 char* str2 = str1;//记录起始
	while (*str1 != '\0')
	{
		str1++;
	}
	return str1 - str2;//指针相减的绝对值为元素个数
}
int main()
{
	 char str[] = "abcdef";
	int len = my_strlen(str);
	printf("%d\n", len);
	return 0;
}

        第三种就是通过递归的思想,每一次的调用加一:

#include<stdio.h>
int my_strlen(char* str)
{
	if (*str == '\0')//递归的限制
	return 0;
	else
		return 1 + my_strlen(str + 1);

}
int main()
{
	char str[] = "abcdef";
	int len = my_strlen(str);
	printf("%d\n", len);
	return 0;
}

         以上运行的代码都是一样的全为6,所以这给我了启发,我们要善于多用几种方法去解决一道题。

        strlen返回值是size_t类型的,两个size_t类型相减也是size_t,而size_t类型是无符号的,所以使用时候要注意 

2.6 strstr

2.6.1 strstr库函数使用

        strstr库函数用来寻找是否有相同的字符串,格式为(char*)strstr(const字符串str1(比较),const字符串str2(寻找的))如果寻找到相同的字符串,那就会返回起始str1中str2的起始字符开始读取直到读到\0停止,如果没有找到则返回NULL空指针。

#include<stdio.h>
#include<string.h>
int main()
{
	char str1[] = "aabaceebcccabace";
	char str2[] = "bac";
	char* ret = strstr(str1, str2);
	printf("str1:%s\n", str1);
	printf("ret:%s\n", ret);
	return 0;
}

 

2.6.2 strstr库函数的模拟

        strstr(str1,str2)底层,就是通过一个一个比较字符,如果str1第一个与str2的第一个匹配失败那就换str1第二个进行比较,如果在途中匹配成功了就有三种情况了,第一种:就是一路匹配成功(这是最好情况),第二种就比较麻烦了,那就是中途又失败,那就str2还要返回到第一个数中,而str1要返回到刚开始第一个匹配成功的那个值然后加一,继续重新匹配第一个数,然后最后匹配成功(情况最复杂的),第三种就是匹配第二个的时候到达末尾了(也就是不相同情况)。很抽象,直接上图:

        接下来就好好分析我为什么这样子搞,前面两种情况是最好理解的,直接对第三种分析。第三种这我们arr1和arr2是不动的值(记录起始位置的),那么我们比较时就需要再设2个指针来指向地址,然后解析进行比较(这里我设置了s1(arr1),s2(arr1)这两个),在之前我们分析了在匹配到第二个时匹配失败了,我们的处理方式了,这里就是要找一个指针去记录第一个匹配成功的地方,那就是每一次匹配成功一次后用一个指针记录(这里我用的是cur记录),这里不只是要记录还需要跳过一个字符,进而在让s1退回到cur这个地址,这下思路就顺了,剩下的细节我都写在代码里面去了。

#include<stdio.h>
#include<assert.h>
const char* my_strstr(const char* arr1, const char* arr2)
{
	assert(arr1 && arr2);//判断是不是空指针
	const char* s1 = NULL;//用于arr1比较
	const char* s2 = NULL;//用于arr2比较
	const char* cur = arr1;//cur初始
	while (*cur)
	{
		s2 = arr2;
		s1 = cur;//返回
		while (*s1 == *s2 && *s1 != '\0')
		{
			s1++;
			s2++;
		}
		if (*s2 == '\0')
		{
			return cur;//返回
		}
		
		cur++;//
	}
	return NULL;
}
int main()
{
	const char arr1[] = "aabaceebcccabace";
	const char arr2[] = "cca";
	const char* ret = my_strstr(arr1,arr2);
	printf("%s\n", ret);
	return 0;
}

         

2.7 strtok库函数使用

        strtok这个库函数用来分隔符号(也就是字符)的函数,格式为(char*)strtok(char*str(需要拷贝),const char*sep(这个是需要分割的字符)),而对于strtok遇到sep内分割符号后就会将其改为\0,返回分割符号之前的str这个起始指针,当strtok遇到第一个为不是空指针时,那么就会寻找到分割符号将其改为\0,并在编译器中保留这个位置,当遇到第一个是空指针时,那么strtok这个就会按照上一个保留的位置开始,并跳过空指针,寻找下一个分割符号。代码如图

#include<stdio.h>
#include<string.h>
int main()
{
	char str1[] = "2133714913@qq.com";
	char str2[20];
	const char* sep = "@.";
	strcpy(str2, str1);
	char* ret1 =strtok(str2, sep);
	printf("%s", ret1);
	char* ret2 = strtok(NULL, sep);//上一个保留了位置
	printf("%s", ret2);
	char* ret3 = strtok(NULL, sep);//同上
	printf("%s", ret3);
	return 0;
}

        这样的代码是很糙的代码,只是方便理解,一般我们都是用循环写:

#include<stdio.h>
#include<string.h>
int main()
{
	char str1[] = "2133714913@qq.com";
	const char* sep = "@.";
	char str2[20];
	strcpy(str2, str1);
	char* p = NULL;
	for (p = strtok(str1, sep); p != NULL; p= strtok(NULL, sep))
        //   初始化                   判断         调整
	{
		printf("%s", p);
	}
	return 0;
}

2.8strerror函数使用

        strerror库函数是用来返回错误信息的地址,这个一般和errno这个全局变量一起使用,这里errno这个全局变量,又需要头文件errno.h一旦程序出现什么错误,errno就会有数字,然后strerror(errno)将错误数字的错误消息地址返回,然后用指针来接受,进而打印

#include<errno.h>
int main()
{
	FILE* pf = fopen("test.test", "r");
	//成功访问则返回非空指针
	//否则为空指针
	if (pf == NULL)
	{
		printf("%s\n", strerror(errno));
		return 1;
	}
	//perror("错误信息");
	//这个函数是用于直接设置名字,并且还能打印出对应的错误信息
	return 0;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值