介绍一些字符串相关的库函数

以下介绍的所有函数头文件都为#include

一.strlen函数介绍与底层逻辑的模拟实现

strlen函数介绍

strlen函数是用来求字符串有多少个字符数量的函数,以"\0"作为结束标志,但是计数的时候不会把\0也算进去。比如说我有个字符串"ABCDEF",此字符串默认末尾有个\0但是利用strlen计算结果个数是6,不会把\0也算进去。

#include
#include
int main()
{
	const char* str = "ABCDEF";//字符串默认是常量是不可修改的,所以用const修饰
	size_t ret=strlen(str);
	printf("%zd", ret);
}

介绍一些字符串相关的库函数_第1张图片

同样上述字符串也可以写成字符串数组的格式,结果也是一样的

#include
#include
int main()
{
	const char arr[] = "ABCDEF";//字符串默认是常量是不可修改的,所以用const修饰
	size_t ret=strlen(arr);
	printf("%zd", ret);
}

介绍一些字符串相关的库函数_第2张图片

数组里面单独arr表示的是数组首元素地址,那么字符串str是不是也是首元素地址呢?

其实str确实是传了首元素A的地址给strlen函数,strlen函数本质上接收的就只是字符串首元素的地址,然后往后挨个找\0的位置,返回\0之前有多少个元素个数。

请注意strlen函数返回的是个数,个数一般来说不可能是负数,也不会有除了整数之外的类型,不会有什么一个半(1.5)个数。所以返回值ret要用size_t(无符号整数接收),而不是用习惯的int类型接收

strlen函数与sizeof关键字的区别

1.首先sizeof函数是关键字,不是库函数,可以直接使用,不用包含头文件

2.sizeof是求字节长度的关键字而strlen是字符串库函数,sizeof函数可以求所有类型的字节大小,因为所有类型都有字节大小啊,比如一个int类型占4个字节,char占一个字节大小,求字符串字节大小会把字符串隐藏的\0也会一块计算了。

而strlen函数一般是只能用在字符串中的,是用来计算有多少个字符的,虽然字符串末尾会默认隐藏字符\0,但是strlen函数不会把\0也一块计算了

以下是sizeof和strlen函数求字符个数的代码区别

#include
#include
int main()
{
	const char str[] = "ABCDEF";
	size_t ret = sizeof(str)/sizeof(str[0]);
	
	printf("%zd", ret);

}

 介绍一些字符串相关的库函数_第3张图片

需要注意的是,sizeof里面单独一个数组名,表示的是求整个数组大小的字节长度,例如上述代码sizeof(str)表示求整个str的地址,而不是首元素地址。整个字符串数组字节大小除以首元素单个字节大小sizeof(str[0]),就得到元素个数了

strlen求字符串大小

#include
#include
int main()
{
	const char str[] = "ABCDEF";
	size_t ret = strlen(str);//此时str表示首元素地址
	printf("%zd", ret);
}

介绍一些字符串相关的库函数_第4张图片

strlen没把\0算进去,所以是6

xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

请注意char * str和char str []两种字符串表示方法,strlen都能用,结果都是一样的,都是传首元素地址给strlen函数用。但是sizeof求字节长度却是不一样的结果

介绍一些字符串相关的库函数_第5张图片

为什么结果是8呢,改变一下字符串改为ABCDEFG看看

介绍一些字符串相关的库函数_第6张图片

结果依旧一样

这是因为你用指针变量保存字符串的地址,sizeof(str)意思是求字符串指针变量str的字节大小,而此时str内部保存的是字符串首元素地址,而32位平台下地址的大小默认全为4个字节,64位平台下默认是8个字节。

strlen函数逻辑的实现

#include
size_t my_strlen(const char* str)
{
	size_t count = 0;
	while (*str)//*str此时是首元素A,遇到字符串隐藏的\0就会停下来,字符\0ascall码值是0
		//所以循环遇到0为假会直接跳出
	{
		count++;
		str++;//str从A位置一直往后偏移,每移一次count值加一次,相当于计数
   }
	return count;
}
int main()
{
	const char* str = "ABCDEF";//指针变量str保存首元素地址
	size_t ret=my_strlen(str);//本质上传的是首元素地址
	printf("%zd", ret);
}

二.strcpy的介绍与底层逻辑的模拟实现

strcpy函数的介绍

strcpy函数功能其实就是把一个字符串复制到另一个字符串上,前提是目标空间足够大,以确保能放下整个复制过来的字符串。

其次,目标空间必须是可修改的,而被复制的字符串没有修改的必要,所以会被const修饰

被复制的字符串必须以\0结束,同时会把这个\0复制到目标空间当中去

strcpy函数的使用

代码表现形式为 char * strcpy(char * destination,const char * source);

destination为目标字符串,即目的地,要复制到这里

source为被复制的字符串

#include
#include
int main()
{
	char str[20] = { 0 };//先用0全部填充
	const char* stc = "ABCDEF";
	strcpy(str, stc);
	printf("%s", str);
}

介绍一些字符串相关的库函数_第7张图片

strcpy函数的底层逻辑实现

#include
char * my_strcpy(char* str, const char* stc)//用指针的形式来接收传过来的地址
{
	char* p = str;//用指针p来保存最初str指向的首元素位置
	while (*stc != 0)//到字符串结束标志\0停下来
	{
		*str = *stc;//字符串stc的元素挨个复制过去
		str++;
		stc++;
	}
	return p;//str最初的位置随着++已经改变,而p保存了最初的位置
}
int main()
{
	char str[20] = { 0 };
	const char* stc = "ABCDE";
	my_strcpy(str, stc);//实质都是传了首元素地址
	printf("%s", str);
}

介绍一些字符串相关的库函数_第8张图片

strncpy与strcpy的区别和联系

strncpy可以指定复制字符串的个数,比如上字符串ABCDEF,我现在只想复制AB过去,strcpy是整个ABCDEF都复制过去了,而strncpy可以只复制两个字符

表现形式为char * strncpy(char* destination,const char * source,size_t num);

size_t num为用复制多少个字符过去

源字符串的前 num 个字符复制到目标。如果在复制 num 个字符之前找到字符串的末尾(由 null 字符表示),则 destination 将用零填充,直到总共写入 num 个字符。

如果 source 的长度大于 num,则不会在目标末尾隐式追加 null 字符。因此,在这种情况下,destination 不应被视为以 null 结尾的 C 字符串(这样读取它会溢出)。

同时目的地不得重叠

#include
#include
int main()
{
	char str[20];
	const char* stc = "ABCD";
	strncpy(str, stc,2);
	printf("%s", str);
}

介绍一些字符串相关的库函数_第9张图片

strncpy函数的介绍与底层逻辑模拟实现

#include
char* my_strncpy(char* str, const char* stc,int num)
{
	char * p = str;
	while (num)
	{
		*str = *stc;
		str++;
		stc++;
		num--;
	}
	*str= '\0';
	return p;
}
int main()
{
	char str[20];
	const char* stc = "ABCD";
	my_strncpy(str, stc,2);
	printf("%s", str);
}

与strcpy的代码实现大致相同,只是用num去控制循环赋值的次数。同时strncpy复制过后的字符串不会有'\0',所以要在末尾加上字符串结束标志

末尾不设置‘\0’的代码及运行结果

#include
char* my_strncpy(char* str, const char* stc,int num)
{
	char * p = str;
	while (num)
	{
		*str = *stc;
		str++;
		stc++;
		num--;
	}
	return p;
}
int main()
{
	char str[20];
	const char* stc = "ABCD";
	my_strncpy(str, stc,2);
	printf("%s", str);
}

介绍一些字符串相关的库函数_第10张图片

三.strcat函数的介绍及模拟实现

strcat的介绍

strcat可以理解为字符串追加函数,比如一个字符串str"ABCD",这是常量字符串,已经不能修改了。此时我有另一字符串stc"EFG"要加在字符串str的后面,这就需要strcat函数来实现。

字符串末尾都会有个结束标志‘\0’,而strcat函数会把目的地字符串str末尾的‘\0'用源字符串stc的首元素D直接覆盖,并且会把stc的末尾’\0'复制过去,成为字符串str“ACBCDEFG"的新末尾结束标志

注意事项

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

目标空间也得有‘\0’,否则没法知道追加从哪里开始

目标空间必须有足够大,能容下源字符串的内容

目标空间必须可修改

strcat函数的使用

strcat表现形式为

char * strcat ( char * destination, const char * source );
#include 
#include
int main()
{
	char str[20] = "ABCD";
	const char* stc = "EFGH";
	strcat(str, stc);
	printf("%s", str);
}

介绍一些字符串相关的库函数_第11张图片

strcat函数的底层逻辑的模拟实现

要先找到目的地字符串函数的末尾结束标志“\0”才能依次往后循环赋值

#include 
#include
char* my_strcat(char* str, const char* stc)
{
	char* p = str;//保存字符串的首地址,一遍后面打印
	while (*str)//字符串末尾结束标志\0,它的ascall码值是0,循环条件为假跳出循环
		//这样就找到了\0的位置
	{
		str++;
	}
	while (*stc != '\0')//此循环与上面循环是平行关系,并不是嵌套,stc="\0"说明已经赋值完了
	{
		*str++ = *stc++;
	}
	return p;
}
int main()
{
	char str[20] = "ABCD";
	const char* stc = "EFGH";
	my_strcat(str, stc);
	printf("%s", str);
}

介绍一些字符串相关的库函数_第12张图片

strncat函数的介绍与底层逻辑实现

strncat也是和strcat多了一个限制数量,但是依旧要补上\0

strncat表现形式为
char * strncat ( char * destination, const char * source, size_t num );
#include 
#include
int main()
{
	char str[20] = "ABCD";
	const char* stc = "EFGTYU";
	strncat(str, stc, 3);
	printf("%s", str);
}
介绍一些字符串相关的库函数_第13张图片

可以看到只拼接了EFG,因为我只限制3个字符拼接

底层逻辑实现
#include 
#include
char* my_strncat(char* str, const char* stc, int num)
{
	char* p = str;
	while (*str)//找到*str为\0的位置
	{
		str++;
	}
	while (num)
	{
		num--;
		*str++= *stc++;		
	}
	return p;
}
int main()
{
	char str[20] = "ABCD";
	const char* stc = "EFGTYU";
	my_strncat(str, stc, 3);
	printf("%s", str);
}

介绍一些字符串相关的库函数_第14张图片

四.strcmp函数的使用及模拟实现

strcmp函数介绍

strcmp函数是比较字符串当中字符大小的

如果第一个字符串大于第二个字符串,则返回大于0的数字;

第一个字符串等于第二个字符串,则返回0;

第一个字符串小于第二个字符串,则返回小于0的数字

strcmp函数比较两个字符串大小是通过ascll码值来进行比较的,如果第一个字符与另一个字符串的首字符相等,则开始比较他们的下一个字符的大小,依次类推。

比如"ABCDEF"和"ABCEFG",前三个字符都相当,所以要从第四个字符来开始比较

strcmp表现形式及使用

int strcmp ( const char * str1, const char * str2 );
#include
#include 
int main()
{
	const char* str = "ABCFGH";
	const char* stc = "ABCTHY";
	int ret = strcmp(str, stc);//返回整数,所以用int类型接收
	if (ret > 0)
	{
		printf("大于\n");
	}
	else if (ret == 0)
	{
		printf("等于\n");
	}
	else
	{
		printf("小于\n");
	}
}

介绍一些字符串相关的库函数_第15张图片

strcmp函数的底层逻辑实现

#include
#include 
int my_strcmp(const char* str, const char* stc)
{
	while (*str == *stc&&*str!='\0'&&*stc!='\0')
	{
		
		str++;
		stc++;
	}
	if (*str > *stc)
	{
		return 1;
	}
	else if (*str < *stc)
	{
		return -1;
	}
	else
		return 0;
}
int main()
{
	const char* str = "ABCFGH";
	const char* stc = "ABCFGH";
	int ret = my_strcmp(str, stc);
	if (ret > 0)
	{
		printf("大于\n");
	}
	else if (ret == 0)
	{
		printf("等于\n");
	}
	else
	{
		printf("小于\n");
	}
}

介绍一些字符串相关的库函数_第16张图片

strncmp函数的使用

依旧是加上比较的次数,比较str与字符串stc的前num个字符,如果相等就继续往后比较,最多比较num个字母,如果提前发现不一样就提前结束,大的字符所在的字符串大于另一个。如果num个字符都相等,就是相等返回0;

int strncmp ( const char * str1, const char * str2, size_t num );
#include
#include
int main()
{
	const char* str = "ABCDE";
	const char* stc = "ACFGH";
	int ret=strncmp(str, stc, 3);
	if (ret == 0)
		printf("相等\n");
	if (ret < 0)
		printf("小于\n");
	if (ret > 0)
		printf("大于\n");
}

介绍一些字符串相关的库函数_第17张图片

strncmp的实现

#include
#include
int my_strncmp(const char* str, const char* stc,int num)
{
	num = num - 1;
		while (*str == *stc&&num)//大致实现都和strcmp差不多,只是多了num为限定条件
		{
			if (*stc == '\0')
			{
				return 0;
			}
			num--;
			stc++;
			str++;
		}
		if (*str < *stc)
			return -1;
		else if (*str > *stc)
			return 1;
		else
			return 0;
}
int main()
{
	const char* str = "ABCDE";
	const char* stc = "ABC";
	int ret=my_strncmp(str, stc, 3);
	if (ret == 0)
		printf("相等\n");
	if (ret < 0)
		printf("小于\n");
	if (ret > 0)
		printf("大于\n");
}

ABCDE与ABCD测试结果

介绍一些字符串相关的库函数_第18张图片

ABCDE与A的测试结果

介绍一些字符串相关的库函数_第19张图片

ABCD与ABC的测试结果

介绍一些字符串相关的库函数_第20张图片

你可能感兴趣的:(算法)