字符函数与字符串函数

在之前我们已将学习过printf,scanf等库函数,在编程的过程中,我们经常要处理字符和字符串,为了⽅便操作字符和字符串,C语⾔标准库中提供了一系列库函数,现在在本篇中将继续学习字符函数和字符串函数的使用方法,以及试着模拟这些一部分字符串函数的实现


1.字符分类函数

语言中有⼀系列的函数是专门做字符分类的,也就是判断⼀个字符是属于什么类型的字符的。
这些函数的使用都需要包含一个头文件是 ctype.h

这些函数的使用都十分的相似,都是通过返回值来说明是否是相应的字符,如果是相应的字符就返回非0的整数,如果不是相应的字符,则返回0

练习:

写一个代码,将字符串中的小写字母转写,其他字符不变。

#include<stdio.h>
#include<ctype.h>
int main()
{
	char arr[] = "You Are Right";
	int i = 0;
	for (int i = 0; arr[i] != '\0';i++)
	{
		if (islower(arr[i]))
		{
			arr[i]-= 32;
		}
	}
	printf("%s", arr);

	return 0;
}

 

 2. 字符转换函数

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

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

所以在以上代码中就可以使用字符转换函数来替代arr[i]-= 32;

#include<stdio.h>
#include<ctype.h>
int main()
{
	char arr[] = "You Are Right";
	int i = 0;
	for (int i = 0; arr[i] != '\0';i++)
	{
		if (islower(arr[i]))
		{
			arr[i]=toupper(arr[i]);
		}
	}
	printf("%s", arr);

	return 0;
}

3.strlen

之前已经详细的讲解过库函数strlen的功能以及使用,strlen是用来计算字符串长度的函数,统计的是字符串\0之前的元素个数,详细讲解在深入理解指针(5)

strlen的模拟实现:

在之前指针的相关章节中已经讲解了模拟实现strlen的两种方法

第一种是使用计数法实现模拟:

int my_strlen(const char * str)
{
 int count = 0;
 while(*str)
 {
  count++;
  str++;
 }
 return count;
}

第二种是使用指针-指针的方法实现:

int my_strlen(const char *s)
{
   char *p = s;
   while(*p != ‘\0’ )
       p++;
   return p-s;
}

在此以上两种方法都是创建了新的变量才实现模拟的,如果要求不创建新的变量我们应该如何去实现tsrlen的模拟呢?

int my_strlen(const char * str)
{
assert(str);
if(*str == '\0')
return 0;
else
return 1+my_strlen(str+1);
}

这时就需要用到函数递归的思想,递归中的限制条件就是当*ptr为\0时,且在递归中越来越接近这个限制条件


4.strcpy与strncpy

strcpy 

首先来了解库函数strcpy的作用是实现字符串的拷贝,将一个字符串的内容拷贝到另一个字符串中,调用该函数时需要的参数是源字符串的首元素地址以及拷贝目标字符串的首元素地址 。且调用strcpy时是将源字符串中包含\0和\0之前的字符全部拷贝到目标空间

注:在使用strcpy时有几个需要注意的点:
       •1.目标空间必须足够大 
       •2.源字符串必须以 '\0' 结束
       •3.目标空间必须可修改

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

例如在以上代码中使用strcpy使得字符串str1拷贝到str2中,就会将str1中的 a b c d \0五个元素都拷贝到数组str2中

最终打印输出结果就为abcd

模拟实现strcpy

在了解了库函数strcpy的使用方法与作用我们就可以来试着模拟strcpy的实现

#include<assert.h>
char* my_strcpy(char* dest, const char* src)
{
	assert(dest!=NULL && src!=NULL);
	char* str = dest;
	while (*src != '\0')
	{
		*dest = *src;
		dest++;
		src++;
	}
	 *dest=*src ;
	 return str;
}

 以上代码有什么可以简化的呢?
1.在上面的代码中asser断言部分指针不为空其实可以直接将后面的!=NULL部分省略,因为当指针为空时assert后括号内就会为假就会报错,这和省略之前所实现的功能是一样的
2.可以在*dest和*src两个直接++,变成*dest++=*src++
3.当源字符串指针解引用为\0时候,会跳出while循环再将\0赋给*dest,其实可以直接把\0这一情况也包含在while循环内,所以在while判断部分就改写为*dest++=*src++

改写后的模拟实现代码 :

#include<assert.h>
char* my_strcpy(char* dest, const char* src)
{
	assert(dest && src);
	char* str = dest;
	while (*dest++ = *src++)
	{
		;
	}
	 return str;
}

strncpy 

在学习了strcpy之后再来了解一个库函数strncpy

 首先来了解strncpy的参数和功能
 在以上形参部分可以看到strncpy的参数前两个都与strcpy相同,但strncpy多了一个size_t num的参数,那么这个参数表示的是什么呢?

其实num表示的是调用strncpy时需要从源空间串中拷贝的字符的个数

因此我们就可以知道了strncpy的功能就是指定拷贝多少个字符到目标空间中
注:在使用strncpy时有几个需要注意的点:
        1.目标空间必须足够大 
        2.源字符串必须以 '\0' 结束
        3.⽬标空间必须可修改
        4.如果源字符串的长度小于num,则拷贝完源字符串之后,在目标的后边追加0,直到nu个

以下代码就是使用strncpy将str1中的前三个字符拷贝到str2中

#include<stdio.h>
#include<string.h>
int main()

{
	char str1[] = "abcd";
	char str2[20] = "xxxxxxx";
	char*s=strncpy(str2, str1,3);
	printf("%s", s);
	return 0;
}

 


由以上调试和运行结果可见调用strncpy确实只是将str1中的前三个字符拷贝到str2中,并没有将\0拷贝过去

 strncpy的模拟实现

#include<assert.h>
char* my_strncpy(char* dest, const char* src,size_t num)
{
	assert(dest && src);
	char* str = dest;
	while (*dest++ = *src++&&--num)
	{
		;
	}
	for (int i = 0; i < --num; i++)//追加\0
	{
		*dest++ = '\0';
	}
	 return str;
}

5.strcat与strncat

strcat

首先来了解库函数strcat的作用是实现字符的追加将一个字符串的内容追加到另一个字符串中,调用该函数时需要的参数是源字符串的首元素地址以及拷贝目标字符串的首元素地址 。且调用strcat时是将源字符串中包含\0和\0之前的字符全部追加到目标空间

注:在使用strcat时有几个需要注意的点:
• 源字符串必须以 '\0' 结束。
• 目标字符串中也得有 \0 ,否则没办法知道追加从哪里开始。
• 目标空间必须有足够的大,能容纳下源字符串的内容。
• 目标空间必须可修改

#include<stdio.h>
#include<string.h>
int main()
{
	char str1[] = "abcd";
	char str2[20] = "x\0xxxxx";
	char* s = strcat(str2, str1);
	printf("%s", s);
	return 0;
}

例如在以上代码中使用strcat使得字符串str1追加到str2中,就会将str1中的 a b c d \0五个元素都追加到数组str2中

最终打印输出结果就为xabcd

模拟实现strcpy
在了解了库函数strcpy的使用方法与作用我们就可以来试着模拟strcpy的实现

由于要实现字符串的追加,就先要找到源字符串末尾的\0,再从源字符串中\0开始追加目标字符串 

#include<assert.h>
char* my_strcat(char* dest, const char* src)
{
	assert(dest && src);
	char* str = dest;
	while (*dest)
	{
		dest++;
	}
	while ( *dest++= *src++ )
	{
		;
	}
	return str;
}

strncat

在学习了strcpy之后再来了解一个库函数strncpy

首先来了解strncat的参数和功能 
在以上形参部分可以看到strncpy的参数前两个都与strcat相同,但strncat多了一个size_t num的参数,那么这个参数表示的是什么呢?
其实num表示的是调用strncat时需要从源空间串中追加的字符的个数
所以strncat的功能就是将src指向字符串的前num个字符追加到dest指向的字符串末尾,再追加一个 \0 字符

注:在使用strncpy时有几个需要注意的点:
• 源字符串必须以 '\0' 结束。
• 目标字符串中也得有 \0 ,否则没办法知道追加从哪里开始。
• 目标空间必须有足够的大,能容纳下源字符串的内容。
• 目标空间必须可修改
• 如果src指向的字符串的长度小于num的时候,只会将字符串中到\0 的内容追加到dest指向的字符串末尾

以下代码就是使用strncat将str1中的前两个字符追加到str2中

#include<stdio.h>
#include<string.h>
int main()
{
	char str1[] = "abcd";
	char str2[20] = "x\0xxxxx";
	char* s = strncat(str2, str1,2);
	printf("%s", s);
	return 0;
}

 

由以上调试和运行结果可见调用strncat确实在将str1中的前两个字符追加到str2中后又追加一个 \0 字符过去

 模拟实现strncpy

char* my_strncat(char* dest, const char* src,size_t num)
{
	assert(dest && src);
	char* str = dest;
	while (*dest)
	{
		dest++;
	}
	while ((*dest++ = *src++)&& --num )
	{
		;
	}
	*dest = '\0';
	
	return str;
}

6.strcmp与strncmp

strcmp

首先来了解库函数strcmp的作用是用来比较两个字符串当第一个字符串大于第二个字符串就返回大于0的数,第一个字符串小于第二个字符串就返回小于0的数,两个字符串相等就返回0

同时strcmp的两个形参分别是所要比较字符串首元素的地址
 

#include<stdio.h>
#include<string.h>
int main()
{
	char str1[] = "abcdef";
	char str2[] = "abg";
	printf( "%d",strcmp(str1, str2));

	return 0;
}

在以上代码中使用strcmp比较str1和str2时就可以发现调用strcmp时返回值为负数,说明字符串abcdef小于字符串abg,这也就表示strcmp中的大字符串不表示是字符串长度大于另一字符串
那么为什么abcdef是大于abg呢?

其实对比的是相应位置字符的ASCII值,ASCII值大就表示字符串为大的字符串
所以在以上abcdef与abg中因为在第三个字符中g的ASCII值大于c的ASCII值,所以字符串abg就大于字符串abcdef,返回值就为负数

注:在vs中调用strcmp时默认当第一个字符串大于第二个字符串就返回1,第一个字符串小于第二个字符串就返回-1,两个字符串相等就返回0

strcmp模拟实现

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);
}

strncmp

首先来了解strncpy的参数和功能
在以上形参部分可以看到strncmp的参数前两个都与strcmp相同,但strncmp多了一个size_t num的参数,那么这个参数表示的是什么呢?

其实num表示的是调用strncmp时想要比较两字符串的元素个数

因此strncmp的作用就是比较str1和str2的前num个字符,如果相等就继续往后比较,最多比较num个字母,如果提前发现不一样,就提前结束,大的字符所在的字符串大于另外一个。如果num个字符都相等,就是相等返回0.

7.strstr

首先来了解库函数strcmp的作用是返回字符串在另一个字符串第一次出现的位置 

int main()
{
	char str1[] = "adcabfab";
	char str2[] = "ab";
	printf( "%s",strstr(str1, str2));

	return 0;
}

在以上代码中调用strstr就能返回ab在abcabf中第一次出现位置的地址,因此打印结果就为abfab

 

 模拟实现strstr
 

在实现strstr的过程中str1表示目标查找字符串的首元素的地址,str2表示要查找的字符串首元素的地址,但由于在遍历过程中需要多次从找到第一个元素相同时在查找从这个位置开始的是否和查找目标相同,因此就再创建了两个变量s1,s2分别实现两字符串内部的遍历

再创建一个变量src,这样就使得str1一直指向查找目标字符串首元素的地址

char* my_strstr(char* str1, char* str2)
{
	char* s1 = NULL;
	char* s2 = NULL;
	char* src = str1;
	if (str2 == '\0')
	{
		return str1;
	}
	while (*src)
	{
		s1 = src;
		s2 = str2;
		if (*s1 == *s2&& *s1 &&*s2)
		{
			s1++;
			s2++;
		}
		if (*s2)
		{
			return src;
		}
		if (*s1)
		{
			return NULL;
		}
		src++;
	}
}

8.strtok

来了解strtok的参数以及作用
sep参数指向⼀个字符串,定义了⽤作分隔符的字符集合
第⼀个参数str指定⼀个字符串,它包含了0个或者多个由sep字符串中一个或者多个分隔符分割标记。

strtok作用是找到str中的下一个标记,并将其⽤ \0 结尾,返回一个指向这个标记的指针

注:在使用strtokt时有几个需要注意的点:
• strtok函数的第⼀个参数不为 NULL ,函数将找到str中第⼀个标记,strtok函数将保存它在字符串中的位置。
• strtok函数的第⼀个参数为 NULL ,函数将在同⼀个字符串中被保存的位置开始,查找下⼀个标记。
• 如果字符串中不存在更多的标记,则返回 NULL 指针

#define  _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>

int main()
{	
    char arr3[] = "hello@world.yes";
	char dest[200] = { 0 };
	strcpy(dest, arr3);
	char* arr4 = "@.";
	char* ret = NULL;
	for (ret=strtok(dest, arr4); ret != NULL; ret=strtok(NULL, arr4))
	{
		printf("%s\n", ret);
	}
	return 0;
}

以上代码输出结果如下: 

 

9.strerror

 strerror 函数作用是可以把参数部分错误码对应的错误信息的字符串地址返回来。

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

#include <errno.h>
#include <string.h>
#include <stdio.h>
int main()
{
int i = 0;
for (i = 0; i <= 10; i++) {
printf("%s\n", strerror(i));
}
return 0;
}

在VS2022环境下输出的结果如下:

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

  • 122
    点赞
  • 86
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 64
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 64
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

mljy.

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

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

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

打赏作者

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

抵扣说明:

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

余额充值