字符串函数

36 阅读6分钟

字符串_字符串函数

求字符串长度
    strlen
长度不受限制的字符和字符串函数
    strcpy
    strcat
    strcmp
 长度受限制的字符串函数//更加严谨,多了第三个参数,比较个数的限制
    strncpy
    strncat
    strncmp
 字符串查找
    strstr
    strtok
 错误信息报告
    strerror
 字符操作
 内存操作函数
    memcpy
    memmove
    memset
    memcmp
    

1.strlen

以'\0'作为结束标志,strlen函数返回的是在字符串中'\0'前面出现的字符个数(不包含'\0')

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

注意函数的返回值为size_t,是无符号的

#include<stdio.h>
#include<string.h>
int main()
{
	char arr[] = "abcdef";//abcdef\0
	int len = strlen(arr);
	printf("%d\n", len);
	return 0;
}

strlen的结果.png

{
	if (strlen("abc") - strlen("abcdef") > 0)//不合理
     if(strlen("abc")>strlen("abcdef"))
	{
		printf(">\n");
	}
	else
	{
		printf("<=\n");
	}
	return 0;
}
//

strlen输出大于号的结果.png

//模拟实现
#include<assert.h>
//计数器方法
//指针-指针
//递归的方式
size_t my_strlen(const char* str)
{
	size_t count = 0;
	assert(str);
	while(*str != '\0')
	{
		count++;
		str++;
	}
	return count;
}
int main()
{
	char arr[] = "abcdef";
	size_t n = my_strlen(arr);
	printf("%u\n", n);
	return 0;
}

my_strlen结果为6.png

2.strcpy

拷贝遇到’\0‘停止,得保证拷贝的原数据里面有’\0‘

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

会将源字符串中的'\0'拷贝到目标空间

目标空间必须足够大,以确保能存放源字符串

目标空间必须可变

拷贝返回的是目标地址

int main()
{
	char name[20] = { 0 };
	//"zhangsan"
	//strcpy  
	strcpy(name, "zhangsan");
	printf("%s\n", name);

	return 0;
}

strcpy的结果.png

char* my_strcpy(char* dest, const char* src)
{
	assert(dest);
	assert(src);
    //assert(dest && str);
	char* ret = dest;
	/*while (*src)
	{
		*dest++ = *src++;
	}
	*dest = *src;*/
	while (*dest++ = *src++)
	{
		;
	}
    //;

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

my_strcpy的结果.png

3.strcat

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

字符串追加

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

目标空间必须足够大,以确保能存放源字符串

目标空间必须客修改

避免自己给自己追加

int main()
{
	char arr1[20] = "hello ";
	strcat(arr1, "world");
	printf("%s\n", arr1);
	return 0;
}

strcat的结果.png

char* my_strcat(char* dest, const char* src)
{
	char* ret = dest;
	assert(dest && src);
    //1.找到吗目标空间的末尾'\0'
	while (*dest != '\0')
	{
		dest++;
	}
    //2.拷贝字符串
	while (*dest++ = *src++)
	{
		;
	}
	return ret;
}
int main()
{
	char arr1[20] = "hello ";
	my_strcat(arr1, "world");
	printf("%s\n", arr1);
	return 0;
}

my_strcat的结果.png

4.strcmp

比较的是字符的ASCII码值

一对字节一对字节的比较



int main()
{
	char arr1[20] = "zhangsan";
	char arr2[] =   "zhangsanfeng";
	//0的ASCII值为0,比f的ASCII值要小
	// abcdef和abq  abq更大
	//两个字符串比较相等,应该使用strcmp
	int ret = strcmp(arr1, arr2);
	if (ret < 0)
		printf("<\n");
	else if (ret == 0)
		printf("==\n");
	else
		printf(">\n");

	//比较一下两个字符串是否相等
	//arr1是数组名,数组名是数组首元素的地址
	//这种写法是在比较两个地址,而不是两个字符串的内容


	//
	//if (arr1 == arr2)
	//{
	//	printf("==\n");
	//}
	//else
	//{
	//	printf("!=\n");
	//}
	return 0;
}

strcmp比较字符串大小的结果.png

模拟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);

}

	int main()
	{
		/*char arr1[20] = "zhangsan";
		char arr2[] = "zhangsanfeng";*/
		char arr1[] = "abc";
		char arr2[] = "abcd";
		//0的ASCII值为0,比f的ASCII值要小
		// abcdef和abq  abq更大
		//两个字符串比较相等,应该使用strcmp
		int ret = my_strcmp(arr1, arr2);
		if (ret < 0)
			printf("<\n");
		else if (ret == 0)
			printf("==\n");
		else
			printf(">\n");
	return 0;
}

模拟my_strcmp函数的结果.png

5.strncpy

char* strncpy(charr* destination,const char* source,size_t num)

strn***( , ,num)

	int main()
{
        char arr1[20] = "abcdef";
		char arr2[] = "hello bit";
		strncpy(arr1, arr2, 5);
		printf("%s\n", arr1);


	return 0;
}

strncpy的运行结果.png

6.strncat

最后会补上'\0'

int main()
{
	char arr1[20] = "hello\0xxxxx";
	char arr2[] = "world";
	strncat(arr1, arr2, 3);
	printf("%s\n", arr1);
	return 0;
}

strncat的运行结果.png

7.strncmp

int main()
{
	char arr1[] = "abcdef";
	char arr2[] = "abc";
	int ret = strncmp(arr1, arr2, 4);
	if (ret == 0)
		printf("==\n");
	else if (ret < 0)
		printf("<\n");
	else
		printf(">\n");
	return 0;
}

strncmp的结果.png

8.strstr

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

查找子串的一个函数

int main()
{
	char email[] = "zpw@bitejiuyeke.com";
	char substr[] = "bitejiuyeke";
	char* ret = strstr(email, substr);
	if (ret == NULL)
		printf("子串不存在\n");
	else
		printf("%s\n", ret);
	return 0;
}

strstr的运行结果.png

strstr的模拟实现

有两种情况

情况一:一次匹配就找到了

情况二:多次匹配才能找到

模拟实现strstr的两种情况.png

char* my_strstr(const char* str1, const char* str2)
{
	assert(str1 && str2);
	const char* s1 = str1;
	const char* s2 = str2;
	const char* p = str1;
	while (*p)
	{
		s1 = p;
		s2 = str2;
		while (*s1 != '\0' && *s2 != '\0' && *s1 == *s2)
		{
			s1++;
			s2++;
		}
		if (*s2 == '\0')
		{
			return (char*)p;
		}
		p++;
	}
	return NULL;
}
int main()
{
	char email[] = "zpw@bitejiuyeke.com";
	char substr[] = "bitejiuyeke";
	char* ret = my_strstr(email, substr);
	if (ret == NULL)
		printf("子串不存在\n");
	else
		printf("%s\n", ret);
	return 0;
}

模拟实现strstr的结果.png

9.strtok

char* strtok(charstr,const char sep)

切割字符串 具有记忆功能

spe参数是个字符串,定义了用作分隔符的字符集合

第一个参数指定一个字符串,它包含了0个或者多个由sep字符串中一个或者多个分隔符分割的标记

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

strtok函数会改变被操作的字符串,所以在使用strtok函数切分的字符串一般都是临时拷贝的内容并且可以修改

strtok函数的第一个参数不为NULL,函数将找到str中第一个标记,strtok函数将保存它在字符串中的位置

strtok函数的第一个参数为NULL,函数将在同一个字符串中被保存的位置开始,查找下一个标记

如果字符串中不存在更多的标记,则返回NULL指针

int main()
{
	const char* sep = "@.";//分隔符
	char email[] = "zhangpengwei@bitejiuyeke.com";
	char cp[30] = { 0 };
	strcpy(cp, email);
    strcpy(cp, email);

char* ret = NULL;
for (ret = strtok(cp, sep);ret != NULL;ret = strtok(NULL, sep))
{
	printf("%s\n",ret);
}
	/*char* ret =  strtok(cp, sep);
	printf("%s\n", ret);
	ret = strtok(NULL, sep);
	printf("%s\n", ret);
	ret = strtok(NULL, sep);
	printf("%s\n", ret);*/
	return 0;
}

strtok的结果.png

10.strerror

char*strerror(int errnum);

返回错误码,所对应的错误信息

C语言的库函数,在执行失败的时候,都会设置错误码

//0 1 2 3 4 5 6 7

#include<errno.h>
int main()
{

	/*printf("%s\n", strerror(0));
	printf("%s\n", strerror(1));
	printf("%s\n", strerror(2));
	printf("%s\n", strerror(3));*/


	//errno-C语言设置的一个全局的错误码存放的变量
	FILE* pf = fopen("test.txt", "r");//fopen是指打开文件,r是指读
	if (pf == NULL)
	{
		printf("%s\n", strerror(errno));
		return 1;
	}
	else
	{

	}
	return 0;
}

strerror的结果.png

strerror的第二种结果.png

字符分类函数

字符分类函数.jpg

字符转换函数

字符转换函数.jpg

字符转换函数2.jpg

#include<ctype.h>
int main()
{
/*	int a = isspace(' ');
	printf("%d\n", a);*///结果为8
	int a = isdigit('0');
	printf("%d\n", a);//结果为非0的数字
	int a = isdigit('x');
	printf("%d\n", a);//结果为0
	return 0;
}

11.memcpy

内存拷贝

负责拷贝两块独立空间中的数据,无法进行重叠内存的拷贝

void *memcpy(void *destination,const void * source,size_t num);num是字节数

函数memcpy从source的位置开始向后复制num个字节的数据到destination的内存位置。

这个函数在遇到'\0'的时候并不会停下来

如果source和destination有任何的重叠,复制的结果都是未定义的。

int main()
{
	int arr1[] = { 1,2,3,4,5,6,7 };
	int arr2[10] = { 0 };
	memcpy(arr2, arr1, 28);
    
    float arr3[5]={1.0,2.0,3.0,4.0,5.0};
    float arr4[10]={0.0};
    memcpy(arr4,arr3,20);

	return 0;
}
//模拟实现

void* my_memcpy(void* dest, const void* src, size_t num)//对于内部拷贝无效
{
	assert(dest && src);
	void* ret = dest;
	while (num--)
	{
		*(char*)dest = *(char*)src;
		dest = (char*)dest + 1;
		src = (char*)src + 1;
	}
	return ret;
}

int main()
{
	int arr1[] = { 1,2,3,4,5,6,7 };
	int arr2[10] = { 0 };
	my_memcpy(arr2, arr1, 28);

	return 0;
}