C语言字符串函数的详解

一.字符串具体有哪些

求字符串的长度
strlen
长度不受限制的字符串函数
strcpy
strcat
strcmp
长度受限制的字符串函数介绍
strncpy
strncat
strncmp
字符串查找
strstr
strtok
错误信息报告
strerror

字符操作

内存操作函数
memcpy
memmove
memset
memcmp

二.具体的函数的介绍

1.strlen

size_t strlen ( const char * str );
/*
具体语法
字符串已经 '\0' 作为结束标志,strlen函数返回的是在字符串中 '\0' 前面出现的字符个数(不包
含 '\0' )。
size_t strlen ( const char * str );
参数指向的字符串必须要以 '\0' 结束。
注意函数的返回值为size_t,是无符号的( 易错 )
*/
具体的使用
int main() {

	char arr[] = "abc\0";
	printf("%d\n", strlen(arr));
	char brr[] = { 'a','b','c','\0'};
	printf("%d\n",strlen(brr));
	return 0;
模拟实现strlen
size_t my_strlen(const char* str)
{
	assert(str);
	const char* start = str;
	const char* end = str;
	while (*end != '\0')
	{
		end++;
	}
	return end - start;
}

int main()
{
	char arr[] = "abcdef";
	int len = my_strlen(arr);
	printf("%d\n", len);
	return 0;
}

2.长度受限制的字符串函数介绍

拷贝字符串
strcpy
剪切字符串
strcat
比较字符串
strcmp
下面让我一个一个去看这些方法的用法

  • strcpy
char* strcpy(char * destination, const char * source );
/*
Copies the C string pointed by source into the array pointed by destination, including the
terminating null character (and stopping at that point).
源字符串必须以 '\0' 结束。
会将源字符串中的 '\0' 拷贝到目标空间。
目标空间必须足够大,以确保能存放源字符串。
目标空间必须可变。

*/

具体用法

int main()
{
	char arr[10] = "xxxxxxxxx";
	const char* p = "abcdef";
	char arr2[] = { 'b', 'i', 't','\0'};

	strcpy(arr, p);
	strcpy(arr, arr2);

	printf("%s\n", arr);

	return 0;
}

这里我们监视变量就可以看出它是如何复制字符串的
在这里插入图片描述

模拟实现strcpy
这里模拟实现拷贝字符串的方法,是用指针相对调用而形成的

char* my_strcopy(char* dest,const char*src) {
	assert(dest);
	assert(src);
	char* ret = dest;
	while (*dest++ = *src++)
	{
		
		;
	}


	return dest;
}
int main() {
	char arr1[20] = "abc";
	char arr2[] = "helloworld";
	my_strcopy(arr1, arr2);
	printf("%s\n", arr1);
	return 0;
}

strcat函数的具体说明
这个函数以"\0"为标识的 进行追加的。

char * strcat ( char * destination, const char * source );
源字符串必须以 '\0' 结束。
目标空间必须有足够的大,能容纳下源字符串的内容。
目标空间必须可修改。

具体的用法

追加字符串
int main() {
	char arr1[20] = "hello";
	char arr2[20] = "world";
	strcat(arr1,arr2);
	printf("%s\n",arr1);
	return 0;

我们看图说话,目前看来可以说是以“\0”为追加的。
在这里插入图片描述

strcat的模拟实现

char* my_strcat(char*dest ,const char*src) {
	//1.找目标函数的\0
	char* cur = dest;
	while (*cur!='\0') {
		cur++;
	
	}
	//2..拷贝源头数据到\0之后
	while (*cur++ = *src++) {
		;  
	}
}
int main() {
	char arr1[20] = "hello \0xxxxxxxxxx";
	char arr2[] = "world";
	my_strcat(arr1,arr2);
	printf("%s\n",arr1);


	return 0;
}

strcmp 字符串的比较
这个函数就十分的简单,我就简单的说明一下,这个字符串比较函数,实际上就是一个一个字节字节的比对。
具体的使用

/*
实际上是一个字节一个字节的比较
实际上比较对应位置上字符的大小,而并非长度
*/
int main() {
	char arr1[] = "abcdef";
	char arr2[] = "abq";
	int ret = strcmp(arr1,arr2);
	printf("%d\n",ret);
	return 0;

}

具体的函数实现

int my_strcmp(const char* s1, const char* s2) {
	assert(s1 && s2);
	while (*s1 == *s2) 
 {
		if (*s1=='\0') 
		{
			return 0;
		}
		s1++;
		s2++;
	}
	if (*s1 > *s2) {

		return 1;
	}
	else {
		return -1;
	}
}
//字符串比较函数的实现
int main() {
	char arr1[] = "abc";
	char arr2[] = "abq";
	int ret=my_strcmp(arr1,arr2);
	if (ret > 0) {
		printf("arr1>arr2");
	}
	else if (ret < 0) {
		printf("arr1<arr2");
	}
	else {
		printf("arr1==arr2");
	}
	return 0;
}

这三组函数,长度受限制,顾名思义,我们做操作的时候,可以指定数量
strncpy

char * strncpy ( char * 目标, const char *, size_t num );
从字符串中复制字符
将source的前num个字符 复制到destination。如果在复制num个字符之前找到源C 字符串的结尾(由空字符表示) ,则用零填充目标,直到总共写入了num个字符。如果source长于num ,则不会在目标 末尾隐式附加空字符。因此,在这种情况下,目的地不应被视为以空结尾的 C 字符串(这样读取它会溢出)。目的地和
int main()
{
	char arr1[20] = "abcdefghi";
	char arr2[] = "xxxx";
	strncpy(arr1, arr2, 8);
	printf("%s\n", arr1);

	return 0;
}

strncat


int main()
{
	char arr1[20] = "abcdef\0qqqqqq";
	char arr2[] = "xyz";
	strncat(arr1, arr2, 2);
	printf("%s\n", arr1);

	return 0;
}

strncmp

int main()
{
	int ret = strncmp("abcdef", "abc", 4);
	printf("%d\n", ret);

	return 0;
}

3.字符串查找

strstr

char * strstr ( const char *str1, const char * str2);
定位子串
返回指向 str1 中第一次出现str2的指针,如果str2不是 str1 的一部分,则返回空指针。 匹配过程不包括终止的空字符,但它会停在那里。

这里大概的意思是,记录字串第一次出现的位置
具体用法

int main() {

	char arr1[] = "abcdef";
	char arr2[] = "bcd";
	char* p = strstr(arr1, arr2);
	if (p == NULL) {
		printf("不存在");
	}
	else
	{
		printf("%s\n",p);
	}
}

strstr 模拟实现
这个方法不好理解,我画个图大家理解一下

char* my_strstr(const char* str1, const char* str2)
{
	const char* s1 = str1;
	const char* s2 = str2;
	const char* p = str1;
	if (*str2 == '\0')
	{
		return 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 arr1[] = "abcdefabcdef";
	char arr2[] = "fab";

	char* p = my_strstr(arr1, arr2);
	if (p == NULL)
	{
		printf("不存在\n");
	}
	else
	{
		printf("%s\n", p);
	}
	return 0;
}

3.内存操作函数
memcpy

 memcpy 的函数用法
int main() {
	int arr[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
	int arr2[10] = { 0 };
	memcpy(arr2, arr, 20);
	float arr1[] = { 1.0f,2.0f,3.0f,4.0f };
	float arr2[] = { 0.0 };
	return 0;
}

具体模拟实现

// 如何自己实现memcpy
void* my_memcpy(void* dest,void* src,size_t num) {
	assert(dest);
	assert(src);
	void* ret = dest;
	while (num--)
	{
		*(char*)dest = *(char*)src;
		dest = (char*)dest + 1;
		src = (char*)src + 1;
	}
	return ret;
	
}
int main() {

	int arr[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
	int arr2[10] = { 0 };
	my_memcpy(arr2, arr, 20);
	int i = 0;
	for (i = 0; i < 10; i++) {
	
		printf("%d",arr2[i]);
	
	}
	float arr3[] = { 1.0f,2.0f,3.0f,4.0f };
	float arr4[] = { 0.0 };
	my_memcpy(arr4, arr3, 20);
	return 0; 
}

这里我们引入一个问题,如果我们自己拷贝自己的话
是否会成功吗?
试一试就知道了

int main()
{
	int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
	memcpy(arr1 + 2, arr1, 20);
	//memmove(arr1+2, arr1, 20);

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

运行截图
在这里插入图片描述
你看,我们这里,就出现了自己拷贝自己的问题,
简单来说,就是,我们正常拷贝的时候,会出现以下情况
在这里插入图片描述

所以我们拷贝数据有时候不能从前往后拷贝,有时候会覆盖,这样我们可以考虑从后向前拷贝,我把这样的情况分为以下三种情况
在这里插入图片描述

改进之后的代码,如下

void* my_memcpy(void* dest,void* src,size_t num) {
	assert(dest);
	assert(src);
	void* ret = dest;
	if (dest < src) 
	{//前->后
		while (num--)
				{
					*(char*)dest = *(char*)src;
					dest = (char*)dest + 1;
					src = (char*)src + 1;
				}
	
	}

	else { //从后向前
		while (num--) 
		{
			*((char*)dest + num) = *((char*)src + num); 
		}
	
	}
	return ret;
	
}

int main() {

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

	return 0; 
}

memmove

void * memmove ( void * dst, const void * src, size_t count) {
        void * ret = dst;
        if (dst <= src || (char *)dst >= ((char *)src + count)) {
                /*
                 * Non-Overlapping Buffers
比特就业课-专注IT大学生就业的精品课程 比特主页:https://m.cctalk.com/inst/s9yewhfr 比特就业课
本章完
                 * copy from lower addresses to higher addresses
                 */
                while (count--) {
                        *(char *)dst = *(char *)src;
                        dst = (char *)dst + 1;
                        src = (char *)src + 1;
               }
       }
        else {
                /*
                 * Overlapping Buffers
                 * copy from higher addresses to lower addresses
                 */
                dst = (char *)dst + count - 1;
                src = (char *)src + count - 1;
                while (count--) {
                        *(char *)dst = *(char *)src;
                        dst = (char *)dst - 1;
                        src = (char *)src - 1;
               }
       }
        return(ret);
}

memset

具体用法

int main() {
	int arr[] = { 1,2,3,4,5 };
	memset(arr, 0, 8);
	return 0;
}

memcmp

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

具体用法

memcmp的使用
int main() {
	int arr2[] = { 1,2,3,0,0 };
	int arr1[] = { 1,2,3,4,5 };
	int ret=memcmp(arr1, arr2,12);
	printf("%d\n",ret);
	return 0;

}

模拟实现

void * memcpy ( void * dst, const void * src, size_t count) {
        void * ret = dst;
 assert(dst);
   assert(src);
        /*
         * copy from lower addresses to higher addresses
         */
        while (count--) {
                *(char *)dst = *(char *)src;
                dst = (char *)dst + 1;
                src = (char *)src + 1;
       }
        return(ret);
}
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

忘忧记

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值