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

在学习编程的过程中,我们会经常会遇到一些字符和字符串,为了方便操作字符和字符串,C语言标准库中就提供了一系列函数。那么,接下来就学习下这些函数。

1. 字符分类函数

C语言中有一系列的函数是专门做字符分析的,也就是判断一个字符属于什么类型的字符的。

这些函数的使用都需要包含一个头文件 ctype.h

上图就是字符类函数的一些种类。

这些函数的使用方法非常类似,我们就以一个函数为例。

int main()
{
	int ret1 = islower('c');
	int ret2 = islower('A');
	printf("ret1 = %d\n", ret1);
	printf("ret2 = %d\n", ret2);

	return 0;
}

islower函数 是一个能判断参数部分是否为小写字母的函数。

通过返回值来说明是否为小写字母,如果是小写字母,就返回一个非0的整数,如果不是小写字母,就返回数字0。 

2. 字符转换函数

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

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

多说不用,直接上一道例题体会体会。

练习:将一个字符串的小写字母转换成大写字母,其他字符不变。

int main()
{
	char arr[] = "hello man";
	int i = 0;
	while (arr[i])
	{
		if (islower(arr[i]))
		{
			arr[i] = toupper(arr[i]);
		}
		i++;
	}
	printf("%s", arr);
	return 0;
}

上面代码就是通过 toupper 这个函数将字符串中的小写字母转换成大写代码的例子。

运行如下 

3. strlen的使用和模拟实现 

size_t strlen ( const char * str );

1.strlen函数是用来计算一个字符串大小的库函数,不过它计算的是 ‘\0’ 前面的大小,不包括 ‘\0’,所以用strlen来计算大小是以 ‘\0’ 为结束标志的。

2.参数指向的字符串必须要以 '\0' 结束。

3.注意strlen函数的返回值是 size_t 类型的。这是一个易错点。

4. strlen 的使用需要包含其头文件 <string.h>

为什么说第3点是一个易错点呢?直接上代码

#include <stdio.h>
#include <string.h>
int main()
{
 const char* str1 = "abcdef";
 const char* str2 = "bbb";
 if(strlen(str2)-strlen(str1)>0)
 {
 printf("str2>str1\n");
 } 
 else
 {
 printf("srt1>str2\n");
 }
 return 0;
}

上面这段代码运行结果是什么呢?

相信很多人就立马猜出打印 str1>str2。 到底是不是呢?

运行代码,发现并不是我们猜想的那样。到底是为什么呢?

哦,原来是strlen函数的返回值类型为size_t的原因,size_t 是无符号整形的意思,两个无符号整形的相减的结果还是无符号整形的,尽管原来的结果是负数,但被强制转换成了size_t类型的,结果中带有的负号就不再算是符号位了,也就不算是一个 负数了。这就导致了运行结果的不同。

strlen函数的3中模拟实现

1. 计算器类型

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

2,递归类型

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

3.指针-指针类型

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

4.strcpy的使用和模拟

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

strcpy函数的作用是将一个字符串里面的内容复制到另一个字符串里面。 如上形式,就是将source里面字符串里的内容复制到destination字符串。

使用时注意事项

1. 源字符串必须以 '\0' 结束。

2.strcpy不仅会将字符串的内容复制到另一个函数,也会将 '\0' 一同复制过去。

3.目标空间必须可修改,如果目标空间是一个常量,就无法使用strcpy函数。

4.目标空间必须足够大,有确保能保存复制过来的内容。

strcpy的模拟实现

实现模拟之前。我们要清楚strlen函数是将字符串里面的内容一个一个复制过来的。

void my_strcpy( char* dest,  char* soc)
{
	while (*soc != '\0')
	{
		soc++;
		dest++;
	}
	*dest = *soc; // 将 '\0' 复制过来

}
int main()
{
	char arr1[] = "xxxxxxx";
	char arr2[20] = "abcd";
	my_strcpy(arr2, arr1);
	printf("%s", arr2);
	return 0;
}

我们也可以简化成以下版本 

void my_strcpy( char* dest,  char* soc)
{
	while (*dest++==*soc++)
	{
      ;
	}
}
int main()
{
	char arr1[] = "xxxxxxx";
	char arr2[20] = "abcd";
	my_strcpy(arr2, arr1);
	printf("%s", arr2);
	return 0;
}

简化版本也会将 '\0' 复制过去的,虽然++的优先级比 * 好高,但它是后置++,所以是先用完指定数据在进行++,也就是先对dest和soc进行解引用之后,再分别++,由于while()循环只有条件为真时才能进行,所以当soc一直++到 '\0' 时,赋值给dest时,条件刚好为0,循环终止,dest 也刚好被赋值 '\0' , 也就将arr2中的 '\0' 复制过去了。

以 %s 的形式打印时,也是以 '\0' 为终点的。 

运行如下

5.strcat的使用和模拟

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

strcat()函数是用来拼接2个字符串的函数。

使用strcat的注意事项

1. 源字符串必须要以 '\0' 结尾。

2. 目标空间也必须要有  ‘\0' 结尾,否则不知道从哪里开始拼接。

3. 目标空间要有足够大的空间来存储源字符串复制过来的内容。

4. 目标空间必须是可修改的空间。

我们还是直接通过代码感受

int main()
{
	char arr1[20] = "abcd";
	char arr2[] = "efghigk";
	strcat(arr1, arr2);
	printf("%s", arr1);
	return 0;
}

这段代码是将arr2里面的内容拼接到arr1里面。

运行代码如下图

 

通过上面图片可知,arr2的内容已经成功拼接到arr1里面了。

模拟实现strcat函数

模拟之前,先大概清楚下strcat()函数是如何实现拼接的。

首先,我们要找到目标空间的 '\0' ,确定了开始拼接的位置,然后再一个一个将要拼接的内容拼接到目标空间。

了解这个,开始实现代码

void my_strcat(char* dest, const char* soc)
{
	assert(dest && soc);
	//找到目标空间的 \0
	while (*dest)
	{
		dest++;
	}
	//接着开始实现复制,复制就和前面的strcmp的一摸一样了
	while ((*dest++ = *soc++))
	{
		;
	}

}
int main()
{
	char arr1[20] = "abcd";
	char arr2[] = "efghigk";
	my_strcat(arr1, arr2);
	printf("%s", arr1);
	return 0;
}

 

6. strcmp的使用和模拟

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

strcmp是用来比较2个字符串的大小的。 

两个字符串的比较原理

两个字符串相互比较时,两个字符串中的相应字符会一个一个进行比较,如上图,直到遇到两个不同的字符,这时,那个字符的ASCII值大,对应的字符串就大。如上图,c的ASCII值大于b的,则下面的字符串大。

strcmp是有返回值的。

标准规定:

1.当第一个字符串 小于  第二个字符串时,返回一个小于0的值。

2.当第一个字符串 等于 第二个字符串时,返回0.

3.当第一个字符串 大于 第二个字符串时,返回一个大于0的值。

照惯例,上代码

int main()
{
	char arr1[20] = "abcd";
	char arr2[] = "efghigk";
	int ret=strcmp(arr1, arr2);
	printf("%d", ret);
	return 0;
}

 

由于arr1字符串小于arr2字符串,所以ret为一个小于0的值。

模拟实现strcmp()函数

int my_strcmp(char* arr1, char* arr2)
{
	while (*arr1 == *arr2)
	{
		if (*arr1 = *arr2)
		{
			return 0;
		}
		arr1++;
		arr2++;
	}
	if (*arr1 > *arr2)
	{
		return 1;
	}
	else
	{
		return -1;
	}
}
int main()
{
	char arr1[20] = "abcd";
	char arr2[] = "abcd";
	int ret=my_strcmp(arr1, arr2);
	printf("ret=%d", ret);
	return 0;
}

也可以简化成

int my_strcmp(char* arr1, char* arr2)
{
	while (*arr1 == *arr2)
	{
		if (*arr1 = *arr2)
		{
			return 0;
		}
		arr1++;
		arr2++;
	}
	return *arr1 - *arr2;
}
int main()
{
	char arr1[20] = "abcd";
	char arr2[] = "abcd";
	int ret=my_strcmp(arr1, arr2);
	printf("ret=%d", ret);
	return 0;
}

因为是通过字符串里面的字符一个一个进行比较,所以想到用到了while()循环。

7.strncpy的使用

1 char * strncpy ( char * destination, const char * source, size_t num );

其实strncpy的使用和strcpy差不多,多了一个参数 num。

意思是将源字符串 num 个字符复制到目标空间。

注意事项

如果源字符串的长度小于num个,则会一直给目标空间补'\0',直到达到num个。 

8.strncat的使用

1 char * strncat ( char * destination, const char * source, size_t num );

strncat的用法和strcat差不多,也是多了个参数num。

意思是将源字符串num个字符拼接到目标空间去,并追加一个 '\0' 。

注意事项

 如果源字符串的长度小于num,则只会将 '\0' 前面的内容拼接到目标空间

9.strncmp的使用

strncmp的用法和strcmp差不多,也是多了个参数num。

意思是⽐较str1和str2的前num个字符,如果相等就继续往后⽐较,最多⽐较num个字⺟,如果提前发现不⼀样,就提前结束,⼤的字符所在的字符串⼤于另外⼀个。如果num个字符都相等,就是相等返回0。

10.strstr的使用和模拟

1 char * strstr ( const char * str1, const char * str2);

strstr()函数是用来在一个字符串中寻找另一个字符串。

如果有则返回开始匹配的地址,如没有则返回NULL。

老样子,上代码

int main()
{
	char arr1[20] = "abbbbhicd";
	char arr2[] = "abb";
	char* ret=strstr(arr1, arr2);
	printf("%s", ret);
	return 0;
}

如上图,在arr1字符串中寻找arr2字符串,由于当第一个字符匹配,再继续往后找时,就找到了abb,所以就将在arr1中开始匹配的地址返回,也就是将arr1中的a的地址返回。

运行结果如下

模拟实现strstr()

有几种情况我们要讨论一下

第一种情况是比较简单的,当发现第一个字符不匹配时,让arr1继续往后走,接着进行匹配就行了。

这种情况是最复杂的。

我们发现第一个字符不匹配时,让arr1+1,指向b,接着匹配,b和b匹配了, arr1和arr2一起进行加1,但发现匹配过程中有匹配不了了,所以这时我们要重新匹配,所以要让arr1和arr2共同返回开始匹配的位置,但是arr1和arr2已经在后面了,不在匹配时的位置了。

因此我们想到要用2个指针分别记录arr1中开始匹配的位置和arr2的起始地址。

 

如上图所示,用一个指针纪录开始匹配的位置,这样当我们匹配到半路失败时,可以返回的开始匹配地址。

char* my_strstr(const char* arr1,const char* arr2)
{
	const char* s1 = NULL;
	const char* s2 = NULL;
	const char* cur = arr1;
	if (*arr2 == '\0')
	{
		return (char*)arr1;
	}
	while (*cur)
	{
		s1 = cur;
		s2 = arr2;
		while (*s1 !='\0' && *s2!='\0' && * s1 == *s2)
		{
			s1++;
			s2++;
		}
		if (*s2 == '\0')
		{
			return (char*)cur;
		}
		cur++;
	}
	return NULL;
}
int main()
{
	char arr1[] = "abbbcefg";
	char arr2[] = "bbc";
	char* ret=my_strstr(arr1, arr2);
	printf("%s", ret);
	return 0;
}

11. strtok函数的使用

1 char * strtok ( char * str, const char * sep);

1.解释参数的意思

1.1 sep参数指向一个字符串,定义了一个用作分隔符的集合。

1.2.  第⼀个参数指定⼀个字符串,它包含了0个或者多个由sep字符串中⼀个或者多个分隔符分割的
标记。
2. strtok的用法原理
1. strtok函数找到str中的下⼀个标记,并将其⽤ \0 结尾,返回⼀个指向这个标记的指针。(注:
strtok函数会改变被操作的字符串,所以在使⽤strtok函数切分的字符串⼀般都是临时拷⻉的内容
并且可修改。)
2. strtok函数的第⼀个参数不为NULL ,函数将找到str中第⼀个标记,strtok函数将保存它在字符串
中的位置。
3. strtok函数的第⼀个参数为 NULL ,函数将在同⼀个字符串中被保存的位置开始,查找下⼀个标
记。
4. 如果字符串中不存在更多的标记,则返回 NULL 指针。
老样子,上代码
int main()
 {
 char arr[] = "192.168.6.111";
 char* sep = ".";
 char* str = NULL;
 for (str = strtok(arr, sep); str != NULL; str = strtok(NULL, sep))
 {
   printf("%s\n", str);
 }
 return 0;
}

12.strerror的使用

1 char * strerror ( int errnum );
 strerror函数可以把参数部分错误码对应的错误信息的字符串地址返回来。
在不同的系统和C语⾔标准库的实现中都规定了⼀些错误码,⼀般是放在 errno.h 这个头⽂件中说
明的,C语⾔程序启动的时候就会使⽤⼀个全⾯的变量errno来记录程序的当前错误码, 只不过程序
启动的时候errno是0,表⽰没有错误 ,当我们在使⽤标准库中的函数的时候发⽣了某种错误,就会
讲对应的错误码,存放在errno中, ⽽⼀个错误码的数字是整数很难理解是什么意思,所以每⼀个
错误码都是有对应的错误信息的 。strerror函数就可以将错误对应的错误信息字符串的地址返回。
int main()
{
 int i = 0;
 for (i = 0; i <= 10; i++) {
 printf("%s\n", strerror(i));
 }
 return 0;
}

 

 

 

 

 

 

 

 

 

 

 

 

 

评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值