冰冰学习笔记:strcpy,strcat,strcmp

一、strcpy 库函数

1.1函数介绍:

strcpy函数执行的是字符串拷贝的功能,即把一个字符串拷贝放到另一个字符空间。

头文件为<string.h>

strcpy函数含有两个参数,参数类型为 char* 的指针,一个为源头字符串的地址,一个为目标空间的地址。

其返回类型为char* 类型,为什么是char* 呢?因为strcpy函数支持链式访问,所以需要返回目标空间的起始地址。

1.2注意事项:

(1)源字符串必须必须以‘\0’ 结束

此时,arr2中只放了hello这几个字符,并没有放'\0',程序执行,将会崩溃。

(2)会将源字符串中的'\0'拷贝到目标空间

strcpy函数在将源头字符串拷贝过去的时候会寻找字符串中的'\0'作为结束标志,并且将'\0'一同拷贝过去。因此在上个例子中,stecpy函数找不到arr2中的'\0'作为结束标志,将会一直向后寻找,最终程序崩溃。

 

通过调试我们可以很清楚的看到,strcpy确实将'\0'也拷贝过去了。

(3)目标空间必须足够大

strcpy函数将字符串拷贝到目标空间,其目标空间是必须能够容纳字符串的,strcpy并不会检查书否能够容下字符串内容,它只管拷贝过去。

如果空间容纳不下,将会导致程序崩溃。

arr1中只能存放4个字符,arr2中有'hello\0' 6个字符,明显存放不下。 

strcpy还是将其拷贝过去了,但是非法访问了内存空间,程序崩溃 

(4)目标空间必须可变

还是上面的例子,我们将arr1设计成如下形式,是否可以放下呢?

arr1指向常量字符串,字符串的长度大于arr2,能否将其拷贝过去呢?

答案是不能,因为常量字符串无法改变,arr1实际存放的为字符串的首元素地址。最终结果也是程序崩溃。

1.3模拟实现strcpy

在了解了上述strcpy函数的各种特点后,我们能否自己实现一个函数来完成strcpy的功能呢?

(1)首先函数接收两个地址,一个指向源头字符串,一个指向目标空间。返回为目标空间的起始地址。

并且我们是将源头字符串的内容复制过去,并不会改变源头字符串的内容。

设计如下:

char* my_strcpy(char*dest,const char*src)

dest为指向目标空间的指针,src为指向源头字符串的指针。

(2)接下来是内部实现,strcpy是不被允许接收空指针的,所以我们加上assert进行断言,避免dest和src接收空指针,如果为空,则报错。

然后是拷贝,src指针将遍历源头字符串,如果不是'\0'则将字符内容赋给dest,然后src和dest分别向后移动一步,src指向下一个字符,如果为'\0'则停止拷贝。

因此我们需要while循环来完成这个操作。

 因此我们将函数写成如下形式:

注意:使用assert千万不要忘记引用头文件<assetr.h> 

(3)while循环最后虽然停下来,但是str指向的'\0'并没有将其赋值给dest;

并且dest经过++操作符指向的不在是目标文件的开头,而是结尾,所以我们需要一个指针存放目标空间的其实地址,以便最终返回,实现链式访问。

最终程序实现为这样:

#include<assert.h>
char* my_strcpy(char* dest, const char* src)
{
	assert(dest && src != NULL);
	char* ret = dest;//存放目标空间的起始地址
	while (*src!='\0')
	{
		*dest = *src;
		dest++;
		src++;
	}
	*dest = *src;//将'\0'传递过去
	return ret;
}

目标实现了,但是代码并不完美。

我们在字符拷贝环节分成了两次进行拷贝,将'\0'进行了分开拷贝,能不能一次实现呢?

使用do while?答案是do while也是无法实现的,while结束循环依然是src指向'\0'但是却无法将其赋值给dest

但是下面的代码可以,而且极其简便,非常巧妙。

#include<assert.h>
char* my_strcpy(char* dest, const char* src)
{
	assert(dest && src );
	char* ret = dest;//存放目标空间的起始地址
	while (*dest++=*src++)
	{
		;
	}
	return ret;
}

首先,assert里面直接用dest&&src作为条件,dest和src无论哪个为空都都会停止,因为NULL 就是0,就是假。其次,while循环的判断条件为一个表达式,*src将值赋值给*dest,然后分别++指向下一个字符,当*src为'\0'时,首先将其赋值给*dest,然后进行判断'\0'为假,循环停止。

二、strcat 库函数

2.1函数介绍

strcat函数执行的是字符串添加的操作,strcat函数要求dest参数原先已经包含一个字符串(可以是空)。它找到这个字符串的末尾,然后把src字符串的内容将其拷贝过去。

和strcpy一样,dest指向目标空间,src指向源头字符串。返回类型也为char* 以便进行链式访问。

2.2注意事项

(1)原始字符串必须以'\0'结束

因为strcat函数要先找到目标空间字符串的结束标识,然后将其作为源头字符串的开始位置进行添加。

并且将源头字符串的'\0'拷贝过去 

(2)目标空间必须足够大,能够容纳添加后的整个字符串 

(3)目标空间必须可以修改,不能是指向常量字符串的指针

(4)源头字符串中必须包含'\0'

2.3模拟实现

接下里我们对其进行模拟实现。

strcpy函数的参数类型和返回类型都与strcpy一样,我们只需要在其基础上进行更改即可。

不同点在于我们需要提前找到目标字符串的结束标志,然后将其作为字符串拷贝的起始位置。

一个while循环便可以搞定

代码:

#include<assert.h>
char* my_strcat(char* dest, const char* src)
{
	assert(dest && src);
	char* ret = dest;//存放目标空间的起始地址
	while (*dest)
	{
		dest++;
	}//循环停止,dest指向'\0'
	while (*dest++ = *src++)
	{
		;
	}
	return ret;
}

如果自己给自己追加会怎样?

会发现程序崩溃了(有些编译器的strcat函数不会)

为啥呢?

因为在进行strcat链接的时候会先寻找目标字符串的'/0',然后将其覆盖掉,而源头指针也指向目标字符串的起始位置,这将导致找不到源头你字符串的'/0'使其无法停止,最终会无限的进行复制,然后程序崩溃。

 三、strcmp 库函数

3.1函数介绍

strcmp函数是用来对字符串进行比较的函数,该函数接收两个字符串的起始指针,然后对两个字符串进行逐字节进行比较,直到不同或者都遇到 '\0' 才会停下来。比较的是字符的ASCII码值,而不是长度。

返回类型为int

如果string1指向的字符ASCII吗值小于string2指向的字符,则返回小于0的数字

如果string1指向的字符ASCII吗值大于string2指向的字符,则返回大于0的数字

如果两个字符串都指向了'\0'并且之前的字符全都相同,则返回0

注意:VS编译器下返回的是-1,1,0; 

既然返回的是大于0,小于0,等于0的数字,我们就不能简单的用是否等于1或者-1来判断。

3.2模拟实现

首先函数需要接收两个起始地址,由于我们只是对其进行比较,并不会对其进行更改,为了保证安全,所以使用const来修饰。为了避免传过来空指针,我们依然用断言进行警报。

int my_strcmp(const char* s1,const char* s2)

然后我们需要对字符串进行比较,如果s1 和 s2指向的字符相同,则两个指针都向后移动一步,用来判断下一对字符。如果字符不相同则跳出循环。来到外面。

来到外面后只需要将两个指针指向的内容进行相减就可以得到字符串相比较的大小,如果s1指向的字符小于s2指向的字符则相减得到负数,返回负数,反之则返回正值。

但是什么时候返回0呢?

当有一个字符串来到末尾,指向的是'\0'的时候,如果还可以进行循环,则说明另一个字符也指向了字符串末尾,此时我们需要判断是否为'\0'如果是,则返回0;

如果一个字符串指向了'\0'但是循环并没有进去,则说明两个字符串中此刻指向的内容是不同的,那么此刻位于循环外面的指针相减的返回结果依然可以工作。

所以代码为:

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;
}

就上面的例子,运行结果:

结语:

上面所举出的例子都是字符不受限制的字符串函数(包括前面模拟实现的strlen),也就是说他们只是通过寻找字符串参数结尾的'\0'来确定字符串长度并对其进行操作。这些函数一般都指定一块内存用于存放结果字符串。因此我们必须要保证结果字符串不会溢出这块内存。

那如果我想指定复制,连接,比较的字符串数目呢,那就需要长度受限的字符串函数来进行操作,将在下一篇文章中进行讲解

  • 13
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 9
    评论
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

bingbing~bang

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

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

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

打赏作者

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

抵扣说明:

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

余额充值