字符函数和字符串函数

strlen函数

strlen是用来统计字符串\0之前的字符的个数

size_t strlen ( const char * str );

由此可见strlen的返回类型是size_t   参数类型是const char*

#include<string.h>
int main()
{
	char* p1 = "abcdef";

	//传递的是char* 类型变量
	printf("%d\n", strlen(p1));

	//传递的是首字符'a'的地址
	printf("%d\n", strlen("abcdef"));

	return 0;
}

bd42b865384e45a29662de5c1a41d6c8.png

//这里要注意strlen函数的返回类型是size_t,是无符号整型
#include<string.h>
int main()
{
	size_t len1 = strlen("abc");
	size_t len2 = strlen("abcdef");
	//这里要注意len1-len2=-3
	// 但是数字在内存中以二进制补码形式存储
	// 原码 10000000 00000000 00000000 00000011
	// 反码 11111111 11111111 11111111 11111100
	// 补码 11111111 11111111 11111111 11111101-----这个就是-3在内存中实际的存储情况
	// 但是当要计算这两个数字相减时,因为是size_t类型,是无符号整型,
	// 在取出时就会把1看作是数据位而不是符号位,那么就是正数,原码反码补码相同
	// 那么取出的数据就是  4,294,967,293,远远大于0
	//
	//

	if (len1 - len2 > 0)
	{
		printf("hehe\n");
		printf("%zu\n", len1 - len2);
	}
	else
	{
		printf("haha\n");
	}
	return 0;
}

ac909124c9ce44f28bed75ccee881e21.png

模拟实现strlen函数

方法一

//计数器加法
#include<assert.h>
size_t my_strlen(const char* p)
{
	assert(p);
	size_t rst = 0;
	while (*p)
	{
		p++;
		rst++;
	}
	return rst;
}
int main()
{
	char* p = "abcdef";
	size_t rst = my_strlen(p);
	printf("%zu\n", rst);
	return 0;
}

方法二

 //函数递归的方法
size_t my_strlen(const char* p)
{
	assert(p);
	if (*p == '\0')
	{
		return 0;
	}
	else
		return 1 + my_strlen(p + 1);
}
int main()
{
	char* p = "abcdef";
	size_t rst = my_strlen(p);//长度是6
	printf("%zu\n", rst);
	return 0;
}

方法三

//指针相减的方法
size_t my_strlen(const char* p)
{
	assert(p);
	char* p1 = p;
	while (*p1)
	{
		p1++;
	}
	return p1 - p;
}


int main()
{
	char* p = "abcdef";
	size_t rst = my_strlen(p);
	printf("%zu\n", rst);
	return 0;
}

strcpy函数

strcpy函数是用来实现字符串的拷贝的

char* strcpy(char * p1, const char *  p2);

strcpy函数的返回类型是char* ,返回的是待拷贝字符串的起始地址

参数类型也是char*,和    const char*,以保证模版不会被修改

p1是等待拷贝的字符串地址,p2是字符串模版

在拷贝时,一直拷贝到遇到字符串模版的\0,并且\0也要拷贝,\0拷贝下来后拷贝结束,所以字符串模版必须要有\0

#include<string.h>
int main()
{
	char arr1[15] = { "xxxxxxxxxx" };
	char arr2[] = { "hello\0haha" };
	//strcpy函数在拷贝时已知拷贝到模版的\0拷贝才停止,\0也要拷贝
	//\0拷贝下来后就不再拷贝
	strcpy(arr1, arr2);
	return 0;
}

4c404f208dbc4933bde0874d3f230675.png

注意

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

2.目标空间必须可变。

3.字符串模版必须要有\0,只有把模版的\0 拷贝下来,拷贝才停止

1.目标空间必须足够大,以确保能存放源字符串。9087a08f4f5e46e284c5366791d7ddb1.png

2.目标空间必须可变。5444a27370e74ba1818ee0a52b54cfa7.png

模拟实现strcpy函数

#include<assert.h>
char* my_strcpy(char* str1, const char* str2)
{
	assert(str1 && str2);
	char* p = str1;
	//先赋值再++,当str2为\0时赋值给str1然后()里面的内容就是0,停止循环
	while (*str1++ = *str2++)
	{
		;
	}
	return p;
}
int main()
{
	char arr1[15] = { "xxxxxxxxxx" };
	char arr2[] = { "hello\0haha" };
	//strcpy函数在拷贝时已知拷贝到模版的\0拷贝才停止,\0也要拷贝
	//\0拷贝下来后就不再拷贝
	char* p = my_strcpy(arr1, arr2);
	printf("%s\n", arr1);
	return 0;
}

b7a3a6ce07364401a0f074aa243dfc7c.png

strcat函数

strcat函数是用来实现字符串的追加的

char * strcat ( char * p1, const char * p2 );

函数的返回类型是char,参数类型char  和const  char*

在p1指向 的字符串末尾追加字符串,可以修改

p2指向的是被追加的字符串,所以不可修改

追加方式是在p1指向字符串的\0处追加p2指向的字符串,p1处的\0被p2指向字符串的第一个字符替代

p2指向的字符串被完整的追加到p1后面,包括\0

#include<string.h>
int main()
{
	char arr1[20] = { "hello \0xxxxxxxxx" };
	char arr2[] = { "world" };

	//在arr1的第一个\0处追加字符串"world\0",arr1的第一个\0 被字符'w'替换
	strcat(arr1, arr2);
	return 0;
}

d85a52ab58e5448ba4e03bf4c422715b.png

注意

1.目标空间必须可修改

2.目标空间必须足够大

3.目标空间必须有\0(以保证能找到目标空间的末尾)

4.原字符串必须也有\0,拷贝时拷贝到\0结束

模拟实现strcat函数

#include<assert.h>
char* my_strcat(char* str1, const char* str2)
{
	assert(str1 && str2);
	char* p = str1;
	//首先找到目标空间的末尾,第一个\0处
	while (*str1)
	{
		str1++;
	}
	//从末尾开始替换,直到模版字符串的结束
	while (*str1++ = *str2++)
	//*str1		\0	x	x	x	x	x
	//*str2		w	o	r	l	d	\0
	//先把'w'赋给\0 然后str1和str2再++,把o替换x   r替换x
	//
	{
		;
	}
	return p;
}

int main()
{
	char arr1[20] = { "hello \0xxxxxxxxx" };
	char arr2[] = { "world" };

	//在arr1的第一个\0处追加字符串"world\0",arr1的第一个\0 被字符'w'替换
	char* p = my_strcat(arr1, arr2);
	printf("%s\n", arr1);

	return 0;
}

2aee9b0bf1ca48db81a004cf5e76c371.png

strcmp函数

strcmp函数是用来比较字符串的

比较的不是字符串的长度而是字符串对应位置上的字符的大小

0ba0099941984a138d561f65d74f7d6f.png

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

函数的返回类型是int。   参数类型都是const char*

如果str1>str2 就返回一个大于0的数字

如果str1==str2 就但会一个0

如果str1<str2就返回一个小于0的数字

edfd1998f9954e8b80e023e39ccca145.png

模拟实现strcmp

#include<assert.h>
int my_strcmp(const char* str1, const char* str2)
{
	assert(str1 && str2);
	//如果两个指针对应的字符相等
	while (*str1 == *str2)
	{
		//\0就说明两个字符串都已经结束了,且在结束前对应位置的字符相同
		if (*str1 == '\0')
		{
			return 0;
		}
		str1++;
		str2++;
	}
	//说明两个字符串不相等
	return *str1 - *str2;
	
}


int main()
{
	char arr1[] = { "abcdef" };
	char arr2[] = { "abq" };
	int rst = my_strcmp(arr1, arr2);
	printf("%d\n", rst);
	return 0;
}

5b8954aaaed844428215f81eb85baab2.png

strncpy函数

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

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

strncpy和strcpy相比多了一个size_t  num

这里的num是要拷贝的字符的个数

03efaf1b85f94abeaeced57f000f1df5.png

strncat函数

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

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

strncat比strcat多了个函数参数size_t num

这里的num是表示要追加的字符个数

f6deb10d15c84c838e6c85a56d7eedf2.png

strncmp函数

int strncmp ( const char * str1, const char * str2, size_t num );

这里的num是指需要比较的字符个数

e5b4ceeac6924c4a9af0dbb486483993.png

strstr函数

strstr函数

函数的功能是在字符串中找出是否有另一个字符串

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

函数的返回类型是const  char*

参数类型是const char*

注意str1是模版

在str1中如果能找到str2,就返回str1中str2第一次出现的位置

如果在str1中不能找到str2,就返回NULL

#include<string.h>
int main()
{
	char arr1[] = { "abcdefbcd" };
	char arr2[] = { "bcd" };
	char arr3[] = { "xxxx" };
	//这里可以找到字符串bcd,返回的是第一次找到bcd的位置
	char* p1 = strstr(arr1, arr2);
	//这里找不到字符串xxxx,返回NULL
	char* p2 = strstr(arr1, arr3);
	printf("%s\n", p1);
	printf("%s\n", p2);
	return 0;
}

d5efdece8e5f4be8bc25dae306b3972f.png

模拟实现strstr函数

#include<assert.h>
const char* my_strstr(const char* str1, const char* str2)
{
	assert(str1 && str2);
	//s1和s2是作为标志,来遍历两个字符串
	const char* s1;
	const char* s2;
	//p1是记录在arr1中第一次找到与arr2中字符串相同的位置
	const char* p1;

	// 如果要在模版中找空字符串,就直接返回模版字符串的首地址
	if (*str2 == '\0')
	{
		return str1;
	}
	p1 = str1;
	// 如果标志p1遍历到\0也就是把模版字符串遍历完停下
	while (*p1)
	{
		//让遍历的指针从标志开始
		s1 = p1;
		s2 = str2;
		//当s1和s2指向的字符相同且都不为\0 进入循环
		while (*s1 && *s2 && *s1 == *s2)
		{
			s1++;
			s2++;
			//s1++,s2++比较下一个字符是否相同
		}
		//当跳出while循环,并且s2为\0,说明就s2被遍历了一遍,
		//此时就在模版中找到了字符串,就返回p1记录的位置
		if (*s2 == '\0')
		{
			return p1;
		}
		p1++;
	}
	//如果在前面没有返回就说明在模版字符串中没有找到,返回NULL
	return NULL;
	
}

int main()
{
	char arr1[] = { "abbbcdef" };
	char arr2[] = { "bbc" };
	char arr3[] = { "xxxx" };
	//这里可以找到字符串bcd,返回的是第一次找到bcd的位置
    const char* p1 = my_strstr(arr1, arr2);
	//这里找不到字符串xxxx,返回NULL
	const char* p2 = my_strstr(arr1, arr3);
	printf("%s\n", p1);
	printf("%s\n", p2);
	return 0;
}

1a0c2660688f4b2094e4741ef4698679.png

strtok

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

函数的返回类型是char*

用来切割字符串的

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

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

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

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

并且可修改。)

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

中的位置。

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

记。

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

#include<string.h>
int main()
{
	char arr1[] = { "hello*world#haha" };
	char arr2[20] = { 0 };
	//在进行strtok分隔函数时,会对字符串修改,所以调用strcpy函数拷贝副本
	strcpy(arr2, arr1);

	char* p = "#*";//这里把'#'和'*'都当作字符串的分隔符

	//第一次,传递非空指针时从起始位置向后找
	char* s1 = strtok(arr2, p);
	//在调用strtok函数时,arr2数组的字符串遇到#或者*时,就会把#或者*替换成\0,并保存#或者*的位置
	// 如在第一次遇到*时会把*替换成\0并保存\0所在的位置
	// 最后返回的是h的地址
	printf("%s\n", s1);


	//当第二次,传递空指针时,就从上一次保存的位置开始找,也就是\0的位置
	char* s2 = strtok(NULL, p);
	//这一次把#替换成\0 并保存\0所在位置
	// 返回w的地址
	printf("%s\n", s2);

	
	//第三次,传递空指针就从上一次保存的位置开始找,也就是\0的位置
	char* s3 = strtok(NULL, p);
	//这一次没有#或者*就直接返回haha中h的地址
	printf("%s\n", s3);

	char* s4 = strtok(NULL, p);
	//因为上一次调用没用找到#或者* ,所以这一次调用返回空指针


	return 0;
}

f4a6b9e05ca547f1a278f6b3af053d4c.png


#include<string.h>

int main()
{
	char arr1[] = { "hello#world*haha" };
	char arr2[20] = { 0 };
	strcpy(arr2, arr1);

	char* s = NULL;
	char* p = "*#";
	for (s = strtok(arr2, p); s != NULL; s = strtok((NULL), p))
	{
		printf("%s\n", s);
	}
	return 0;
}

57e75ec52d854ed9a150b08aba71c8e4.png

strerror函数

是将错误码翻译成错误信息,返回错误信息字符串的起始地址

在C语言中使用库函数时,如果发生错误就会把错误码放在errno变量中

errno是全局变量

char * strerror ( int errnum );

函数的返回类型是char*,返回的是错误信息字符串的起始地址

参数类型是int

5bec7b9b24a74684bb8f68fbe83a683f.png

字符分类函数和字符转换转换函数

   这些函数的头文件都是#include<ctype.h>

字符分类函数

efc3f88133ef4a6d9f3914847bb843b2.png

int islower ( int c );

判断字母是不是小写字母,如果是小写字母就返回一个非0的数字,如果不是,就返回0

int main()
{
	//判断是不是小写字母,是返回一个非0的值,不是返回0
	int rst1 = islower('a'); 
	printf("%d\n", rst1);
	//判断是不是十进制数字0~9,是返回一个非0的值,不是返回0
	int rst2 = isdigit('9');
	printf("%d\n", rst2);

	//判断是不是十六进制数字0~9包括大写字母A~F和小写字母a~f,是返回一个非0的值,不是返回0
	int rst3 = isxdigit('F');
	printf("%d\n", rst3);
	return 0;
}

f96d92554e944018b45542a4ad6754b9.png

字符转换函数

int tolower ( int c );

int toupper ( int c );

函数要包含头文件<ctype.h>

tolower是把大写字母转换成小写字母,toupper是把小写字母转化为大写字母

函数的参数类型是int,传递的是字母的ASCII码值,返回的也是字母的ASCII值

3ae7a27a44144edaa72629b45794914b.png

//把字符串Test String.\n转换成小写
#include<string.h>
int main()
{
	char arr[] = { "Test String.\n" };
	size_t i = 0;
	for (i = 0; i < sizeof(arr); i++)
	{
		//判断是不是大写字母,如果是就是非0,进入转换成小写
		if (isupper(arr[i]))
		{
			arr[i] = tolower(arr[i]);
		}
	}
	printf("%s", arr);
	
	return 0;
}

7e01013a111444efa2f367e178a1e3ef.png

memcpy

函数需要头文件<string.h>

void * memcpy ( void * destination, const void * source, size_t num );

函数的参数是把source中的内容拷贝到destination中,

num规定了拷贝的字节数,注意在拷贝时时一个字节一个字节的拷贝

用void* 作为函数的返回类型和参数类型,可以接收任意类型指针

返回的是目标空间的起始地址

//memcpy函数
#include<string.h>
int main()
{
	int arr1[10] = { 0 };
	int arr2[] = { 1,2,3,4,5 };
	memcpy(arr1, arr2, 20);
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		printf("%d ", arr1[i]);
	}
	printf("\n");
	return 0;
}

0d83c62a7e504ef49bb7613ee0f62793.png

memcpy函数的模拟实现

#include<assert.h>
void* my_memcpy(void* p1, const void* p2, size_t num)
{
	assert(p1 && p2);
	void* p = p1;
	size_t i = 0;
	while (i < num)
	{
		//void*类型不能进行+-和解引用操作,先强制类型转换然后解引用赋值
		*((char*)p1) = *((char*)p2);
		// void*类型先强制类型转换后+1
		p1 = (char*)p1 + 1;
		p2 = (char*)p2 + 1;
		i++;
	}
	return p;
}


int main()
{
	int arr1[10] = { 0 };
	int arr2[] = { 1,2,3,4,5 };
	void* p = my_memcpy(arr1, arr2, 20);
	return 0;
}

fa61c6288ee24cdf9a155cd4fe22f4bc.png

memmove函数

void * memcpy ( void * destination, const void * source, size_t num )

C语言标准规定:memcpy实现不重叠的内存拷贝,重叠的内存拷贝,用memmove实现

#include<string.h>
int main()
{
	//希望把前五个元素1,2,3,4,5拷贝到arr[2]arr[3]...这就导致内存重叠
	//用的函数就是memmove
	int  arr[] = { 1,2,3,4,5,6,7,8,9 };
	memmove(arr + 2, arr, 20);

	return 0;
}

bcee09c008a84008b6aa2a50486ed50f.png

模拟实现memmove函数

bf136258e1354b47ad91c6bf94363327.png

#include<assert.h>
void* my_memmove(void* p1, const void* p2, size_t num)
{
	assert(p1 && p2);
	void* p = p1;
	size_t i = 0;

	//模版在后面,从前往后拷贝
	if ((char*)p2 > ((char*)p1))
	{
		while (num--)
		{
			*(char*)p1 = *(char*)p2;
			p1 = (char*)p1 + 1;
			p2 = (char*)p2 + 1;
		}
	}
	else//模版在前面,从后往前拷贝
	{
		p1 = (char*)p1 + num - 1;
		p2 = (char*)p2 + num - 1;
		while (num--)
		{
			//*((char*)p1 + num) = *((char*)p2 + num);
			*(char*)p1 = *(char*)p2;
			p1 = (char*)p1 - 1;
			p2 = (char*)p2 - 1;
		}
	}
	return p;
}

int main()
{
	int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
	void* p = my_memmove(arr + 2, arr, 20);
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		printf("%d ", arr[i]);
	}
	return 0;
}

cc09e0b9b46a4ad6ab7ab85315b4035f.png

0705242e64484aacb19569f9dd98571f.png

memset

void*  memset(void* ptr,int value,size_t num)

函数的返回类型是void*

ptr是要替换的起始位置,

value 表示要替换的字符的ASCII值

num表示要替换的字符个数

//memset是以字节为单位设置内存的
#include<string.h>
int main()
{
	char arr1[] = { "hello world" };
	memset(arr1 + 6, 'x', 3);
	printf("%s\n", arr1);

//	int arr2[10] = { 0 };
//	memset(arr2, 1, 40);
//	//这样 并不能得到是个1
//	int i = 0;
//	for (i = 0; i < 10; i++)
//	{
//		printf("%d ", arr2[i]);
//	}
	return 0;
}

3067acae57cb4f588e863f07061a32bb.png

b9756a91ea8c46f6974fc99eaed07a7a.png

memcmp

int memcmp ( const void * ptr1, const void * ptr2,  size_t num );

与strcmp类似 ,也是以字节为单位进行比较,但是memcmp可以比较的类型不止char型int double等都可以比较

#include<string.h>
int main()
{
	int arr1[] = { 1,2,3,4,5,6,7 };
	int arr2[] = { 1,2,3 };
	int arr3[] = { 1,2,5 };
	int arr4[] = { 1,2,2 };

	int rst1 = memcmp(arr1, arr2, 12);
	int rst2 = memcmp(arr1, arr3, 12);
	int rst3 = memcmp(arr1, arr4, 12);

	printf("%d\n", rst1);
	printf("%d\n", rst2);
	printf("%d\n", rst3);

	return 0;
}

1bfdafdbcb114d939704f2dd1017b419.png

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值