字符串函数和内存函数

字符串函数和内存函数

strlen函数的模拟实现

1.字符串已经 ‘\0’ 作为结束标志,strlen函数返回的是在字符串中 ‘\0’ 前面出现的字符个数(不包含 ‘\0’ )。

2.参数指向的字符串必须要以 ‘\0’ 结束。

3.注意函数的返回值为size_t,是无符号的( 易错 )

int main()
{
	if( strlen("abc") - strlen("abcde") > 0)
	{
		printf("> \n");

	}
	else
	{
		printf("<= \n");
	}
	return 0;
}

在这里插入图片描述

例:模拟实现strlen


//模拟实现strlen
int my_strlen(const char* str)
{
	int count = 0;
	assert(str != NULL);//断言str不是空指针
	while (*str != '\0')//判断str是否是\0,strlen遇到\0结束
	{
		count++;
		str++;
	}
	return count;
}
int main()
{
	char arr[] = "abcd";
	int len = my_strlen(arr);
	printf("%d \n", len);
	return 0;
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xMOYVBbZ-1633147514895)(C:\Users\32108\AppData\Roaming\Typora\typora-user-images\image-20210929185222697.png)]

strcpy函数的模拟实现

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oGeHsbfs-1633147514897)(C:\Users\32108\AppData\Roaming\Typora\typora-user-images\image-20210930191819231.png)]

1.源字符串必须以 ‘\0’ 结束。
2. 会将源字符串中的 ‘\0’ 拷贝到目标空间。

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

4.目标空间必须可变。

例:模拟实现strcpy

//模拟实现strcpy
char* my_strcpy(char* dest, const char* src)
{
    assert(dest != NULL);
    assert(src != NULL);
    char* ret = dest;
    //拷贝src指向的字符串到dest指向的空间 包含'\0'
    while (*src != '\0')
    {
        *dest = *src;
        dest++;
        src++;
    }
    *dest = *src;//'\0'
    return ret;//返回目的空间的起始地址
}

int main()

{
    char arr1[] = "abcdefghi";
    char arr2[] = "bit";
    my_strcpy(arr1, arr2);

    printf("%s\n", arr1);
    return 0;

}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fc4rBfOl-1633147514901)(C:\Users\32108\AppData\Roaming\Typora\typora-user-images\image-20210930192033283.png)]

strcat函数的模拟实现

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NrCXKLqU-1633147514904)(C:\Users\32108\AppData\Roaming\Typora\typora-user-images\image-20210930192315303.png)]

1.源字符串必须以 ‘\0’ 结束。

2.目标空间必须有足够的大,能容纳下源字符串的内容。

3.目标空间必须可修改。

例:模拟实现strcat

模拟实现strcat(字符串追加)
char my_strcat(char* dest, const char* src)
{
	char* ret = dest;
	assert(dest != NULL);
	assert(src != NULL);
	while (*dest)//1.寻找\0
	{
		dest++;
	}
	while (*dest++ = *src++)//2.追加字符world
	{
		;
	}
	return ret;
}
int main()
{
	char arr[20] = "hello";
	char arr2[] = " world";
	my_strcat(arr, arr2);
	printf("%s \n",arr);
	return 0;
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-75bo9KZO-1633147514905)(C:\Users\32108\AppData\Roaming\Typora\typora-user-images\image-20210930192634072.png)]

strcmp函数的模拟实现

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5ze6yVXW-1633147514907)(C:\Users\32108\AppData\Roaming\Typora\typora-user-images\image-20210930202224944.png)]

第一个字符串大于第二个字符串,则返回大于0的数字

第一个字符串等于第二个字符串,则返回0

第一个字符串小于第二个字符串,则返回小于0的数字

例:模拟实现strcmp

//模拟实现strcmp(比较)
int my_strcmp(const char* s1, const char* s2)
{
	assert(s1 && s2);
	while (*s1 == *s2)
	{
		if (s1 == '\0')
		{
			return 0;
		}
		s1++;
		s2++;
	}
	return *s1 - *s2;
}
int main()
{
	char m[] = "abcde";
	char n[] = "abcce";
	int ret = my_strcmp(m, n);
	if (ret > 0)
	{
		printf(" m > n \n");
	}
	else if (ret < 0)
	{
		printf("m < n \n");

	}
	else if (ret == 0)
	{
		printf("m = n \n");
	}
	return 0;
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FpT3l5f6-1633147514908)(C:\Users\32108\AppData\Roaming\Typora\typora-user-images\image-20210930202407080.png)]

strstr函数的模拟实现

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-c5Hblr21-1633147514910)(C:\Users\32108\AppData\Roaming\Typora\typora-user-images\image-20210930212421984.png)]

在str1中查找是否包含str2数组

例:模拟实现strstr

//模拟实现strstr
char* my_strstr(const char* str1, const char* str2)
{
	assert(str1 && str2);
	const char* s1 = NULL;
	const char* s2 = NULL;
	char* cp = str1;
	while (*cp)
	{
		s1 = cp;
		s2 = str2;
		while (*s1 && *s2 && (*s1 == *s2))
		{
			s1++;
			s2++;
		}
		if (*s2 == '\0')
		{
			return cp;
		}
		cp++;
	}
	return NULL;
}
int main()
{
	char arr1[] = "abcdef";
	char arr2[] = "cde";
	char* ret = my_strstr(arr1, arr2);
	printf("%s \n", ret);
	return 0;
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-19SykTii-1633147514911)(C:\Users\32108\AppData\Roaming\Typora\typora-user-images\image-20210930212703645.png)]

strtok函数

> char * strtok ( char * str, const char * delimiters );

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

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

strtok函数找到str中的下一个标记,并将其用 \0 结尾,返回一个指向这个标记的指针。(注:strtok函数会改 变被操作的字符串,所以在使用strtok函数切分的字符串一般都是临时拷贝的内容并且可修改。)

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

strtok函数的第一个参数为 NULL ,函数将在同一个字符串中被保存的位置开始,查找下一个标记。 如果字符串中不存在更多的标记,则返回 NULL 指针。

例:实现strtok函数

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <assert.h>
#include <string.h>

int main()
{
	char arr[] = "chang@qq.com love";
	char* tmp = "@. ";
	char ret[40] = { 0 };
	strcpy(ret, arr);//ret复制arr,分割不改变原地址内容
	char* cp = NULL;
	for (cp = strtok(ret, tmp); cp != NULL; cp = strtok(NULL, tmp))
	{
		printf("%s\n ", cp);
	}
	return 0;
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-veJfHHUt-1633147514912)(C:\Users\32108\AppData\Roaming\Typora\typora-user-images\image-20211001122925355.png)]

传入一份临时拷贝的字符串给str,因为不想要源字符串被真正的分割.
对于同一个字符串,第一次调用,必须传入地址,第二次以及多次传入NULL
对于strtok的妙用一般是使用for循环.
未分割完时,返回值是被分割的小段字符串的首地址,分割完时,返回NULL

strerror函数的实现

> char * strerror ( int errnum )

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

#include <stdio.h> 
#include <string.h> 
#include <errno.h>//必须包含的头文件

例:实现strerror

//实现strerror(错误信息报告)

int main()
{	//打开失败返回NULL
	FILE* pf = fopen("tetx.txt", "r");
	if (pf == NULL)
	{
		printf("%s \n", strerror(errno));
		return 1;
	}
	fclose(pf);//关闭文件
	return 0;
 }

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uhRK8wuT-1633147514915)(C:\Users\32108\AppData\Roaming\Typora\typora-user-images\image-20211001165423451.png)]

perror函数

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JOfr8ue8-1633147514917)(C:\Users\32108\AppData\Roaming\Typora\typora-user-images\image-20211001165823318.png)]

字符分类函数

iscntrl 任何可控字符
isspace 空白字符:空格, \f(换页), \n(换行),\t(水平制表符),\r(回车),\v(锤子制表符)
isdigit 检验十进制数字 0 ~ 9
isxdigit 检验16进制数字包括所有十进制数字,小写字母af,大写字母AF
islower 检验是否是小写字母 a ~ z
isupper 检验是否是大写字母 A ~ Z
isalpha 检验是都是字母 a ~ z 和 A ~ Z
isalnum 检验是否是数字和字符 0~9 a~z A~Z
ispunct 标点符号,任何不属于数字或者字母的图形字符(可打印)

isgraph 任何图形字符

isprint 任何可打印字符,包括图形字符和空白字符

//字符分类函数
int main()
{
	char arr[] = "heLLo 123";
	printf("%d \n", islower(arr[2]));
	printf("%d \n", isupper(arr[3]));
	printf("%d \n", isalnum(arr[7]));
	return 0;
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tOLZ0O0B-1633147514918)(C:\Users\32108\AppData\Roaming\Typora\typora-user-images\image-20211001173939097.png)]

如果字符分类函数返回非0数,如果不是返回0

内存函数

memcpy函数

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

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

2.这个函数在遇到 ‘\0’ 的时候并不会停下来。

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

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Tlb9A8pr-1633147514920)(C:\Users\32108\AppData\Roaming\Typora\typora-user-images\image-20211001190349930.png)]

例:模拟实现memcpy

void* my_memcpy(void* dest, const void* str, size_t num)
{
	void* ret = dest;
	assert(dest && str);
	while (num--)
	{
		*(char*)dest = *(char*)str;
		dest = (char*)dest + 1;
		str = (char*)str + 1;

	}
	return ret;
}
int main()
{
	char arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };
	char arr2[10] = { 0 };
	my_memcpy(arr2, arr1, 16);
	for (int i = 0; i < 4; i++) 
	{
		printf("%d ", arr1[i]);
	}

	return 0;
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2aBnhYnz-1633147514921)(C:\Users\32108\AppData\Roaming\Typora\typora-user-images\image-20211002115244645.png)]

memove函数

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

1.和memcpy的差别就是memmove函数处理的源内存块和目标内存块是可以重叠的。

2.如果源空间和目标空间出现重叠,就得使用 比特科技 memmove函数处理。

例:模拟实现memove


//模拟实现memmove
void* my_memmove(void* dest, const void* str, size_t num)
{
	void* ret = dest;
	assert(dest && str);
	if (dest > str)
	{
		while (num--)
		{
			*(char*)dest = *(char*)str;
			dest = (char*)dest + 1;
			str = (char*)str + 1;

		}
	}
	else
	{
		while (num--)
		{
			*((char*)dest + num) = *((char*)str + num);

		}
	}
	
	return ret;
}
int main()
{
	int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };
	my_memmove(arr1 + 2, arr1, 16);
	for (int i = 0; i < 10; i++)
	{
		printf("%d ", arr1[i]);
	}
	printf("\n");

	return 0;
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ajpP0XRE-1633147514922)(C:\Users\32108\AppData\Roaming\Typora\typora-user-images\image-20211002115828896.png)]

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值