【进阶C语言】字符函数和字符串函数(万文详解)

在这里插入图片描述

前言

C语言中对字符和字符串的处理很是频繁,但是C语言本身是没有字符串类型的,字符串通常放在常量字符串中或者字符数组中。
字符串常量适用于那些对它不做修改的字符串函数.
今天将带来C语言函数的使用介绍
分为三部分供大家理解
如果这份博客对大家有帮助,希望各位给恒川一个免费的点赞作为鼓励,并评论收藏一下,谢谢大家!!!
制作不易,如果大家有什么疑问或给恒川的意见,欢迎评论区留言。


1. 字符串系列函数第一部分介绍

1.1 strlen

size_t strlen ( const char * str );
  1. 字符串已经 ‘\0’ 作为结束标志,strlen函数返回的是在字符串中 ‘\0’ 前面出现的字符个数(不包含 ‘\0’ )。
  2. 参数指向的字符串必须要以 ‘\0’ 结束。
  3. 注意函数的返回值为size_t,是无符号的( 易错 )
  4. 学会strlen函数的模拟实现

注:

//strlen函数的返回类型是size_t - 无符号整型
int main()
{
    
    
	if (strlen("abc") - strlen("abcdef") > 0)
	{
    
    
		printf(">\n");
	}
	else
	{
    
    
		printf("<=\n");
	}
	return 0;
}

结果是">",因为strlen函数的返回类型是size_t - 无符号整型

strlen函数的模拟实现
1.计数器版本:

#include <assert.h>
//1. 计数器
int my_strlen(const char* str)
{
    
    
	int count = 0;
	assert(str);//断言保证代码有效性
	while (*str != '\0')
	{
    
    
		count++;
		str++;
	}
	return count;
}

2.递归版本:

//2. 递归
//如果题目要求不创建临时变量,求字符串长度时,用递归
int my_strlen(const char* str)
{
    
    
	if (*str != '\0')
		return 1 + my_strlen(str + 1);
	else
		return 0;
}

3.指针-指针版本:

//3. 指针-指针
int my_strlen(char * str)
{
    
    
	char* start = str;
	while (*str != '\0')
		str++;
	return str - start;//指针-指针得到的是元素个数
}

int main()
{
    
    
	int len = my_strlen("abcdef");
	printf("%d\n", len);

	return 0;
}

1.2 strcpy

char* strcpy(char * destination, const char * source );
  1. Copies the C string pointed by source into the array pointed by destination, including theterminating null character (and stopping at that point).
  2. 源字符串必须以 ‘\0’ 结束。
  3. 会将源字符串中的 ‘\0’ 拷贝到目标空间。
  4. 目标空间必须足够大,以确保能存放源字符串。
  5. 目标空间必须可变。
  6. 学会模拟实现。

分析错误:

int main()
{
    
    
	//这也是一样错的示范- 目标空间必须可以修改
	char* p = "abcdefghi";
	char arr2[20] = "hehe";
	strcpy(p, arr2);
	printf("%s\n", p);

	//这是一个错误的示范 - 目标空间必须足够大
	char arr1[20] = "abcdefghi";//
	char arr2[3] = "";//3
	strcpy(arr2, arr1);
	printf("%s\n", arr2);

	char arr1[] = "qwertyuiop";
	char arr2[20] = arr1;//err
	char arr2[20] = {
    
     0 };
	arr2 = arr1;//err

	return 0;
}

strcpy函数的模拟实现

#include <assert.h>

//回的是目标空间的起始地址
char* my_strcpy(char* dest, const char*src)//目的地发生变化,源头是不需要被改变的,所以使用时源头加一个const会好些
{
    
    
	char* ret = dest;
	assert(dest && src);
	while (*dest++ = *src++)
	{
    
    
		;
	}
	return ret;
}

int main()
{
    
    
	char arr1[] = "hehe";
	char arr2[20] = {
    
     0 };
	//my_strcpy(arr2, arr1);
	//printf("%s\n", arr2);
	printf("%s\n", my_strcpy(arr2, arr1));
	return 0;
}

1.3 strcat

char * strcat ( char * destination, const char * source );
  1. Appends a copy of the source string to the destination string. The terminating null characterin destination is overwritten by the first character of source, and a null-character is includedat the end of the new string formed by the concatenation of both in destination.
  2. 源字符串必须以 ‘\0’ 结束。
  3. 目标空间必须有足够的大,能容纳下源字符串的内容。
  4. 目标空间必须可修改。
  5. 字符串自己给自己追加,如何?
#include <string.h>

int main()
{
    
    
	char arr1[20] = "hello \0xxxxxxxxx";
	char arr2[] = "world";
	//追加  目标空间必须要有\0
	//通过监视,word后面的\0也会覆盖过去
	strcat(arr1, arr2);
	printf("%s\n", arr1);

	return 0;
}

strcat函数的模拟实现

#include <string.h>
char* my_strcat(char* dest, const char*src)
{
    
    
	assert(dest && src);
	char* ret = dest;
	//找目标空间中的\0
	while (*dest != '\0')
	{
    
    
		dest++;
	}
	//拷贝
	while (*dest++ = *src++)
	{
    
    
		;
	}
	return ret;
}

int main()
{
    
    
	char arr1[20] = "hello ";
	char arr2[] = "world";
	//追加
	my_strcat(arr1, arr2);
	printf("%s\n", arr1);



	return 0;
}

在这里插入图片描述
在这里插入图片描述
字符串自己给自己追加,如何?

#include <string.h>
char* my_strcat(char* dest, const char*src)
{
    
    
	assert(dest && src);
	char* ret = dest;
	//找目标空间中的\0
	while (*dest != '\0')
	{
    
    
		dest++;
	}
	//拷贝
	while (*dest++ = *src++)
	{
    
    
		;
	}
	return ret;
}

int main()
{
    
    
	//(还是用刚刚的代码)自己给自己追加(结果是不行的,会陷入死循环)
	char arr1[20] = "bit";
	my_strcat(arr1, arr1);
	printf("%s\n", arr1);


	return 0;
}

图片讲解:
在这里插入图片描述
详细解释一下刚刚的追加问题
正常追加:
在这里插入图片描述
自己给自己追加:
将目标里面的\0覆盖掉(自己将自己源数据破坏掉了)
在这里插入图片描述

1.4 strcmp

int strcmp ( const char * str1, const char * str2 );
  • This function starts comparing the first character of each string. If they are equal to eachother, it continues with the following pairs until the characters differ or until a terminatingnull-character is reached.
  • 标准规定:
  1. 第一个字符串大于第二个字符串,则返回大于0的数字
  2. 第一个字符串等于第二个字符串,则返回0
  3. 第一个字符串小于第二个字符串,则返回小于0的数字
  4. 那么如何判断两个字符串?
#include <string.h>
int main()
{
    
    
	//char* p = "abcdef";
	比较2个字符串的内容的时候,不能使用==,应该使用strcmp
	//if ("abcdef" == "bbcdef")//这里比较的是连个字符串首字符的地址,而并不是字符串的内容
	//{
    
    
	//}
	char arr1[] = "abq";
	char arr2[] = "abq";
	int ret = strcmp(arr1, arr2);

	printf("%d\n", ret);

	return 0;
}

strcmp函数的模拟实现

#include <stdio.h>
#include <assert.h>
//
int my_strcmp(const char* str1, const char* str2)//const目的是能保证拿到内容,不会修改内容
{
    
    
	assert(str1 && str2);
	while (*str1 == *str2) 
	{
    
    
		if (*str1 == '\0')
			return 0;
		str1++;
		str2++;
	}
	return *str1 - *str2;

	//if (*str1 > *str2)
	//	return 1;
	//else
	//	return -1;
}
int main()
{
    
    
	char arr1[] = "abzqw";
	char arr2[] = "abq";
	int ret = my_strcmp(arr1, arr2);
	printf("%d\n", ret);
	/*if (strcmp(arr1, arr2) >0)
		printf(">\n");*/
	return 0;
}

2. 字符串系列函数第二部分介绍

2.1 strncpy

长度受限制的字符串

char * strncpy ( char * destination, const char * source, size_t num );
  1. Copies the first num characters of source to destination. If the end of the source C string(which is signaled by a null-character) is found before num characters have been copied,destination is padded with zeros until a total of num characters have been written to it.
  2. 拷贝num个字符从源字符串到目标空间。
  3. 如果源字符串的长度小于num,则拷贝完源字符串之后,在目标的后边追加0,直到num个。
#include <string.h>
int main()
{
    
    
	char arr1[] = "abcdef";
	char arr2[20] = "xxxxxxxxxx";
	strncpy(arr2, arr1, 8);
	printf("%s\n", arr2);
	return 0;
}

在这里插入图片描述

2.2 strncat

char * strncat ( char * destination, const char * source, size_t num );
  1. Appends the first num characters of source to destination, plus a terminating null-character.
  2. If the length of the C string in source is less than num, only the content up to the terminatingnull-character is copied.
int main()
{
    
    
	char arr1[20] = "hello \0xxxxxxxxxx";
	char arr2[] = "abcdef";
	strncat(arr1, arr2, 3);//追加完后会在后面补一个\0
	printf("%s\n", arr1);
	return 0;
}

在这里插入图片描述

2.3 strncmp

int strncmp ( const char * str1, const char * str2, size_t num );
  • 比较到出现另个字符不一样或者一个字符串结束或者num个字符全部比较完。
int main()
{
    
    
	char arr1[] = "abcdef";
	char arr2[] = "abcq";
	int ret = strncmp(arr1, arr2, 4);
	printf("%d\n", ret);
	return 0;
}

3. 字符串系列函数第三部分介绍

3.1 strstr

char * strstr ( const char *str1, const char * str2);
  • Returns a pointer to the first occurrence of str2 in str1, or a null pointer if str2 is not part ofstr1.
    在一个字符串中找另一个字符串第一次出现的位置
int main()
{
    
    
	char arr1[] = "abcdebcdf";
	char arr2[] = "bcd";

	char* p = strstr(arr1, arr2);
	if (p == NULL)
	{
    
    
		printf("找不到\n");
	}
	else
	{
    
    
		printf("%s\n", p);
	}
	return 0;
}

在这里插入图片描述
在这里插入图片描述
再举一个例子:
在这里插入图片描述
strstr函数的模拟实现

#include <stdio.h>
char* my_strstr(const char* str1, const char* str2)
{
    
    
	char* s1 = NULL;//进行维护第一个指针str1
	char* s2 = NULL;//进行维护第二个指针str2
	char* cp = (char*)str1;

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

int main()
{
    
    
	char arr1[] = "abcdebcdf";
	char arr2[] = "bcd";

	char* p = my_strstr(arr1, arr2);
	if (p == NULL)
	{
    
    
		printf("找不到\n");
	}
	else
	{
    
    
		printf("%s\n", p);
	}
	return 0;
}

一种匹配的场景:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
多次匹配的场景:
在这里插入图片描述
在这里插入图片描述

3.2 strtok

char * strtok ( char * str, const char * sep );
  1. sep参数是个字符串,定义了用作分隔符的字符集合
  2. 第一个参数指定一个字符串,它包含了0个或者多个由sep字符串中一个或者多个分隔符分割的标记。
  3. strtok函数找到str中的下一个标记,并将其用 \0 结尾,返回一个指向这个标记的指针。(注:strtok函数会改变被操作的字符串,所以在使用strtok函数切分的字符串一般都是临时拷贝的内容并且可修改。)
  4. strtok函数的第一个参数不为 NULL ,函数将找到str中第一个标记,strtok函数将保存它在字符串中的位置。
  5. strtok函数的第一个参数为 NULL ,函数将在同一个字符串中被保存的位置开始,查找下一个标记。
  6. 如果字符串中不存在更多的标记,则返回 NULL 指针。
#include <stdio.h> 
#include <string.h>
int main()
{
    
    
	char arr[] = "192.168.3.212";//切割几次加NULL
	char buf[30] = {
    
    0};//临时拷贝方便修改//zpengwei\0yeah\0net\0
	strcpy(buf, arr);

	const char* p = ".";
	char* str = strtok(buf, p);//
	printf("%s\n", str);

	str = strtok(NULL, p);//传NULL的目的是他从刚刚保存的位置开始找了
	printf("%s\n", str); 
	
	str = strtok(NULL, p);//
	printf("%s\n", str);

	str = strtok(NULL, p);//
	printf("%s\n", str);

	return 0;
}

但该代码不太方便,当切割次数多的时候,不灵活

int main()
{
    
    
	char arr[] = "[email protected]";
	char buf[30] = {
    
     0 };//zpengwei\0yeah\0net\0
	strcpy(buf, arr);

	//const char* buf = "[email protected]";代码会崩掉的

	const char* p = "@.";
	char* str = NULL;
	for (str = strtok(buf, p); str != NULL; str=strtok(NULL, p))
	{
    
    
		printf("%s\n", str);
	}

	return 0;
}

在这里插入图片描述

3.3 strerror

char * strerror ( int errnum );

返回错误码,所对应的错误信息。
在这里插入图片描述

其实:
C语言的库函数在调用失败的时候,会将一个错误码存放在一个叫:errno的变量中,当我们想知道调用库函数的时候发生了什么错误信息,就可以将:errno中的错误码翻译成错误信息

如何使用:

#include <errno.h>

int main()
{
    
    
	//打开文件
	//打开文件的时候,如果文件的打开方式是"r"
	//文件存在则打开成功,文件不存在打开失败
	//打开文件失败的话,会返回NULL
	FILE* pf = fopen("test.txt", "r");
	if (pf == NULL)
	{
    
    
		printf("打开文件失败,原因是:%s\n", strerror(errno));
		return 1;
	}
	//读写文件
	//...
	//关闭文件
	fclose(pf);
	pf = NULL;
	return 0;
}

另一种更直接的方式:

int main()
{
    
    
	//打开文件
	//打开文件的时候,如果文件的打开方式是"r"
	//文件存在则打开成功,文件不存在打开失败
	//打开文件失败的话,会返回NULL
	FILE* pf = fopen("test.txt", "r");
	if (pf == NULL)
	{
    
    
		perror("打开文件失败");
		//printf + strerror
		return 1;
	}
	//读写文件
	//...
	//关闭文件
	fclose(pf);
	pf = NULL;
	return 0;
}

4. 字符函数

4.1 字符分类函数

函数 如果他的参数符合下列条件就返回真
iscntrl 任何控制字符
isspace 空白字符:空格‘ ’,换页‘\f’,换行’\n’,回车‘\r’,制表符’\t’或者垂直制表符’\v’
isdigit 十进制数字 0~9
isxdigit 十六进制数字,包括所有十进制数字,小写字母af,大写字母AF
islower 小写字母a~z
isupper 大写字母A~Z
isalpha 字母a ~ z 或A ~ Z
isalnum 字母或者数字,a ~ z,A ~ Z,0 ~ 9
ispunct 标点符号,任何不属于数字或者字母的图形字符(可打印)
isgraph 任何图形字符
isprint 任何可打印字符,包括图形字符和空白字符
int main()
{
    
    
	printf("%d\n", isdigit('6'));
	printf("%d\n", isspace('2'));
	printf("%d\n", islower('x'));
	printf("%c\n", toupper('x'));
	printf("%c\n", tolower('X'));
}

结果如下:
在这里插入图片描述

4.2 字符转换

int tolower ( int c );
int toupper ( int c );

代码练习:

int main()
{
    
    
	char arr[128] = {
    
     0 };
	gets(arr);
	int i = 0;
	while (arr[i])
	{
    
    
		if (isupper(arr[i]))
		{
    
    
			arr[i] = tolower(arr[i]);
		}
		printf("%c", arr[i]);
		i++;
	}
}

结果如下:
在这里插入图片描述

总结:
前面讲的函数都是和字符串,字符相关的!!
但我们在操作数据的时候,不仅仅是操作字符串,字符的数据,还有内存函数,会在下一期进行详细讲解。

如果这份博客对大家有帮助,希望各位给恒川一个免费的点赞作为鼓励,并评论收藏一下,谢谢大家!!!
制作不易,如果大家有什么疑问或给恒川的意见,欢迎评论区留言。

猜你喜欢

转载自blog.csdn.net/m0_75058342/article/details/129872739