C语言:字符函数、字符串函数和内存函数

1.字符函数

        1.1字符分类函数

        C语言有一系列用于分类字符的函数,需要包含头文件 ctype.h 展示如下

#include<ctype.h>

int main()
{
	int ret = 0;
	ret = iscntrl('\n');//任何控制字符
	ret = isspace('\t');//空白字符,空格' ',制表符'\t',换行符'\n'等
	ret = isdigit('9');//十进制数字0~9
	ret = isxdigit('a');//十六进制数字0~9,a~f,A~F
	ret = islower('c');//小写字母
	ret = isupper('C');//大写字母
	ret = isalpha('B');//所有大小写字母
	ret = isalnum('8');//所有大小写字母和十进制数字
	ret = ispunct('?');//标点符号(不属于字母数字的可打印的)
	ret = isgraph('&');//任何图形字符
	ret = isprint(' ');//任何可以打印的字符
	return 0;
}

        当参数部分符合要求时,会返回“真”。

        1.2字符转换函数

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

int tolower(int c);//将字母大写转换为小写

int toupper(int c);//将字母小写转换为大写

        具体的使用如下:

int main()
{
	char arr2[] = "CIRNO";
	int i = 0;
	//把大写转化为小写
	while (arr2[i]!='\0')
	{
		if (isupper(arr2[i]) )
		{
			arr2[i] = tolower(arr2[i]);
		}
		i++;
	}
	//打印
	printf("%s\n", arr2);
	return 0;
}

int main()
{
	char arr1[] = "MineCraft";
	int i = 0;
	//把小写转化为大写
	while (arr1[i] != '\0')
	{
		if (islower(arr1[i]))
		{
			arr1[i] = toupper(arr1[i]);
		}
		i++;
	}
	//打印
	printf("%s\n", arr1);
	return 0;
}

        打印结果分别为

cirno
MINECRAFT

2.字符串函数

        该类函数需要包含头文件string.h

        2.1strlen的使用和模拟实现

size_t strlen(const char*str);

        函数统计字符串中'\0'前的字符个数.

#include<string.h>

int main()
{
	char arr[] = "minecraft";
	printf("%zd", strlen(arr));
	return 0;
}

        最终打印结果为9.

需要注意的是返回的是无符号整型,创建变量接收和打印时需要注意变量类型。

以下是模拟实现,

size_t my_strlen(const char* str)
{
	int count = 0;
	while (*str++ != '\0')
	{
		count++;
	}
	return count;
}

2.2strcpy的使用和模拟实现

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

        函数作用是复制一份字符串,返回值是目标函数的首地址。使用如下,

int main()
{
	char arr1[] = "try to copy";
	char arr2[20] = { 0 };
	strcpy(arr2, arr1);
	printf("%s\n", arr2);
	return 0;
}

        使用时要注意目标函数是否有足够的空间来放置字符串。

        以下是模拟实现,

char* my_strcpy(char* dest, const char* srce)
{
	char* ret = dest;
	while (*dest++=*srce++)
	{
		;
	}
	return ret;
}

 

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

​

      需要注意的一点是,复制过来的字符串带了一个'\0'作为结尾,所以在打印时,只会出现minecraft不会出现额外的x.

        2.3strcat的使用和模拟实现

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

        函数将来源的字符串接到目标字符串后。

        需要注意目标数组是否有足够的空间,返回的是目标函数的首地址.使用如下,

int main()
{
	char arr1[20] = "hello ";
	char arr2[20] = "world!";
	strcat(arr1, arr2);
	printf("%s\n", arr1);
	reiturn 0;
}
结果如下:
hello world!

        模拟实现时需要先让目标地址取到'\0',在进行类似strcpy的赋值操作.

char* my_strcat(char* dest, const char* srce)
{
	char* ret = dest;
	while (*dest != '\0')
		dest++;
	while (*dest++ = *srce++)
	{
		;
	}
	return ret;
}

        2.4strcmp的使用和模拟实现

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

        函数将两个字符串中的字符的ASCII的值分别进行比较,直到比出大小,返回值的正、负、0分别表示>、<、=,使用如下,

​
int main()
{
	char arr1[20] = "abc";
	char arr2[20] = "abd";
	int ret = strcmp(arr1, arr2);
    //打印值为一负数
	printf("%d\n", ret);
	return 0;
}

​

        模拟实现如下,

int my_strcmp(const char* p1, const char* p2)
{
	assert(p1 && p2);
	//保护传来的指针
	char* str1 = p1;
	char* str2 = p2;
	//跳过字符相同且不为字符'\0'的地址
	while (*str1!='\0' && *str2!='\0' && * str1 == *str2)
	{
		str1++;
		str2++;
	}
	//字符相同时相减得到对应的返回值
	return *str1 - *str2;
}

        2.5strncpy的使用和模拟实现

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

        函数是从来源空间中取num个字符拷贝到目标空间中,返回值为目标空间的首地址.其中strncpy中的n可以记为为num,使用如下,

int main()
{
	char arr1[] = "hello world!";
	char arr2[20] = "minecraft";
	strncpy(arr2, arr1, 5);
    // 将会打印出helloraft
	printf("%s\n", arr2);
	return 0;
}

num限制了拷贝的字符个数,某种意义上增强了函数的安全性。

        模拟实现类似strcpy,

​
char* my_strncpy(char* dest, const char* srce, size_t n)
{
    //防止指针为空指针
	assert(dest && srce);
	char* ret = dest;
	int i = 0;
    //循环n次拷贝n个字符
	for (i = 0; i < n; i++)
	{
		*dest = *srce;
		dest++;
		srce++;
	}
	return ret;
}

​

        2.6strncat的使用和模拟实现

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

        函数同理增加了一个衔接字符的个数限制,返回值为目标空间的首地址,使用如下,

int main()
{
	char arr1[20] = "hello ";
	char arr2[20] = "world";
	strncat(arr1, arr2, 3);
    //将会打印hello wor
	printf("%s\n", arr1);
	return 0;
}

        模拟实现如下,

char* my_strncat(char* dest, const char* srce, size_t num)
{
	assert(dest && srce);
	char* ret = dest;
	//使目标指针指向'\0'
	while (*dest != '\0')
	{
		dest++;
	}
	//循环num次,拷贝num个字符到目标空间中
	int i = 0;
	for (i = 0; i < num; i++)
	{
		*dest++ = *srce++;
	}
	return ret;
}

        2.7strncmp的使用

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

        函数分别比较两个空间中的num个字符数,返回值体现大小,使用如下,

int main()
{
	char arr1[] = "abcef";
	char arr2[] = "abcdf";
	int ret = strncmp(arr1, arr2, 3);//ret=0
	ret = strncmp(arr1, arr2, 4);//ret>0
	return 0;
}

        2.8strstr的使用和模拟实现

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

         函数将在指针str1指向的空间中寻找str指针指向空间的内容,找到了返回str1指向空间里找到的内容的起始指针,否则返回空指针。

int main()
{
	char arr1[20] = "abbbcdef";
	char arr2[] = "bbc";
	char* ret = strstr(arr1, arr2);
    //将会输出bbcdef
	printf("%s", ret);
	return 0;
}

        模拟实现如下,

char* my_strstr(const char* dest, const char* sele)
{
    //验证指针有效性
	assert(dest && sele);
    //保护目标指针,同时作为一个匹配基准点,用于移动
	const char* cur = dest;
    //当*cur为'\0'时结束循环
	while (*cur)
	{
		const char* str1 = cur;
		const char* str2 = sele;
        //不相等时跳过匹配
		if (*str1 != *str2)
		{
			str1++;
			cur++;
		}
        //相等且不为空时进行匹配
		while (*str1 == *str2 && *str1 != '\0' && *str2 != '\0')
		{
			str1++;
			str2++;
		}
        //找到相同内容时指针指向'\0',此时返回目标指针现在指向的地址
		if (*str2 == '\0')
		{
			return (char*) cur;
		}
        //否则匹配失败,目标指针++,继续寻找
		else
		{
			cur++;
		}
		
	}
    //结束循环的时候仍未返回值,说明未能找到,且此时*cur为空
	return (char*)cur;
}

        2.9strtok的使用

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

        函数的作用是在一串字符串中去掉选择的分隔符(如@等)其中str是目标空间,sep是分隔符组成的字符或者字符串,函数一次只能去除一个分隔符(即在第一个分隔符位置放一个'\0',且返回值指向这个'\0'),若要再次去除只需要给str传入一个空指针(同样是删除一个),如果不存在分隔符,则返回NULL。看上去去除分隔符需要多次操作,但是我们可以有如下解法。

​
int main()
{
	char arr[] = "114514.1919810.com";
	char *sep = ".";
	char* str = NULL;
	for (str = strtok(arr, sep); str != NULL;str=strtok(NULL,sep))
	{
        //分别输出 114514 1919810 com
		printf("%s\n", str);
	}
	return 0;
}

​

        

3.内存函数

        3.1memcpy的使用和模拟实现

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

        该函数功能和strncpy功能类似但是不在局限于字符数组,而且在拷贝时是一个字节一个字节进行拷贝。使用如下,

int main()
{
	int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };
	int arr2[20] = { 0 };
	memcpy(arr2, arr1, 20);
	int i = 0;
    //最终打印结果是1 2 3 4 5 0 0 0 0 0
	for (i = 0; i < 10; i++)
	{
		printf("%d ", arr2[i]);
	}
	return 0;
}

        模拟实现如下,

void* my_memcpy(void* dest, const void* srce, size_t num)
{
	assert(dest && srce);
    //保存地址
	void* ret = dest;
	int i = 0;
	while (num--)
	{
        //强制类型转换为char* 保证一次空间权限只有一个字节
		*(char*)dest = *(char*)srce;
		(char*)dest = (char*)dest + 1;
		(char*)srce = (char*)srce + 1;
	}
	return ret;
}

        这时候有人就要问了,如果在使用memcpy的时候传参的两个空间有重叠会发生什么。答案是不确定,因为编译器的实现的memcpy的方法不同,导致有的可以正常重叠,有些反之。但实际上,有一个专门用于实现重叠拷贝的函数——memmove.

        3.2memmove的使用和模拟实现

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

        同样是拷贝内容,同样是逐字节拷贝,但它拷贝的是重叠空间以下是它的使用。

int main()
{
	int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };
	int arr2[10] = { 1,2,3,4,5,6,7,8,9,10 };
    //将arr1开始的五个数拷贝到arr1+2开始的五个数处
	memmove(arr1 + 2, arr1, 20);
    //将arr2+2开始的五个数拷贝到arr2开始的五个数处
	memmove(arr2, arr2 + 2, 20);
	int i = 0;
    //打印结果是1 2 1 2 3 4 5 8 9 10
	for (i = 0; i < 10; i++)
	{
		printf("%d ", arr1[i]);
	}
	printf("\n");
    //打印结果是3 4 5 6 7 6 7 8 9 10
	for (i = 0; i < 10; i++)
	{
		printf("%d ", arr2[i]);
	}
	return 0;
}

        模拟实现如下,

void* my_memmove(void* dest, const void* srce, size_t num)
{
	assert(dest && srce);
	void* ret = dest;
    //当源空间地址小于目标空间的地址时,需要从后往前拷贝
	if (*(char*)srce <= *(char*)dest)
	{
		while (num--)
		{
			*((char*)dest + num) = *((char*)srce + num);
		}
	}
    //当源空间的地址大于目标空间的地址时,需要从前往后拷贝
	else
	{
		while (num--)
		{
			*(char*)dest = *(char*)srce;
			(char*)dest = (char*)dest + 1;
			(char*)srce = (char*)srce + 1;
		}
	}
}

        3.3memset的使用

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

        函数的作用是将num个字节在ptr指向的空间中改成value,如下

int main()
{
	char arr[] = "hello world!";
	memset(arr, 'x', 5);
    //将会打印出 xxxxx world!
	printf("%s\n", arr);
	return 0;
}

        3.4memcmp的使用

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

        和strncmp类似,比较从ptr1和ptr2指向开始,向后的num个字节,返回值表示大小.

int main()
{
	int a[5] = { 1,2,3,4,5 };
	int b[10] = { 256,5,6,7,8 };
	int ret=memcmp(a, b, 1);
    //比较一个字节a为1,b为0;所以返回值>0
	printf("%d\n", ret);
	return 0;
}

最后的最后,咱才发现可以直接贴代码

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值