字符串函数的使用:

一些前言:在C语言中没有单独的字符串类型,所以在存放字符串时一般用字符数组和常量字符串。而常量字符串一般用于不修改的字符串函数中。

char* arr1="abcde";常量字符串

char arr1[]="abcde";可变的字符串

函数介绍:

1.strlen函数

这个函数是用来计算字符串长度的函数,它会从字符串第一个字符一直找到字符串的最后一个字符,直至找到末尾结束标志“\0”。然后计算字符的个数并且返回。它的参数是指针。我们有三种方法去实现这个函数,分别为:

1.计数器

2.递归

3.指针减去指针

注意点:strlen函数的返回值是size_t,一个无符号整型,所以它是不会返回负数的。

模拟实现:

int my_strlen1(const char* a)//计数器
{
	//加上const防止被修改
	int num = 0;
	assert(a != NULL);//判断非空指针
	while (*a!='\0')
	{
		a++;
		num++;
	}
	return num;
}
int my_strlen2(char* a)//递归
{
	if (*a != '\0')
	{
		return 1 + my_strlen2(a + 1);
	}
	else
		return 0;
}
int my_strlen3(char* a)//指针减去指针
{
	char* maxpointer = a;
	char* minpointer = a;
	while (*a != '\0')
	{
		a++;
		maxpointer++;
	}
	return maxpointer - minpointer;
}
int main()
{
	char arr[] = "abcdpppef";
	int count1=my_strlen1(arr);
	int count2=my_strlen2(arr);
	int count3=my_strlen3(arr);
	printf("%d\n", count1);
	printf("%d\n", count2);
	printf("%d\n", count3);
	return 0;
}

2.strcpy函数

strcpy函数作用是将一个字符串复制粘贴到另外一个字符串上面

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

注意点:1.目标空间必须可变2.目标空间必须可以存储下3.必须要有"\0"如:char arr[]={'a','b','c'};里面就不包含"\0"4.会将原字符串的"\0"也拷贝进去 模拟实现:

char* his_strcpy(char* arr1,const char* arr2)
{
	assert(arr1 != NULL);
	assert(arr2 != NULL);
	char* ret = arr1;
	//复制包括"\0"的所有字符
	while (*arr1++ = *arr2++)
	{
		;
	}
	//返回目标起始指针,因为arr1已经被改变
	return ret;
}
//void my_strcpy(char* arr1, char* arr2)
//{
//	int count = 0;
//	char* arr_init = arr1;
//	assert(arr1 != NULL);
//	assert(arr2 != NULL);
//	while(*arr2)
//	{
//		*arr1 = *arr2;
//		arr1++;
//		arr2++;
//		count++;
//	}
//	*(arr_init + count) = '\0';
//}
int main()
{
	char arr1[] = "abcdefg";
	char arr2[] = "cppplpp";
	//my_strcpy(arr1,arr2);
	char* arr3 = his_strcpy(arr1, arr2);
	printf("%s", arr3);
	return 0;
}

1.strcat函数

char* strcat(char* destination,const char* source)

它的作用是增长字符串,将源头字符串拷贝到目标字符串的后面。 追加的方法是将第二个字符串包括"\0"拷贝到第一个字符串后面,以第一个字符串的结束标志"\0"作为第二个字符串的拷贝起始位置,可由下列代码测试:

int main()
{
	char arr1[50] = "abcdef\0xxxxxxxxxx";
	char arr2[] = "ghijk";
	strcat(arr1, arr2);
	return 0;
}

注意点:

1.目标空间必须足够大去容纳源字符串,如下面代码,要在第一个字符串标明空间大小

int main()
{
	//char arr1[] = "abcdef";//错误写法
	char arr1[50]="abcdef"//正确写法
	char arr2[] = "ghijk";
	strcat(arr1, arr2);
	return 0;
}

2.源字符串必须要"\0"结束

3.目标字符串必须是一个可改变的字符串,即不能是常量字符串

4.自己给自己拷贝,即strcat(str,str)情况下程序会崩溃。因为将自己第一个字符覆盖了自己末尾的"\0"后源字符串就没有"\0"可以拷贝。

模拟实现strcat

char* my_strcat(char* str1,const char* str2,int length)
{
	assert(str1);
	assert(str2);
	char* str = str1 + length;//第一个字符串的'\0'位置
	while (*str2!='\0')
	{
		*str = *str2;
		str++;
		str2++;
	}
	return str1;//返回目标字符串的首地址
}
char* his_strcat(char* dest, const char* src)
{
	assert(dest);
	assert(src);
	char* ret = dest;
	while (*dest != '\0')
	{
		dest++;
	}
	while (*dest++ = *src++)
	{
		;
	}
	//while(*dest++=*src++);//另一种写法
	return ret;
}
int main()
{
	char arr1[50] = "abcdef";
	char arr2[] = "ghijklmn";
	int length = strlen(arr1);
	char* getstr = 0;
	//getstr = my_strcat(arr1, arr2,length);
	getstr = his_strcat(arr1, arr2);
	printf("%s\n",getstr);
	return 0;
}

2.strcmp函数

int strcmp(const char* str1,const char* str2)

这个函数是用来比较字符串大小的函数,不过比较的是字符串首字符的ACSII码的大小,若首字符相同则继续向下比较。VS编译器下如果字符1大于字符2,则返回1,小于则是-1;而在Linux的编译器下会返回两个字符串的ASCII码值的差值。

模拟实现:

int my_strcmp(const char* str1, const char* str2)
{
	assert(str1 && str2);
	while (*str1 == *str2)//当两个字符不相等时停止循环
	{
		if (*str2 == '\0')
		{
			return 0;//当两个字符串全部字符相等同时结束
		}
		str1++;
		str2++;
	}
	if (*str1 > *str2)
		return 1;//大于返回1
	else
		return -1;//小于返回-1

}
int main()
{
	char str1[] = "abcdef";
	char str2[] = "abcdef";
	int ret = my_strcmp(str1, str2);
	printf("%d\n", ret);
	return 0;
}

3.strncpy函数

char* strncpy(char* Dest,const char* Source,size_t count)

strncpy函数比strcpy函数参数多了需要拷贝的字符长度,功能也是用于复制字符串。当源字符串的字符个数比需要拷贝的字符长度小时,多出的部分用'\0'补充。strcpy函数会一直拷贝源字符串直至拷贝完'\0',而strncpy函数可以选择拷贝的字符的个数。

4.strncat函数

char* strncat(char* Dest,const char* Source,size_t num)

strncat函数的参数比strcat多一个需要追加的字符个数。注意,它无论是否追加完Source的字符串里的所有字符,它都会在末尾加上一个'\0'(即使目标空间后面还有字符),这与strncpy追加count个'\0'的特点不同。

5.strncmp函数

int strncmp(const char* str1,const char* str2,size_t num)

这个函数用于比较两个字符串的大小,比较的是字符的ASCII码值的大小,比起strcmp函数多了一个参数num,这个参数可以用于设置参与比较的字符的个数。

6.strstr函数

char* strstr(const char* str1, const char* str2)

strstr函数用于在字符串str1中寻找str2字符串,即str2字符串是str1字符串的子串。当str2是str1的子串,则返回str1中str2对应第一个字符的地址(即若str1="abcdef",str2="cd",则返回abcdef中的c的地址);若不是,则返回空指针。注意,当str1中包含两个str2时,返回第一个子串的地址(即str1="abcdefabcedf",str2="cd",则返回第一个c的地址)。

笔记:NUL和Null都表示'\0'。

我自己尝试实现的strstr函数:

char* my_strstr(char str1[],char str2[])
{
	assert(str1&&str2);
	//实现strstr函数
	int length = strlen(str2);
	if (*str2 == '\0')//判断是否str1函数为空
	{
		return str1;
	}
	while (*str1!='\0')
	{
		if (*str1 == *str2)
		{
			char* tmp1 = str1;//创造临时变量,保持str1进入第二层循环出来不变
			char* tmp2 = str2;//创造临时变量,保持str2进入第二层循环出来不变
			while ((*str1&&*str2)&& (*str1 == *str2))
            //while(*str1 && *str2 &&!(*str1-str2))
			{
				str1++;
				str2++;
				if (*str2 == '\0')//可以写成if(!*str2)
					return tmp1;
			}
			str1 = tmp1;
			str2 = tmp2;
		}
		str1++;
	}
	return NULL;
	
}
int main()
{
	char str1[] = "abffc";
	char str2[] = "ffc";
	//字符串也可以定义为const char* str1 =..后面的函数返回要强制类型转换为(char*)
	char* ret = NULL;
	ret = my_strstr(str1,str2);
	printf("%s\n", ret);
	return 0;
}

7.strtok函数

char* strtok(char* str1,const char* sep)

这个函数用于切割有符号隔开的字符串,例如给定一个字符串为"abc.def@ghi"。则可以调用这个函数将这个字符串分割为abc,def,ghi三个部分。但需要分别调用三次才能完全切割。

其中的参数部分,str1为需要切割的含符号的字符串,sep为需要切割的字符串中含有的所有字符组成的一个集合。返回值为当前切割环境下的字符串部分的首地址。例如切割字符串"ab.ee@peo"时,则需要创造一个包含这个字符串里所有分割符号的字符集合,即创造char sep[]=".@"。关于str1这个参数,第一次切割需要传递被切割的字符串地址,第二次后则改为传递NULL。

工作原理:要想切割字符串需要反复调用这个函数,这个函数一次只会切割一部分,一次切割过程是从当前地址截取到下一次遇到标点符号符号中间的字符串部分。以字符串char str1[100]="ab.ed@rr",char sep[]=".@"为例,第一次调用strtok传递的参数是(str1,sep)。则它会返回a的地址并且将ab后面的'.'改为\0。即字符串变成"ab\0ed@rr"。此后第二次以后调用strtok函数时传的参数是strtok(NULL,sep),即不再传递str1的地址。该函数有记忆功能,第二次调用会直接从e的地址开始进行第二次切割直至遇到第二个符号ed后面的'@',并且返回e的地址。同时,它会像上次一样将'@'改变为'\0',此时字符串变成"ab\0ed\0rr"。并且下一次调用会指向第一个r。当找不到更多标点符号后会返回NULL。

注意:1.因为这个函数会对字符串进行实际改变,所以一般先对字符串进行备份再操作。2.因为反复调用函数不利于操作,可以使用下图所示的方法进行切割。

int main()
{
	char str1[] = "abc.def@eeee";
	char punctuation[] = "@.";
	char tmp[100] = { 0 };
	strcpy(tmp, str1);
	char* ret = NULL;
	for (ret = strtok(tmp, punctuation); ret!=NULL; ret = strtok(NULL, punctuation))
	{
		printf("%s\n",ret);
	}
	return 0;
}

8.strerror函数

char* strerror(int errnum)

这个函数用来报告错误信息,errnum是错误对应的数值。一般用errno为参数,errno为全局变量需要引用头文件errno.h。

#include<errno.h>
int main()
{
   char* pf=strerror(errno);
   return 0 ;
}

---2022年1月30日

---2022年1月31日

---2022年2月1日

---2022年2月2日

---2022年2月3日