C语言字符函数和字符库函数(一)

一.strlen函数

1.1strlen函数作用

strlen分开读就是string length,也就是说这是一个求字符串长度的函数

1.2strlen函数格式

 size_t strlen( const char *string );

参数:const char *string

  • char *string是说明这是一个字符型的指针,里面只要写你需要求的那个字符串的首字符地址即可
  • const:如果用const关键字定义char *string的话,说明char *string不可被修改。因为我们只是通过这个地址来求他的长度,所以我们不希望他会被修改。这样写可以增强程序的健壮性。

返回值:size_t

strlen的返回值是size_t类型的,size_t相当于unsigned int类型是无符号整型。原因也很简单,我们要求的是一个长度,长度不可能是一个负数,所以在这里我们只用无符号整型就可以了。

头文件:<string.h>.一般str开头的函数的头文件都是<string.h>

1.3strlen函数的用法

#include <stdio.h>
#include <string.h>
int main()
{
	char str[] = "hello word";
	char* str1 = "hello word";
	printf("%zd\n", strlen(str));//定义一个字符数组,数组名就是这个字符串
	                             //首元素的地址
	printf("%zd\n", strlen(str1));//str1是字符型指针,指向"hello word"这个
	//常量字符串,而常量字符串的地址就是这个字符串首元素的地址
	printf("%zd\n", strlen("hello word"));
	//因为strlen函数返回的类型是size_t,printf在打印时需要使用zd%,不是d%
	return 0;
}

看到这里可以发现strlen函数的使用特别简单只用在括号里写入需要求的字符串的地址,再拿个无符号整型的变量接受即可。

1.4strlen函数的模拟实现

1.4.1strlen函数运行原理

在模拟函数之前我们首先要搞懂这个函数运行的原理:

我们知道字符串通常以\0标志结尾,所以strlen函数就是从刚开始输入的地址开始一直到\0,返回其中出现的字符个数。

我们通过代码来验证一下:

int main()
{
	char str1[] = { 'h','e','l','l','o' };
	char str2[] = "hello";
	printf("%zd\n", strlen(str1));
	printf("%zd\n", strlen(str2));
}

这里我们可以看到两个数组的内容都是hello,但是打印出来的结果会都是5吗?
在这里插入图片描述
结果显然不是,但是原因是什么呢?

char str1[] = { ‘h’,‘e’,‘l’,‘l’,‘o’ };里面不会自动给你加上\0所以strlen函数在运行的时候会一直计算到后面出现\0为止,但我们不知道后面何时才会出现\0,所以出现的结果其实是一个随机值。
char str2[] = “hello”;这个数组在写完后为自动为后面补上\0。

char str1[] = { 'h','e','l','l','o' ,'\0'};//当我们补上\0之后看结果

在这里插入图片描述

1.4.2strlen模拟实现

我们既然清楚了原理,模拟起来就简单了。我们直接看代码:

size_t my_strlen(const char* string)//既然是模拟实验返回值,参数也要和原来一样
{
    assert(string);//我们传进来的是一个指针类型,所以我们通过assert进行断言
    //防止这个指针是个空指针,如果是空指针就会报错
    //因为我们下面要解引用指针,如果这个指针是空,解引用会导致
    //系统崩溃。
	int count = 0;//定义count来计数
	while (*string)//因为strlen是计数\0之前的值,\0的本质其实是0,我们用while
	//循环,只要string指向\0时就不计数即可
	{
		string++;//string起始位置指向的这个字符串的首字符地址,如果这个首字符地
		//址不为\0,指针++,指向下一个元素的位置.
		count++;//指针每次移动,count自加1.
	}
	return count;//最终返回的值就是这个字符串元素的个数
}

assert需要用<assert.h>头文件

我们来看看我们模拟的函数的结果:
在这里插入图片描述

二.strcpy函数

2.1strcpy函数作用

strcpy可以分成string copy,意思就是字符串的拷贝,应该很好理解吧。

2.2strcpy函数的格式

char *strcpy( char *strDestination, const char *strSource );

参数:strDestination是字符串的目的地,就是需要拷贝的地方的地址。strSource是字符串的源头,就是拷贝的内容。我举个例子。

strcpy(str1,str2);//我们先默认str1,str2是两个字符串的地址,这样写就是把,
//str2里的字符串拷贝到str1指向的字符串里

返回值:返回的是char *strcpy,也是一个地址,是strDestination的地址。

这里要注意几个细节:

  • char *strSource就是说明这里要写一个char
    *类型的指针,所以这里你可以直接写一个字符串(因为字符串和数组名很像,都是首元素地址),也可以写一个字符数组(数组名是这个数组首元素地址),或者写一个字符串地址,这个地址指向一个字符串。
  • 而char* strDestination条件就比较严格了,首先他和strcpy函数的第二个参数相比,会发现他没有加const。这也好理解,因为第二个参数只是提供需要拷贝的内容,我们不需要改变它,所以在前面加上const,以防后面不小心改了。其次,第一个参数可不能直接写个字符串上去,像这样strcpy(“word”,“hello”);这样是错的,因为字符串是个常量,是不允许修改的。向上面这样写不就是相当于把hello拷贝到word里面,然后把word变成hello吗?这就是把常量当成变量用了。同理你写成这样也不行
int main()
{
	char* str = "word11";
	printf("%s", strcpy(str, "hello"));
	return 0;
}

把字符串的地址写成函数的第一个参数和把一个字符串当成第一个参数没区别,都是不允许的。
所以strcpy的第一个参数,你最好写成数组的形式

int main()
{
	char str[20] = { 0 };
	printf("%s", strcpy(str, "hello"));
	return 0;
}

这里就相当于把一个字符串“hello”拷贝到str这个数组里去,然后返回的是这个数组的地址

头文件:<string.h>

2.3strcpy函数的用法

这个函数的用法我上面已经讲的差不多了。我用代码的形式再来总结一下:

int main()
{
	char str[20] = { 0 };//函数的第一个参数是以数组形式

	char* str1 = "hello";
	char str2[] = "hello";
	printf("%s\n", strcpy(str, "hello"));//函数的第二个参数可以是常量字符串
	printf("%s\n", strcpy(str, str1));//函数的第二个参数可以是常量字符串的地址
	printf("%s\n", strcpy(str, str2));//函数的第二个参数可以是一个字符数组的
	                                 //首元素地址
	return 0;
}

我们来看看结果:
在这里插入图片描述
strcpy的返回值就是函数第一个参数的地址。

2.4strcpy函数的模拟实现

我们直接上代码:

char* my_strcpy(char* strDestination, const char* strSource)
//为了是我们的模拟函数能很好的还原,除了函数名一样,其他的不变
{
	assert(strDestination && strSource);//老样子,因为传进来的参数是指针
	                                   //所以先断言,防止是空指针
	char* ptr = strDestination;//这里是因为我们返回的是第一个参数(也就是地址)
	//所以我们先将这个地址保存起来,这样这个随便改也不会丢掉原来的地址了
	while (*strSource)
	{
		*ptr = *strSource;
		ptr++;
		strSource++;
	}
	//这个函数的原理就是将strSource指向的元素赋值给strDestination所指向的元素
	//这就相当于将第二个参数拷贝到第一个参数里了。然后将两个地址自加1,这样就把
	//第二个,第三个...元素全部拷贝过去,知道strSource解引用后知道,这个字符串的
	//末尾也就是\0。这是循环结束,返回起始位置。
	return strDestination;
}

当然我们还可以把他简化一下:

char* my_strcpy(char* strDestination, const char* strSource)
{
	assert(strDestination && strSource);
	char* ptr = strDestination;
	while (*ptr++ = *strSource++)
	//每次将strSource指向的元素赋值给ptr指向的元素。赋值完在自加1,分别指向后一个
	//位置,直到strSource指向的元素为\0,也就是0,这样赋值过去ptr指向的值也为0,
	//这样就变成了while(0),这样条件不满足就跳出来。while循环里什么都不写就行。
	{
		;
	}
	return strDestination;
}

三.strcat函数

3.1strcat函数的作用

strcat作用是在一个字符串后面追加另一个字符串
首先,本人我英语不好,我只知道cat是猫的意思,不知道这个cat和追加有什么联系,应该是一个和追加有关的单词里面有cat这三个字母吧。但是我们我们只要知道用法即可。

3.2strcat函数的格式

char *strcat( char *strDestination, const char *strSource );

仔细看,这个和strcpy函数的写法几乎一样,就是函数名不同。
参数:用白话文讲就是将第二个字符串加到第一个字符串上去
来看代码理解一下:

int main()
{
	char str[20] = "hello ";
	printf("%s\n",strcat(str, "word"));
	return 0;
}

再来看效果:
在这里插入图片描述
这就把第二个字符串“word”加到第一个字符串“hello ”后面了。
两个参数可以是什么,不可以是什么,我在strcpy函数那里讲过了,他们的性质其实也是一样的。
但是这个函数还要两个小细节:就是第一个数组它的空间得要大,大到能装下追加后字符串的大小,否则就会发生越界访问。另一个就是源字符串,也就是第二个参数指向的字符串,他的末尾要有\0,否则再追加完打印的时候找不到\0时会打印乱码的。
返回值:返回的是第一个参数字符串的首地址。
头文件:<string.h>

3.3strcat函数的用法

strcat函数的用法也很简单,strcat(“被追加的字符串”,“追加的内容”);但是我们有一个问题,它能自己追加自己吗?这个问题我们先把strcat函数模拟实现后在考虑。

3.4strcat函数模拟实现

我们这个函数的基本原理就是先找到目标字符串的末尾\0,然后从这里开始,将源字符串一个个拷贝(赋值)过去,知道找到源字符串的末尾\0,然后结束。

char* my_strcat(char* StrDestination, const char* StrSource)
{
	assert(StrDestination && StrSource);//先断言,防止地址是空指针
	char* ptr = StrDestination;//因为返回的是目标字符串的地址,所以先将这个地址
	//保存起来
	while (*StrDestination)
	{
		StrDestination++;
	}
	//这里可不可以写成这样?
	//while (*StrDestination++)
	//{
	//	;
	//}
	//不可以,因为假设我们找到了这个地址StrDestination,其解引用是\0,此时应该
	//停止循环,当然这样写确实停止了,但是StrDestination会在while里判断完后自加1
	//跳到\0后的位置,之后追加是从这里追加结果可能就变成:hello\0word\0,这样导致
	//的结果就是在打印时碰到第一个\0就停下来,导致没把追加后的字符串打印出来
	while (*StrDestination++ = *StrSource++)
	{
		;
	}
	//这里为什么可以这样写呢?因为知道\0之后也不用管后面是什么了,因为我们返回的是ptr,已经和他俩
	//没关系了
	return ptr;
}

现在我们再来解决一下刚才提到的问题:它能自己追加自己吗?
我们通过模拟实现的代码可以看到,源字符串是从目标字符串的\0位置开始的。
在这里插入图片描述
我们可以看到源字符串是在箭头指向的那个地方开始追加,追加一个字符之后目标字符串的\0被替换成了a,这时我们可以看看刚才写的代码中while的结束条件:
源字符串变为\0时停止,因为是自己给自己追加,源字符串也就是目标字符串,目标字符串一直在增加导致源字符串也在不停的增加,本该是\0的位置上变成了a,这样的话始终找不到一个\0让程序停下来。最终系统崩溃

四.strcmp函数

4.1strcmp函数的作用

strcmp可以理解为string+compare,顾名思义,就是比较两个字符串。

4.2strcmp函数的格式

int strcmp( const char *string1, const char *string2 );

参数:char *string1,char *string2是需要比较的两个字符串的地址。
返回值

  • 第一个字符串大于第二个字符串:返回一个>0的值
  • 第一个字符串小于第二个字符串:返回一个<0的值
  • 第一个字符串等于于第二个字符串:返回0
    头文件:<string.h>

4.3strcmp函数的用法

我们在比较两个数的时候可能会看a1-a2是否大于0,但是在比较字符串时,这样判断就行不通了。
首先,我们要知道strcmp在比较时是从第一个元素开始比较每个字符的ASCII值。记住,是从第一个元素一个一个向后比较。小写字母的ASCII值比大写字母的大

int main()
{
	printf("%d\n", strcmp("abcde", "aBcde"));
	printf("%d\n", strcmp("aBcde", "abcde"));
	printf("%d\n", strcmp("abcde", "abcde"));
	printf("%d\n", strcmp("aBcde", "abcdE"));

	return 0;
}

我们来看结果:
在这里插入图片描述
这样看就一目了然了。

4.4strcmp函数的模拟实现

int my_strcmp(const char* string1, const char* string2)
{
	assert(string1 && string2);//断言,防止为空指针
	while ((*string1 == *string2) || ((*string1 == '\0') && (*string2 == '\0')))
	//有两种结果:
	//第一种是两个字符串始终相等,也就是一直在循环
	//我们为了让循环停止就加了一个条件((*string1 == '\0') && (*string2 == '\0')))
	//因为如果这两个字符串相等的话,也会同时达到末尾,此时就可以跳出循环了。
	//第二种是两个字符串不相等,从一开始就判断,比如abcd,aBcd.可能刚开始会一样
	//但总会有不一样的时候,这是就跳出循环,比较那不一样的元素。
	{
		string1++;
		string2++;
	}
	if (*string1 < *string2)
		return -1;
	else if (*string1 > *string2)
		return 1;
	else//当两个字符串相等,回跳到这里来
		return 0;
}

当然这和原来函数有些差别,原本的函数是返回>0,<0,0,但是我们返回的是1,-1,0。所以我们可以稍加改进:

int my_strcmp(const char* string1, const char* string2)
{
	assert(string1 && string2);
	while ((*string1 == *string2) || ((*string1 == '\0') && (*string2 == '\0')))
	{
		string1++;
		string2++;
	}
	return *string1 - *string2;
}

这样就可以了直接返回*string1 - string2,如果string1>*string2就返回一个大于0的值,否则就相反。

五.strncpy

5.1strncpy格式

char *strncpy( char *strDest, const char *strSource, size_t count );

这和函数比strcpy相比,就多了一个参数count,本来strcpy是将一个字符串全部拷贝到另一个字符串中。strncpy就相当于加了一个限制条件,就是从源字符串拷贝count个字符到目标字符串中

5.2strncpy用法

int main()
{
	char str[20] = { 0 };
	printf("%s\n", strncpy(str, "hello", 3));
	return 0;
}

我们来看结果:
在这里插入图片描述
我们发现只拷贝了三个字符串过去。

5.3strncpy函数的模拟实现

模拟起来也不麻烦,就是把原来的while循环改成for循环

char* my_strncpy(char* strDestination, const char* strSource, size_t count)
{
	assert(strDestination && strSource);
	char* ptr = strDestination;
	int i = 0;
	for (i = 0; i < count; i++)
	{
		*ptr++ = *strSource++;
	}
	return strDestination;
}

六.strncat

6.1strncat格式

char *strncat( char *strDest, const char *strSource, size_t count );

和strncat类似,这里加了限制条件,追加count个字符。

6.2strncat使用

int main()
{
	char str[20] = "hello ";
	printf("%s\n", strncat(str, "wordxxx", 2));
	return 0;
}

再来看结果:
在这里插入图片描述
这里之追加了两个字符过去。

6.3strncat的模拟实现

比较简单,直接上代码:

char* my_strncat(char* StrDestination, const char* StrSource, size_t count)
{
	assert(StrDestination && StrSource);
	char* ptr = StrDestination;
	while (*StrDestination)
	{
		StrDestination++;
	}
	int i = 0;
	for (i = 0; i < count; i++)//从while循环变成for循环
	{
		*StrDestination++ = *StrSource++;
	}
	return ptr;
}

七.strncmp

7.1strncmp格式

int strncmp( const char *string1, const char *string2, size_t count );

7.2strncmp使用

int main()
{
	printf("%d\n", strncmp("abCd", "abcd", 2));
	printf("%d\n", strncmp("abCd", "abcd", 3));

	return 0;
}

我们来看结果:
在这里插入图片描述
这里我们发现当值比较前两个元素的时候判断其是相等的,但是,比较前三个元素的时候是小于。

7.3strncmp模拟实现

strncmp和之前两个有些不一样:

int my_strncmp(const char* string1, const char* string2, size_t count)
{
	assert(string1 && string2);
	int i = 0;
	while ((*string1 == *string2) || ((*string1 == '\0') && (*string2 == '\0')))
	{
		string1++;
		string2++;
		i++;
		if (i == (count - 1))
			break;
	}
	return *string1 - *string2;
}

strcmp函数是一直循环知道两个元素不相等,或者两个字符串都结束时在跳出来。现在我们加个限制条件就是,循环count次就可以了,如果count等于3,就循环判断3次,一次也不多判断。

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值