C语言 | 字符串相关函数

本文详细介绍了C/C++中常用的字符串函数如strlen、strcpy、strcat等,并通过模拟实现加深理解,涵盖strcmp、strncpy、strstr、strtok等,还有内存操作函数如memcpy、memmove和memcmp。适合提升字符串操作技巧。
摘要由CSDN通过智能技术生成

        本文重点为大家讲解一些常见的字符拆函数的使用,以及实现,比如求字符长度函数strlen、字符串拷贝函数strcpy、字符串拼接strcat、字符串比较strcmp等等函数。

目录

一、strlen函数 

 1、strlen的使用

 2、strlen的模拟实现

二、 strcpy与strncpy函数

1、strcpy和strncpy的使用

2、strcpy和strncpy的模拟实现

三、strcmp和strncmp函数 

1、strcmp和strncmp的使用

2、strcmp和strncmp的模拟实现

四、strcat和strncat函数 

1、strcat和strncat的使用

2、strcat和strncat的模拟实现

五、strstr函数 

1、strstr函数的使用

2、strstr函数的模拟实现

六、strtok函数

1、strtok的使用 

七、memcpy和memmove函数 

1、memcpy和memmove的使用

2 、memcpy和memmove的模拟实现

八、memcmp函数

 1、memcmp函数的使用

 2、memcmp函数的模拟实现


一、strlen函数 

strlen函数是求字符串长度的函数,头文件为string.h。 下图MSDN查阅结果; 

 

返回值 :

 返回值是size_t类型,size_t类型实际上是无符号整型(unsigned int)

参数: 

该函数只有一个参数,类型为 const char*

补充 :const char* str 和char* const str的区别

        const修饰指针变量时,可以放在星号左边,也可以放在星号右边,这两种写法有什么区别呢?

        当const放在星号左边时, 修饰其指针指向的的数据不可变,当const放在星号右边时,其指针的指向不可变,例

int a = 5;

int b = 2;

const int* pi = &a;

此时我们不能够修改指针指向的那块区域的值,但是我们可以修改指针的指向,即

*pi = 2;  //这里为错误代码

pi = &b; //这里为正确代码

 1、strlen的使用

#include <stdio.h>
#include <string.h>

int main()
{
	char* str = "abcde";
	int ret = strlen(str);
	printf("%d\n", ret);
	return 0;
}

 2、strlen的模拟实现

strlen的实现原理:

        字符串是以\0结束, 我们模拟实现strlen即是统计\0前有多少个字符即可。

//写法1
size_t MyStrlen1(const char* p)
{
    assert(p);
	int star = p;
	while (*p)
		p++;
	return (size_t)(p - star);
}
//写法2
size_t MyStrlen2(const char* p)
{
    assert(p);
	size_t n = 0;
	while (*p++)
		n++;
	return n;
}

方法一是通过指针相减获得中间元素个数方法,方法二是通过计数的方法实现。

为什么参数指针用const修饰呢?

        因为我们在计算计算字符串长度时,我们并不期望该函数修改我们原字符串,所以我们用const修饰起来。

为什么使用size_t作为返回值?

        因为字符串的长度不可能为负数,用size_t更加严谨。

二、 strcpy与strncpy函数

        strcpy和strncpy函数是字符串拷贝函数, 他们唯一的区别是strncpy多了一个用于控制拷贝字符串个数的形参,他们都必须引用头文件string.h,下图为MSDN查阅结果。

 函数返回值:

        函数返回值的类型是一个字符指针类型,我们希望该函数在结束时返回赋值后目标字符串的起始地址,这样做的目的是方便进行链式访问。

函数的参数:

参数一:char* strDestination,该参数为目标字符串的地址;

参数二:const char* strSource,该参数为复制字符串的地址;

参数三(strncpy):size_t count,该参数在strncpy中才有,该参数用于控制复制字符个数。

1、strcpy和strncpy的使用

#include <stdio.h>
#include <string.h>

int main()
{
	char* str1 = "hello world";
	char str2[20] = { 0 };
    //strcpy的使用
	strcpy(str2, str1);
	printf("%s\n", str2);
    //strncpy的使用
	char str3[20] = { 0 };
	strncpy(str3, str1, 5);
	printf("%s\n", str3);
	return 0;
}

使用上述函数是需要注意以下几点:

  1. 确保目标地址空间足够大,可以容纳源字符串;
  2. 源字符串中必须以\0结束;
  3. 目标空间必须可变;

2、strcpy和strncpy的模拟实现

//strcpy
char* MyStrcpy(char* dest, const char* src)
{
	assert(dest && src);
	char* start = dest;
	while (*dest++ = *src++)
	{
		;
	}
	return start;
}

注意:strcpy会将源字符串中的'\0'拷贝到目标字符串中

char* MyStrncpy(char* dest, const char* src, size_t count)
{
	assert(dest && src);
	char* start = dest;
	//拷贝字符串
	while (*src && count)
	{
		*dest++ = *src++;
		count--;
	}
	//count大于源字符串长度用\0补
	while (count--)
		*dest++ = '\0';
	return start;
}

三、strcmp和strncmp函数 

        strcmp和strncmp函数是字符串比较函数,该函数会依次比较相对应位置字符的ASCII值,使用前需要引用头文件string.h,以下为MSDN所查阅资料。

函数参数: 

         函数有两个参数,均为字符指针

 函数返回值:函数返回值为整型,具体还分以下三种情况

  • 当第一个字符串大于第二个字符串时,返回一个大于0的数;
  • 当第一个字符串等于第二个字符串时,返回0;
  • 当第一个字符串小于第二个字符串时,返回一个小于0的数;

 1、strcmp和strncmp的使用

#include <stdio.h>
#include <string.h>

int main()
{
	char* str1 = "abcde";
	char* str2 = "abccd";
	printf("%d\n", strcmp(str1, str2));
	printf("%d\n", strncmp(str1, str2, 3));
	return 0;
}

2、strcmp和strncmp的模拟实现

//strcmp
int MyStrcmp(const char* str1, const char* str2)
{
	assert(str1 && str2);
	//如果相同则比较下一个,直到找到不同的那对
	while (*str1 == *str2 && *str1)
	{
		str1++;
		str2++;
	}
	return *str1 - *str2;
}
//strncmp
int MyStrncmp(const char* str1, const char* str2, size_t count)
{
	assert(str1 && str2);
	//比较前count个字符
	while (*str1 == *str2 && count--)
	{
		str1++;
		str2++;
	}
	if (count == 0)
		return *(str1 - 1) - *(str2 - 1);
	else
		return *str1 - *str2;
}

四、strcat和strncat函数 

        strcat和strncat是字符串追加函数,该函数会将第二个字符串的追加到第一个字符串的后面,使用前需要引用头文件string.h,以下为MSDN所查阅资料;

函数参数:

        函数有两个参数均为字符指针。

        strncat还有一个追加字符串个数的参数count

函数返回值:

        函数的返回值为目标字符串的起始地址。

1、strcat和strncat的使用

#include <stdio.h>
#include <string.h>
int main()
{
	char str1[20] = "hello ";
	char* str2 = "world";
	printf("%s\n", strcat(str1, str2));
	printf("%s\n", strncat(str1, str2, 3));
	return 0;
}

注:strcat不能自己给自己追加,具体为什么不能,可看下面strcat的模拟实现;

2、strcat和strncat的模拟实现

char* MyStrcat(char* dest, const char* src)
{
	assert(dest && src);
	//1、找到目标空间\0的位置
	char* cur = dest;
	while (*cur)
	{
		cur++;
	}
	//2、拷贝源头中得数据到\0及之后的空间
	while (*cur++ = *src++)
	{
		;
	}
	return dest;
}

         字符串追加的本质是找到目标字符串的\0然后将其覆盖追加,而如果目标字符串和源字符串是同一个字符串时,如果将\0覆盖就会形成死循环。

char* MyStrncat(char* dest, const char* src, size_t count)
{
	assert(dest && src);
	//1、找到目标空间\0的位置
	char* cur = dest;
	while (*cur)
	{
		cur++;
	}
	//2、拷贝源头中指定的数据到\0及之后的空间
	while ((*cur++ = *src++) && count--)
	{
		;
	}
	*cur = '\0';
	return dest;
}

可以自己给自己追加,因为strncat会在追加后的字符串后加\0。

五、strstr函数 

        strstr函数是查询是否存在子字符串的函数,使用前需要引用头文件string.h,以下为MSDN中所查阅资料; 

 函数的返回值:

        如果能找到子字符串,则返回母串第一个出现子串的地址,如果不能找到子串,则返回NULL。

函数的参数: 

参数一:const char* string

        此参数即为母串

参数二:const char* strCharSet

        此参数即为子串

1、strstr函数的使用

#include <stdio.h>
#include <string.h>
#include <assert.h>

int main()
{
	char* str1 = "abbbcdef";
	char* str2 = "bbc";
	char* str3 = "abc";
	printf("%s\n", strstr(str1, str2));
	printf("%s\n", strstr(str1, str3));
	return 0;
}

2、strstr函数的模拟实现

char* MyStrstr(const char* str1, const char* str2)
{
	char* s1 = str1;
	char* s2 = str2;
	char* cur = str1;
	while (*cur)
	{
		s1 = cur;
		while (*s1 == *s2 && *s1 && *s2)
		{
			s1++;
			s2++;
		}
		if (*s2 == '\0')
		{
			return cur;
		}
		cur++;
		s2 = str2;
	}
	return NULL;
}

六、strtok函数

strtok函数是字符串切割函数,他能使某一字符串按照特定的方式切割开来,使用前需引用头文件string.h。以下为MSDN中所查阅资料;

函数的返回值:

        函数的返回值为每次函数切割出字符串的字符指针;如果该字符串已经没有可以切割的字符串了,则返回NULL。

函数的参数: 

参数一:

        该参数又被分为两种情况:

        (1)被切割函数的指针,首次调用strtok函数时,我们需要传入该字符串的起始地址,当他找到切割字符串标志的字符时,他会将该字符改为'\0',并记住这个位置。

        (2)NULL,第二次调用该函数传NULL即可,他会通过上一次记住的位置继续往后寻找且个字符串标志的字符 ,找到以后则改为'\0',并记住该位置。

参数二:

        该参数则为指向切割字符串的字符数组的指针;

1、strtok的使用 

#include <stdio.h>
#include <string.h>
int main()
{
	char str1[] = "123 456 7789@qq.com";
	char buf1[30];
	strcpy(buf1, str1);	
	char* seq = "@. ";
	printf("%s\n", strtok(buf1, seq));
	printf("%s\n", strtok(NULL, seq));
	printf("%s\n", strtok(NULL, seq));
	printf("%s\n", strtok(NULL, seq));
	printf("%s\n", strtok(NULL, seq));
	return 0;
}

当然实际情况下,我们不知道该字符串要切割几次 ,以下写法更巧妙;

#include <stdio.h>
#include <string.h>
int main()
{
	char str1[] = "123 456 7789@qq.com";
	char buf1[30];
	strcpy(buf1, str1);	
	char* seq = "@. ";
	char* str = NULL;
	for (str = strtok(buf1, seq); str != NULL; str = strtok(NULL, seq))
	{
		printf("%s\n", str);
	}
	return 0;
}

 注:

1、该函数会修改传入的字符串。

2、当传入非空指针作为参数一时,会终止切割原来字符串,而来切割当前字符串。

七、memcpy和memmove函数 

 memcpy和memmove函数都用于内存拷贝,他们唯一的区别是memmove可以用于重叠内存的拷贝,使用前需使用头文件string.h。以下为MSDN查阅结果;

 函数的返回值:

        函数的返回值为目标指针的值;

函数的参数: 

        参数一:

                目标的起始地址;

        参数二:

                 拷贝的起始地址;

        参数三:

                拷贝的字节数;

1、memcpy和memmove的使用

#include <stdio.h>
#include <string.h>
int main()
{
	int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
	int arr2[10] = { 0 };
	int arr3[10] = { 0 };
	int* p = memcpy(arr2, arr1, 20);
	memmove(arr3, arr1, 12);
	return 0;
}

2 、memcpy和memmove的模拟实现

//memcpy
void* MyMemcpy(void* dest, const void* src, size_t count)
{
	void* ret = dest;
	while (count--)
	{
		*(char*)dest = *(char*)src;
		dest = (char*)dest + 1;
		src = (char*)src + 1;
	}
	return ret;
}

memmove的模拟实现则需要另外考虑dest指针与src指针重叠的情况

void* MyMemmove(void* dest, const void* src, size_t count)
{
	void* ret = dest;
	if ((char*)dest > (char*)src)
	{
		while (count--)
		{
			*((char*)dest + count) = *((char*)src + count);
		}
	}
	else
	{
		while (count--)
		{
			*(char*)dest = *(char*)src;
			dest = (char*)dest + 1;
			src = (char*)src + 1;
		}
	}
	return ret;
}

        如果dest大于src就从后往前拷贝,如果dest小于src就从前往后拷贝,如果两者相等,则从前往后和从后往前都可 。

八、memcmp函数

        比较两个数据的大小,按字节进行依次比较,使用前需要引用头文件string.h,以下为MSDN中所查阅资料; 

 

 函数的参数:

        参数一、参数二:

                需要比较两块内存空间的起始地址;

        参数三:

                比较的字节数;

函数的返回值:

         该函数的返回值于strcmp相同,有如下三种:

 1、memcmp函数的使用

#include <stdio.h>
#include <string.h>
int main()
{
	int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
	int arr2[10] = { 0 };
	int arr3[10] = { 0 };
	memcpy(arr2, arr1, 20);
	memmove(arr1 + 3, arr1, 20);
	for (int i = 0; i < 10; i++)
	{
		printf("%d ", arr1[i]);
	}
	return 0;
}

 2、memcmp函数的模拟实现

#include <stdio.h>
#include <string.h>
int MyMemcmp(const void* p1, const void* p2, size_t count)
{
	while (*(char*)p1 == *(char*)p2 && count--)
	{
		p1 = (char*)p1 + 1;
		p2 = (char*)p2 + 1;
	}
	if (count == 0)
		return *((char*)p1 - 1) - *((char*)p2 - 1);
	else
		return *(char*)p1 - *(char*)p2;
}

        以上便是一些基本的字符串及内存函数,在模拟实现以上函数可以让你对上述函数有更深刻的认识,这些函数在未来的运用中也非常重要,以上为小编在学习期间所感悟,希望本文能给大家带来帮助。

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值