字符函数和字符串函数
2023-12-25 18:27:47
    		1.strlen函数
-  size_t strlen ( const char * str ); 
函数功能:
- 获取字符串的长度,即返回一个字符串到中到\0'字符之前的的字符个数
//int main()
//{
//	char* arr = "abcdef";
//	size_t len = strlen(arr);
//	printf("%d\n", len);//6
//
//	return 0;
//}
int main()
{
	char* arr = "abc\0def";
	size_t len = strlen(arr);
	printf("%d\n", len);//3
	return 0;
}注意:strlen的返回值是size_t类型,是无符号的
int main()
{
	char str1[] = "abcdef";
	char str2[] = "bbb";
	if (strlen(str2) - strlen(str1) > 0)
	{
		printf("str2>str1\n");
	}
	else
	{
		printf("srt1>str2\n");
	}
	return 0;
}代码解读:
- 因为strlen的返回值是size_t类型的,两个size_t类型的值相减,结果仍然是size_t类型
3-6结果是-3,因为是size_t类型,会被编译器当成一个很大的正数,因此打印str2>str1
1.1strlen的模拟实现
方法1:计数器
size_t my_strlen(const char* str)
{
	assert(str);
	char* p = str;
	int count = 0;
	while (*p != '\0')
	{
		count++;
		p++;
	}
	return count;
}方法2:递归
size_t my_strlen(const char* str)
{
	assert(str);
	char* p = str;
	if (*p == '\0')
		return 0;
	return 1 + my_strlen(p + 1);
}方法三:指针-指针
size_t my_strlen(const char* str)
{
	assert(str);
	char* p = str;
	while (*p != '\0')
	{
		p++;
	}
	return (p - str);
}2.strcpy函数
-  char * strcpy ( char * destination, const char * source ); 
函数功能:
- 将source处的内容拷贝到destination指向的空间,包括'\0'
注意事项:
- source中的内容要有'\0'
- 会将'\0'一起拷贝
- destination指向的空间要足够大
2.1strcpy的模拟实现
char* my_strcpy(char* destination, const char* source)
{
	assert(destination && source);
	char* ret = destination;
	while (*destination++ = *source++)
	{
		;
	}
	return ret;
}3.strcat函数
-  char * strcat ( char * destination, const char * source ); 
函数功能:
- 在destination末尾追加字符串source
注意事项:
- 先找到destination字符串中的'\0',在'\0'处开始拷贝
- 会将source字符串中的'\0'一起拷贝
- destination字符串必须要有'\0';source字符串也必须要有'\0'
- destination的空间必须足够大
3.1strcat的模拟实现
char* my_strcat(char* destination, const char* source)
{
	assert(destination && source);
	
	char* ret = destination;
	//找到'\0'
	while (*destination++)
	{
		;
	}
	//拷贝
	while (*destination++ = *source++)
	{
		;
	}
	return ret;
}问:能不能自己给自己追加?
答:我们自己写的模拟实现代码是不能追加给自己追加的,程序会陷入死循环;库函数中的strcat更加完善,能够完成自己追加自己,但还是不建议这样做
4.strcmp函数
-  int strcmp ( const char * str1, const char * str2 ); 
函数功能:
- 比较两个字符串
注意事项:
- str1>str2,返回正数
- str1==str2,返回0
- str1<str2,返回负数
int main()
{
	char arr1[] = "abcdef";
	char arr2[] = "abcdeg";
	int ret = strcmp(arr1, arr2);
	if (ret > 0)
		printf("str1 > str2\n");
	else if (ret == 0)
		printf("str1 == str2\n");
	else
		printf("str1 < str2\n");
	return 0;
}
//输出:str1 < str24.1strcmp的模拟实现
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;
}上面的strcpy,strcat都是长度不受限制的字符串函数,与它们相对应的是长度受限制的字符串函数
5.strncpy函数
-  char * strncpy ( char * destination, const char * source, size_t num ); 
函数功能:
- 相较于strcpy,strncpy函数多了一个num参数,该参数表示要拷贝的字节个数
也就是我们可以指定拷贝的字符个数
注意事项:
- ?destination指向的空间必须足够大
- 如果source中的字符串个数小于num,则拷贝完source的字符串后自动补'\0'
- 如果source中的字符串个数大于num,则仅拷贝num个字符,不会加上'\0'
int main()
{
	char arr1[20] = "xxxxxxxxx";
	char arr2[] = "abcde";
	strncpy(arr1, arr2, 3);
	printf("%s\n", arr1);
	return 0;
}
//输出:abcxxxxxx5.1strncpy的模拟实现
char* my_strncpy(char* destination, const char* source, int num)
{
	assert(destination && source);
	char* ret = destination;
	while (num--)
	{
		if (*source == '\0')
			*destination++ = '\0';
		else
			*destination++ = *source++;
	}
	return ret;
}6.strncat函数
-  char * strncat ( char * destination, const char * source, size_t num ); 
函数功能:
- 从source中追加num个字符到destination中
注意事项:
- destination的空间必须足够大
- 如果source字符串个数小于num,则相当于追加source字符串
- 如果source字符串个数大于num,则追加完num个字符后,自动补上'\0'
6.1strncat的模拟实现
char* my_strncat(char* destination, const char* source, int num)
{
	assert(destination && source);
	char* ret = destination;
	//找'\0'
	while (*destination != '\0')
	{
		destination++;
	}
	while (num--)
	{
		if (num < 0 || *source == '\0')
			break;
		*destination++ = *source++;
	}
	*destination = '\0';
	return ret;
}7.strncmp函数
-  int strncmp ( const char * str1, const char * str2, size_t num ); 
函数功能:
- 比较str1和str2中前num个字符构成的字符串的大小
int main()
{
	char arr1[] = "abcdef";
	char arr2[] = "abcdef";
	int ret = strncmp(arr1, arr2, 3);
	if (ret > 0)
		printf("str1>str2\n");
	else if (ret == 0)
		printf("str1==str2\n");
	else
		printf("str1<str2\n");
	return 0;
}
//输出:str1 == str28.strstr函数
-  const char * strstr ( const char * str1, const char * str2 );? 
函数功能:
- 在字符串str1中查找字符串str2
- 如果找到了,返回str2第一个字符在str1中的地址;如果找不到,返回NULL
int main()
{
	char arr1[] = "abcdef";
	char arr2[] = "cde";
	char* ret = strstr(arr1, arr2);
	if (ret)
		printf("%s\n", ret);
	else
		printf("找不到\n");
	return 0;
}
//输出:cdef8.1strstr的模拟实现
char* my_strstr(const char* str1, const char* str2)
{
	assert(str1 && str2);
	if (*str2 == '\0')
		return str1;
	int i = 0;//str1的下标
	int j = 0;//str2的下标
	while (str1[i])
	{
		while (str1 && str2 && str1[i] == str2[j])
		{
			i++;
			j++;
		}
		if (str2[j] == '\0')
			return str1 + i - j;
		i = i - j + 1;
		j = 0;
	}
	return NULL;
}9.strtok
-  char * strtok ( char * str, const char * delimiters ); 
函数功能:
- 根据delimiters中的字符分割str字符串中的内容
int main()
{
	char arr1[] = "baiyahua@qq.com";
	char arr2[] = "@.";
	char* ret = strtok(arr1, arr2);
	printf("%s\n", ret);
	return 0;
}
//输出:baiyahua注意事项:
- delimiters中是自己定义的分隔符的集合
- str中包含delimiters中的分隔符
- 如果strtok的第一个参数不为空,会将str中的第一个分隔符替换成'\0',并记录该位置,返回起始位置的地址
- 如果strtok的第一个参数为空,从上次记录的位置开始寻找分隔符
- 如果没有找到分隔符,返回NULL
由于strtok会改变字符串的内容,所以我们一般先拷贝一份原来的字符串,对拷贝的字符串进行操作
int main()
{
	char arr1[] = "baiyahua@qq.com";
	char* p = "@.";
	char copyArr1[50] = { 0 };
	strcpy(copyArr1, arr1);
	char* s = strtok(copyArr1, p);
	while (s != NULL)
	{
		printf("%s\n", s);
		s = strtok(NULL, p);
	}
	return 0;
}
//输出:
//baiyahua
//qq
//com10.strerror
-  char * strerror ( int errnum ); 
函数功能:
- 翻译错误码对应的错误信息,并返回错误信息的起始地址
在C语言中,使用库函数发生错误时,会将错误码存放在一个叫errno的全局变量中;strerror的作用就是返回errnum中的值所对应的错误信息,然后返回错误信息的起始地址

int main()
{
	FILE* pf = fopen("data.txt", "r");
	if (pf == NULL)
	{
		printf("打开文件失败,原因是:%s\n", strerror(errno));
		return 0;
	}
	else
	{
		printf("打开文件成功\n");
	}
	fclose(pf);
	pf = NULL;
	return 0;
}
//输出:打开文件失败,原因是: No such file or directory10.1perror
-  void perror ( const char * str ); 
函数功能:
- 直接将错误码翻译成错误信息,并打印出来
perror相当于strerror+printf;在使用库函数出错时,它首先会打印str字符串,再将错误码对应的错误信息打印
int main()
{
	FILE* pf = fopen("data.txt", "r");
	if (pf == NULL)
	{
		perror("打开文件失败,原因是");
		return 0;
	}
	else
	{
		printf("打开文件成功\n");
	}
	fclose(pf);
	pf = NULL;
	return 0;
}
//输出:打开文件失败,原因是: No such file or directorystrerror和perror
- 如果只想要错误码对应的错误信息,用strerror
- 如果还想打印出错误信息,用perror更方便
11.字符函数
11.1字符分类函数
常见的字符分类函数:
| 函数 | 符合下面的条件返回真 | 
| iscntrl | 任何控制字符 | 
| isspace | 空白字符,空格' ',换页'\f',换行'\n',回车'\r',制表符'\t',垂直制表符'\v' | 
| isdigit | 数字0~9 | 
| isxdigit | 十六进制数字,0~9,a~f或A~F | 
| islower | 小写字母,a~z | 
| isupper | 大写字母,A~Z | 
| isalpha | 字母,a~z,A~Z | 
| isalnum | 字母或数字,0~9,a~z,A~Z | 
| ispunct | 标点符号,任何不属于数字或字母的可打印字符 | 
| isgraph | 任何图形字符 | 
| isprint | 任何可打印字符 | 
我们就拿其中一个函数举例,其他函数同理
isdigit函数
- int isdigit ( int c );
函数功能:
- 判断c是否是一个数字字符,如果是数字返回非0;如果不是,返回0
int main()
{
	int ch = '1';
	if (isdigit(ch))
		printf("是数字字符\n");
	else
		printf("不是数字字符\n");
	return 0;
}
//输出:是数字字符11.2字符转换函数
-  int toupper ( int c ); 
-  int tolower ( int c ); 
函数功能:
- toupper:如果c是小写字母,则返回c的大写字母;否则就直接返回c
- tolower:如果c是大写字母,则返回c的小写字母;否则就直接返回c
int main()
{
	char arr[] = "Test String.\n";
	char* p = arr;
	while (*p)
	{
		if (isupper(*p))
			*p = tolower(*p);
		p++;
	}
	printf("%s\n", arr);
	return 0;
}
//输出:test string.12.内存函数
12.1memcpy函数
-  void * memcpy ( void * destination, const void * source, size_t num ); 
函数功能:
- 从source指向的内存拷贝num个字节到destination中,返回destination首元素的地址
前面的strcpy是只能对字符串进行拷贝的函数,而memcpy能对任意类型的数据进行拷贝
int main()
{
	int arr1[20] = { 0 };
	int arr2[] = { 1,2,3,4,5,6,7 };
	memcpy(arr1, arr2, 20);
	for (int i = 0; i < 5; i++)
	{
		printf("%d ", arr1[i]);
	}
	printf("\n");
	return 0;
}
//输出1 2 3 4 512.1.1memcpy的模拟实现
void* my_memcpy(void* destination, const void* source, size_t num)
{
	assert(destination && source);
	void* ret = destination;
	while (num--)
	{
		*(char*)destination = *(char*)source;
		destination = (char*)destination + 1;
		source = (char*)source + 1;
	}
	return destination;
}如果我们想要对重叠的内存进行拷贝,my_memcpy是完成不了的;库函数中的memcpy虽然可以进行重叠内存的拷贝,但我们规定好:
- 两段不重叠的内存拷贝用memcpy
- 两段有重叠的内存拷贝用memmove
12.2memmove函数
-  void * memmove ( void * destination, const void * source, size_t num ); 
函数功能:
- 从source指向的内存拷贝num个字节到destination中,返回destination首元素的地址
同样是拷贝内存,用法也与memcpy一样,只不过对于重叠内存的拷贝我们一般选择memmove
12.2.1memmove的模拟实现
void* my_memmove(void* destination, const void* source, size_t num)
{
	assert(destination && source);
	void* ret = destination;
	if (source < destination)
	{
		//从后往前拷贝
		while (num--)
		{
			*((char*)destination + num) = *((char*)source + num);
		}
	}
	else
	{
		//从前往后拷贝
		while (num--)
		{
			*(char*)destination = *(char*)source;
			destination = (char*)destination + 1;
			source = (char*)source + 1;
		}
	}
	return ret;
}
12.3memset函数
-  void * memset ( void * ptr, int value, size_t num ); 
函数功能:
- 设置ptr指向内存的内容改为value;以字节为单位,一共该num个字节
int main()
{
	char arr[] = "Welcome to my world.\n";
	memset(arr + 14, 'x', 3);
	printf("%s", arr);
	return 0;
}
//输出:Welcome to my xxxld.注意事项:
- 该函数是以字节为单位进行修改的,每次只会修改一个字节
12.4memcmp函数
-  int memcmp ( const void * ptr1, const void * ptr2, size_t num ); 
函数功能:
- 以字节为单位比较两块内存
- ptr1>ptr2,返回正数;
- ptr1==ptr2,返回0
- ptr1<ptr2,返回负数
int main()
{
	int arr1[] = { 1,2,3,4,5,6,7,8 };
	int arr2[] = { 1,2,3,4,0x11111105 };
	int ret = memcmp(arr1, arr2, 17);
	printf("%d\n", ret);
	return 0;
}
//输出0,前16字节都是相等
//arr1和arr2的第十七字节数据都是05,所以相等字符函数和字符串函数的内容就到这!
    			文章来源:https://blog.csdn.net/2303_77982246/article/details/135039561
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!
    	本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!