资讯专栏INFORMATION COLUMN

常用字符串和内存函数是如何工作的Do you really know?

ashe / 3091人阅读

摘要:参数指向的字符串必须要以结束。需要注意的是源字符串必须以结束。会将源字符串中的拷贝到目标空间。目标空间必须足够大,以确保能存放源字符串。举例最终字符串函数的模拟实现定义两个数组,首先遍历到,然后和函数相似开始拷贝即可。

前言:

C语言中对字符和字符串的处理很是频繁,但是C语言本身是没有字符串类型的,字符串通常放在 常量字符串 中或者 字符数组 中。
字符串常量适用于那些对它不做修改的字符串函数.


一、长度不受限制的字符串函数

1.1字符串求长——strlen函数

1.1.1strlen函数的介绍

size_t strlen ( const char * str );

这里我们可以看到strlen函数的返回值是size_t
?:1.字符串已经 ‘/0’ 作为结束标志,strlen函数返回的是在字符串中 ‘/0’ 前面出现的字符个数(不包
含 ‘/0’ )。
?:2.参数指向的字符串必须要以 ‘/0’ 结束。
?:3.注意函数的返回值为size_t,是无符号的( 易错 )
例子:?

#include #include int main(){	if (strlen("abc") - strlen("abcdef") > 0)	{		printf("hehe/n");	}	else	{		printf("haha/n");	}	return 0;}

这里输出的结果是hehe,因为返回的是无符号整数,这两哥字符串无论怎么减都是正数。


1.1.2strlen函数的模拟实现

这里直接计算个数即可,较为简单,不做赘述。

#include#includesize_t my_strlen(const char* str){	int count = 0;	assert(str != NULL);	while (*str)	{		count++;		str++;	}	return count;}int main(){	char arr[] = "pwh";	int len = my_strlen(arr);	printf("%d", len);	return 0;}

1.2字符串拷贝——strcpy函数

1.2.1strcpy函数的介绍

?:strcpy把含有’/0’结束符的字符串复制到另一个地址空间,返回值的类型为char*。

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

需要注意的是:?
1.源字符串必须以 ‘/0’ 结束。
2.会将源字符串中的 ‘/0’ 拷贝到目标空间。
3.目标空间必须足够大,以确保能存放源字符串。
4.目标空间必须可变。

为什么返回值为char*

返回strDest的原始值使函数能够支持链式表达式,增加了函数的“附加值”。同样功能的函数,如果能合理地提高的可用性,也就就更加理想。

int iLength=strlen(strcpy(strA,strB));char * strA=strcpy(new char[10],strB);

举例:?

char a[10],b[]={"PWH"};//定义字符数组a,bstrcpy(a,b);//将数组b中的PWH复制到数组a中

1.2.2strcpy函数的模拟实现

该代码与strlen函数类似,只需要注意代码的严谨,源地址的不可变性,拷贝至’/0’,数组空间够大即可。且一定要是字符数组!

#include#includechar* my_strcpy(char* dest, const char* src){	assert(dest != NULL);	assert(src != NULL);	char* ret = dest;	while (*dest++ = *src++)	{		;	}	return ret;}int main(){	char arr1[] = "abcdefghi";	char arr2[] = "bit";	my_strcpy(arr1, arr2);	printf("%s", arr1);	return 0;}

1.3字符串比较——strcmp函数

1.3.1strcmp函数的介绍

 int strcmp(const char *s1,const char *s2);

?:1.第一个字符串大于第二个字符串,则返回大于0的数字
?:2.第一个字符串等于第二个字符串,则返回0
?:3.第一个字符串小于第二个字符串,则返回小于0的数字
?:注意:
比较的是字符串的ASCII码值!
从第一个字符开始比较,第一个相等就从第二个字符比较,第一个大于返回正数,小于返回负数;然后从第二个开始比较。

#include#includeint main(){	char* p1 = "abcdef";//6	char* p2 = "aqwer";//5	//if("abcdef"=="sqwer")//比较的是地址,所以肯定不相等	int ret = strcmp(p1, p2);//strcmp比较的是每个字符的ASCII码值	//从第一个开始比较,第一个相等就从第二个字符比较,第一个大于返回1,小于返回-1;然后从第二个	printf("%d/n", ret);	return 0;}

1.3.2strcmp函数的模拟实现

strcmp函数的实现思路为定义两个数组,且都为不可变,使用while循环从第一个字符开始比较,如果相等则返回0,如果不相等则继续比较下个字符,字符地址+1,如果大于,返回正数,小于返回负数。

#include#includeint my_strcmp(const char* str1, const char* str2){	assert(str1 && str2);	//比较	while (*str1 == *str2)	{		if (*str1 == "/0")		{			return 0;//相等		}		str1++;		str2++;	}	if (*str1 > *str2)	{		return 1;//大于	}	else	{		return -1;//小于	}}int main(){	char* p1 = "abcdef";	char* p2 = "abqwe";	int ret = my_strcmp(p1, p2);	printf("ret=%d/n", ret);	return 0;}

1.4字符串连接——strcat函数

1.4.1strcat函数的介绍

char *strcat(char *dest, const char *src);

?:把src所指向的字符串(包括“/0”)复制到dest所指向的字符串后面(删除dest原来末尾的“/0”)。要保证dest足够长,以容纳被复制进来的*src。*src中原有的字符不变。返回指向dest的指针。
举例:?

#include #include int main (){   char src[50]="source";    char dest[50]="destination";   strcat(dest, src);   printf("最终字符串:%s", dest);   return 0;}

1.4.1strcat函数的模拟实现

?:定义两个数组,首先遍历到’/0’,然后和strcpy函数相似开始拷贝即可。

#include #include char* my_strcat(char *dest, const char *src){    assert(dest && src);    char *tmp = dest;    while (*tmp != "/0")    {    	tmp++;    }           while ((*tmp++ = *src++) != "/0");    return dest;}int main(){    char arr1[10] = "pwh";    char arr2[] = "hxs";    char* arr3 = my_strcat(arr1, arr2);    printf("str1=%s/n", arr1);    printf("str2=%s/n", arr2);    printf("str3=%s/n", arr3);    return 0;}

1.5字符串查找——strstr函数

1.5.1strstr函数的介绍

?:返回字符串中首次出现子串的地址
举例:

int main(){	char* p1 = "abcdefghi";	char* p2 = "defq";	char* ret = strstr(p1, p2);//查找第一次出现的位置	if (ret == NULL)	{		printf("子串不存在/n");	}	else	{		printf("%s/n", ret);	}	return 0;}

1.5.1strstr函数的模拟实现

思路:
尽量不要让p1,p2走,这样无法记住它的位置
当相等时,cur作为一个大前提,先在cur的位置使用s1 s2进行查找,如果没找到,cur++,从下一个字符查找。
这里定义了cur s1 s2,这样可以互不干扰,然后s1重新等于cur,从此位置++。

char* my_strstr(const char* p1, const char* p2){	assert(p1 != NULL);	assert(p2 != NULL);	//这样写可以互不干扰,适用于比较复杂的场景	char* s1 = p1;	char* s2 = p2;	char* cur =(char*) p1;	if (*p2 == "/0")	{		return p1;	}	while (*cur)	{		s1 = cur;		s2 = (char*)p2;		while (*s1 && *s2 && (*s1 == *s2))		{			s1++;			s2++;		}		if (*s2 == "/0")		{			return cur;		}		cur++;	}	return NULL;}int main(){	char* p1 = "abbbcdef";	char* p2 = "bbc";	char* ret = my_strstr(p1, p2);//查找第一次出现的位置	if (ret == NULL)	{		printf("子串不存在/n");	}	else	{		printf("%s/n", ret);	}	return 0;}

二、长度受限制的字符串函数

2.1strncpy函数

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

2.1.1与strcpy的区别

?:拷贝num个字符从源字符串到目标空间。
?:如果源字符串的长度小于num,则拷贝完源字符串之后,在目标的后边追加0,直到num个。
?:strncpy越界之后,拷贝完毕会把数组后面的内容全部变为0。

2.1.2strncpy函数的模拟实现

只需要在strcpy基础上加一个n的限制条件即可。

#include#includechar*my_strncpy(char*dest, const char*src, size_t n){	assert(dest != NULL);	assert(src != NULL);	char*ret = dest;	while (n)	{		*dest = *src;		src++;		dest++;		n--;	}	return ret;} int main(){	char arr1[20] = "hxs";	char arr2[20]= "pwh";	int n = 0;	printf("请输入需要拷贝的字符个数:/n");	scanf("%d", &n);	char*ret = my_strncpy(arr1,arr2,n);	printf("%s/n", ret);	return 0;}

2.2strncat函数

2.2.1与strncat的区别

?:strncat越界之后,追加完毕后依旧会自动添加’/0’,但和strncpy区别在于,不会把数组后面的元素变为0

2.2.1strncat函数的模拟实现

先遍历到目标字符串/0处,加一个n的限制条件即可。

#include #include char* my_strncat(const char* dest, const char* src,unsigned n){	assert(dest && src);	char* tmp = dest;	while (*tmp != "/0")	{		tmp++;	}	while (n)	{		*tmp = *src;		tmp++;		src++;		n--;	};	return dest;}int main(){	char arr1[10] = "pwh";	char arr2[10] = "hxs";	int n = 0;	printf("请输入你要拷贝的字符个数");	scanf("%d", &n);	my_strcat(arr1, arr2,n);	printf("arr1=%s/n", arr1);	return 0;}

2.3strncmp函数

2.3.1与strcmp的区别

?:比较的字符数可控。

2.3.2strncmp函数的模拟实现

没什么好说的,就是很简单!这里用for循环更加方便一些。

#include#includeint my_strncmp(const char* str1, const char* str2,unsigned n){	assert(str1 && str2);	//比较	unsigned i = 0;	for (i = 0; i < n - 1 && *str1 && *str2; i++)	{		if (*str1 != *str2)		{			break;		}		str1++;		str2++;	}	return (*str1 - *str2);}int main(){	char* p1 = "abcdef";	char* p2 = "abqwe";	int n = 0;	printf("请输入要检验的字符数");	scanf("%d", &n);	int ret = my_strcmp(p1, p2,n);	printf("ret=%d/n", ret);	return 0;}

三、内存函数

内存函数可以对任意类型的值操作,而字符串函数只能对字符串操作!

3.1memcpy函数

3.1.1memcpy函数的介绍

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

?:1.函数memcpy从source的位置开始向后复制num个字节的数据到destination的内存位置。
?:2.这个函数在遇到 ‘/0’ 的时候并不会停下来。
?:3.如果source和destination有任何的重叠,复制的结果都是未定义的。

3.1.2memcpy函数的模拟实现

将所传入的指针强制类型转换为char*类型,这样可以对于各种类型的数据进行操作,其余过程和strncpy函数比较相似。

struct S{	char name[20];	int age;};void my_memcpy(void* dest, const void* src, size_t num)//void类型不可解引用也不能算术运算{	assert(dest);	assert(src);	void* ret = dest;	while (num--)	{		*(char*)dest = *(char*)src;		++(char*)dest;		++(char*)src;	}	return dest;}int main(){	struct S arr3[] = { {"张三",20},{"李四",30} };	struct S arr4[3] = { 0 };	my_memcpy(arr4, arr3, sizeof(arr3));	//char *dest, const char*src	//memcpy(arr2, arr1, sizeof(arr1));	printf("%d", arr4->age);	return 0
            
                     
             
               

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/120810.html

相关文章

  • 【Java系列】从JVM角度深度解析Java核心类String不可变特性

    摘要:性能,大量运用在哈希的处理中,由于的不可变性,可以只计算一次哈希值,然后缓存在内部,后续直接取就好了。这是目前的一个底层字节码的实现,那么是不是没有使用或者的必要了呢。 凯伦说,公众号ID: KailunTalk,努力写出最优质的技术文章,欢迎关注探讨。 1. 前言 最近看到几个有趣的关于Java核心类String的问题。 String类是如何实现其不可变的特性的,设计成不可变的好处...

    afishhhhh 评论0 收藏0
  • 这5篇文章将使你成为一个Angular Change Detection专家。

    摘要:编写工作首先介绍了一个称为的内部组件表示,并解释了变更检测过程在视图上运行。本文主要由两部分组成第一部分探讨错误产生的原因,第二部分提出可能的修正。它对我意义重大,它能帮助其他人看到这篇文章。 在过去的8个月里,我大部分空闲时间都是reverse-engineering Angular。我最感兴趣的话题是变化检测。我认为它是框架中最重要的部分,因为它负责像DOM更新、输入绑定和查询列表...

    Coly 评论0 收藏0
  • 《JavaScript Web应用开发》作者Nicolas:恰巧,爱好变职业(图灵访谈)

    摘要:本文仅用于学习和交流目的,不得用于商业目的。今年,我们依然会组织。随着语言的发展,这种情况将不再适用。本系列主要讨论如何获得这些高度模块化的应用程序。这一系列内的后续图书会讨论测试及部署等内容。更多精彩,加入图灵访谈微信 本文仅用于学习和交流目的,不得用于商业目的。非商业转载请注明作译者、出处,并保留本文的原始链接:http://www.ituring.com.cn/art... 访谈...

    wawor4827 评论0 收藏0

发表评论

0条评论

ashe

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<