各种字符串函数和字符函数总结

简介

   C语言中对于字符字符串的操作甚是频繁,经常把人给弄晕,今天我来总结一下。C语言中并没有定义字符串的关键字,但是字符串是存在的,字符串一般存放在常量字符串中或者字符数组中,也可以定义一个指向字符串的字符型指针,利用这个字符型指针可以访问该字符串。代码如下:

char arr1[] = {'a','b','c','d','e','f','\0'};//字符数组
char arr2[] = "abcdef";
char* parr = "abcdef";//指向字符串的字符型指针

   以上代码中,“abcdef” 属于常量字符串,可以看到字符串保存在字符数组中的方式有两种(arr1和arr2),这两种方式结果是相同的。


1 字符串函数介绍与模拟实现

  本章主要介绍字符串的库函数的使用和注意事项,并且尝试自己写代码实现。

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

1.1.1 strlen

  长度不受限制的的字符串函数,由于操作过程中以‘\0’作为字符串的结束标志,这就意味着当字符串缺少‘\0’时,会导致程序崩溃,从而使得程序的不安全性增高。在VS编译器中,当使用这一类函数是会报警告,一般在程序开头加上 #define _CRT_SECURE_NO_WARNINGS 1,可以忽略警告。

  •  定义格式:
			 size_t strlen(const char* str);
  •  函数功能:用于求str指向的字符串长度

  •  输入参数:
        str:字符串的地址(类型:常字符型指针)。

  •  输出参数:
        字符串长度(类型:无符号整型)

  •  函数所在库:<string.h>

  可以看到,strlen的参数是一个常字符型指针变量str,str内部存储的是字符串的首地址。返回值是一个无符号整型(size_t)数据,也即字符串的长度。strlen函数计算字符串长度时,是以’\0’为标志,‘\0’前面出现的字符个数算为字符串长度。
(1)使用例程

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include<stdlib.h>
#include<string.h>
int main()
{
	unsigned int length1 = 0, length2 = 0, length3 = 0;
	char arr1[] = { 'a','b','c','d','e','f','\0' };
	char arr2[] = "abcdef";
	char* parr = "abcdef";
	length1 = strlen(arr1);//将strlen的返回值赋值给length1
	printf("%d\n", length1);

	length2 = strlen(arr2);//将strlen的返回值赋值给length2
	printf("%d\n", length2);

	length3 = strlen(parr);//将strlen的返回值赋值给length3
	printf("%d\n", length3);
	system("pause");
	return 0;
}

运行结果:
在这里插入图片描述

结果分析:
  请注意:arr1和arr2是一样的。对于字符数组arr1,arr1内部保存的是字符串的首地址。arr1中,‘\0’前面的字符个数有6个,所以计算的结果为6,因为"abcdef" 在保存的时候会在末尾添加一个‘\0’,所以计算的出来的也是6。如果没有‘\0’计算得到的是一个随机值(在不同的编译器、不同的电脑得出的结果可能不同),错误示例代码如下:

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
	unsigned int length1 = 0;
	char arr1[] = { 'a','b','c','d','e','f'};
	length1 = strlen(arr1);//将strlen的返回值赋值给length1
	printf("length1 = %d\n", length1);
	system("pause");
	return 0;
}

运行结果:
在这里插入图片描述
(2)模拟实现

第一种:计数器实现

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stdlib.h>
size_t my_strlen(const char* arr)
{
	size_t cnt = 0;//定义计数器cnt
	while (*arr != '\0')
	{
		arr++;
		cnt++;
	}
	return cnt;
}
int main()
{
	char arr[] = "abcdef";
	printf("%u\n", my_strlen(arr));
	system("pause");
	return 0;
}

第二种:递归实现

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stdlib.h>
size_t my_strlen(const char* arr)
{
	if (*arr != '\0')
	{
		arr++;
		return 1 + my_strlen(arr);//递归
	}
	return 0;
}
int main()
{
	char arr[] = "abcdef";
	printf("%u\n", my_strlen(arr));
	system("pause");
	return 0;
}

第三种:利用地址实现

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include<stdlib.h>
int my_strlen(const char* arr)
{
	const char* ret = arr;//记录初始地址
	while (*ret++);
	return ret - arr-1;//地址相减
}
int main()
{
	char arr[] = "abcdef";
	printf("%d\n", my_strlen(arr));
	system("pause");
	return 0;
}

1.1.2 strcpy

  定义格式:

			 char* strcpy(char* des, const char* src);
  •  函数功能:将src指向的字符串复制到des指向的空间。

  •  输入参数:
       des:指向目标字符串的字符型指针,目标字符串存储的空间称为目标空间,des的值为目标空间的首地址;
       src:指向源字符串的常字符型指针,源字符串存储的空间称为源空间,src的值为源空间的首地址。

  •  输出参数:
       输出目标空间的首地址(类型:字符型指针)。

  •  注意事项:
       源字符串必须以‘\0’结束;
       源字符串中的’\0’也要拷贝到目标空间;
       目标空间要足够大,以保证能够存放源字符串;
       目标空间要保证可变。

  •  函数所在库:<string.h>

(1)使用例程
① 正确用法

//将字符串“abcdef”复制到目标空间
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include<stdlib.h>
#include<string.h>
int main()
{
	char des[20];//目标空间
	char src[]= { 'a','b','c','d','e','f','\0'};//源字符串
	//char* src= "abcdef";//源字符串
	printf("%s\n", strcpy(des, src));
	system("pause");
	return 0;
}

运行结果:
在这里插入图片描述
② 错误用法
错误1:源字符串没有以‘\0’结束

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include<stdlib.h>
#include<string.h>
int main()
{
	char des[20];//目标空间
	char src[]= { 'a','b','c','d','e','f'};//字符串没有以'\0'结尾
	printf("%s\n", strcpy(des, src));
	system("pause");
	return 0;
}

错误2:目标空间过小

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include<stdlib.h>
#include<string.h>
int main()
{
	char des[3];//目标空间过小
	char src[]= { 'a','b','c','d','e','f','\0'};
	printf("%s\n", strcpy(des, src));
	system("pause");
	return 0;
}

错误3:目标空间不可变

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include<stdlib.h>
#include<string.h>
int main()
{
	char* des = "123456789";//目标空间,des指向的是一个常量字符串
	char src[]= { 'a','b','c','d','e','f','\0' };
	printf("%s\n", strcpy(des, src));
	system("pause");
	return 0;
}

(2)模拟实现

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include<stdlib.h>
#include<assert.h>
char* my_strcpy(char* des, const char* src)
{
	char* ret = des;
	assert(des != NULL);
	assert(src != NULL);
	while (*src != '\0')//拷贝字符串
	{
		*des = *src;
		des++;
		src++;
	}
	*des = *src;//将源字符串中的'\0'拷贝到目标空间
	return ret;//返回目标空间地址
}
int main()
{
	char des[20];//目标空间
	printf("%s\n", my_strcpy(des, "abcdef"));//测试
	system("pause");
	return 0;
}

将以上代码简化:

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include<stdlib.h>
#include<assert.h>
char* my_strcpy(char* des, const char* src)
{
	char* ret = des;
	assert(des != NULL);
	assert(src != NULL);
	while (*des++ = *src++);//当*src为'\0'时,退出循环,也即完成复制
	return ret;//返回目标空间地址
}
int main()
{
	char des[20];//目标空间
	printf("%s\n", my_strcpy(des, "abcdef"));//测试
	system("pause");
	return 0;
}

1.1.3 strcat

  定义格式:

			 char* strcat(char* des, const char* src);
  •  函数功能:将src指向的字符串粘接到des指向的字符串后面。

  •  输入参数:
       des:指向目标字符串的字符型指针,目标字符串存储的空间称为目标空间,des的值为目标空间的首地址;
       src:指向源字符串的常字符型指针,源字符串存储的空间称为源空间,src的值为源空间的首地址。

  •  输出参数:
       输出目标空间的首地址(类型:常字符型指针)。

  •  注意事项:
       源字符串必须以‘\0’结束;
       源字符串中的’\0’也要粘接到目标空间;
       目标空间要足够大,以保证能够存放源字符串;
       目标空间要保证可变。

  •  函数所在库:<string.h>

(1)使用例程
① 正确用法

//在字符串"I love "后面粘接字符串"you"
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
	char arr[20] = "I love ";
	printf("%s\n", strcat(arr, "you"));
	system("pause");
	return 0;
}

运行结果:
在这里插入图片描述

(2)模拟实现

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>
char* my_strcat(char* des, const char* src)
{
	assert(des != NULL);
	assert(src != NULL);
	char* ret = des;
	while (*des != '\0')//找到des中字符'\0'的位置
	{
		des++;
	}
	while (*des++ = *src++);//将src指向的字符串粘接在des指向的字符串后面
	return ret;
}
int main()
{
	char arr[20] = "I love ";
	printf("%s\n", my_strcat(arr, "you"));//测试
	system("pause");
	return 0;
}

1.1.4 strcmp

  定义格式:

		int strcmp(const char* str1, const char* str2);
  •  函数功能:将str1指向的字符串与str2指向的字符串进行比较

  •  输入参数:
       str1:指向第一个字符串的常字符型指针;
       str2:指向第二个字符串的常字符型指针。

  •  输出参数:
       两个字符串的对比结果(类型:整型)。
       第一个字符串大于第二个字符串,则返回数字 1
       第一个字符串等于第二个字符串,则返回数字 0
       第一个字符串小于第二个字符串,则返回数字 -1

  •  C语言标准规定:
       第一个字符串大于第二个字符串,则返回大于0的数字 ;
       第一个字符串等于第二个字符串,则返回数字 0
       第一个字符串小于第二个字符串,则返回小于0的数字 。

  •  函数所在库:<string.h>

(1)使用例程
① 正确用法

//比较字符串"abc"和字符串"def"的大小
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
	char* str1 = "abc";
	char* str2 = "def";
	int n = strcmp(str1, str2);
	printf("%d\n",n);
	system("pause");
	return 0;
}

运行结果:
在这里插入图片描述
  字符串比较是先从第一个字符比较,如果相等则对比第二个字符,以此类推。显然由于’a’ < ‘b’ 故判定为字符串"abc"小于字符串"def",所以输出为-1。

(2)模拟实现

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
int my_strcmp(const char* str1, const char* str2)
{
	assert(str1 != NULL);
	assert(str2 != NULL);
	while (*str1 == *str2)
	{
		if (*str1 == '\0')
			return 0;
		str1++;
		str2++;
	}
	if (*str1 - *str2 > 0)
		return 1;
	else
		return -1;
}
int main()
{
	char* str1 = "abc";
	char* str2 = "def";
	int n = my_strcmp(str1, str2);
	printf("%d\n",n);
	system("pause");
	return 0;
}

实现C语言标准规定的strcmp函数

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
int my_strcmp(const char* str1, const char* str2)
{
	assert(str1 != NULL);
	assert(str2 != NULL);
	while (*str1 == *str2)
	{
		if (*str1 == '\0')
			return 0;
		str1++;
		str2++;
	}
	return *str1 - *str2;
}
int main()
{
	char* str1 = "abc";
	char* str2 = "def";
	int n = my_strcmp(str1, str2);
	printf("%d\n",n);
	system("pause");
	return 0;
}

运行结果:
在这里插入图片描述


1.2 长度受限制的字符串函数

1.2.1 strncpy

  定义格式:

char* strncpy(char* des, const char* src, size_t num);
  •  函数功能:将src指向的字符串的前num个字符拷贝到des指向的空间。

  •  输入参数:
       des:指向目标字符串的字符型指针,目标字符串存储的空间称为目标空间,des的值为目标空间的首地址;
       src:指向源字符串的常字符型指针,源字符串存储的空间称为源空间,src的值为源空间的首地址;
       num:拷贝的字符个数(类型:无符号整型)。

  •  输出参数:
       输出目标空间的首地址(类型:字符型指针)。

  •  注意事项:

   目标空间要足够大,以保证能够存放num个字符;

   如果源字符串的前num个字符包含‘\0’时,则不足的字符自动以字符’\0’代替,直到num个;

   如果源字符串的前num个字符不包含‘\0’时,则要把目标空间下标为num的字符手动置为’\0,防止出现乱码;

   目标空间要保证可变。

  •  函数所在库:<string.h>

(1)使用例程
  姑且先把des、src称为字符串,这样方便叙述。

① 正确用法

情况1:当源字符串src前num个字符包含‘\0’时

//将数组src前num个字符复制到目标空间
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include<stdlib.h>
#include<string.h>
int main()
{
	char des[20];//目标空间
	char src[] = { 'a','b','\0','d','e','f','\0'};//源字符串 
	size_t num = 12;
	char* pdes = strncpy(des, src, num);
	printf("%s\n", pdes);
	system("pause");
	return 0;
}

运行结果:

在这里插入图片描述

des的内部存储情况如下
在这里插入图片描述

  结果分析:因为字符串src的第3和第7个字符为‘\0’,而num = 12,所以说字符串src前12个字符包含‘\0’,可以看到des的从第3个字符到第12个字符,被自动置为‘\0’。这说明strncpy复制到‘\0’,即使没到num也会提前停止复制,这一点要特别注意。

情况2:当字符串src前num个字符不包含‘\0’时,要手动将第num个字符置为’\0’

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include<stdlib.h>
#include<string.h>
int main()
{
	char des[20];//目标空间
	char src[] = { 'a','b','c','d','e','f','\0'};//源字符串 
	size_t num = 4;
	char* pdes = strncpy(des, src, num);
	des[num] = '\0';//复制完毕后,为保险起见,将最后一个字符置为'\0'
	printf("%s\n", pdes);
	system("pause");
	return 0;
}

运行结果:
在这里插入图片描述

内部存储:
在这里插入图片描述
  从程序里可以看到,把目标空间下标为num的字符手动置为’\0’,所以输出没有出现乱码。如果不手动置为‘\0’,输出时就会出现乱码,示范代码如下:

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include<stdlib.h>
#include<string.h>
int main()
{
	char des[20];//目标空间
	char src[] = { 'a','b','c','d','e','f','\0' };//源字符串 
	size_t num = 4;
	char* pdes = strncpy(des, src, num);
	printf("%s\n", pdes);
	system("pause");
	return 0;
}

运行结果:
在这里插入图片描述

(2)模拟实现

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include<stdlib.h>
#include <assert.h>
char* my_strncpy(char* des, const char* src, size_t num)
{
	char* ret = des;
	assert(des != NULL);
	assert(src != NULL);
	while (num--)
	{
		if (*src == '\0')
		{
			*des++ = '\0';
		}
		else
		{
			*des++ = *src++;
		}
	}
	return ret;
}
int main()
{
	char des[20];//目标空间
	char src[] = { 'a','b','c','d','e','f','\0' };//源字符串 
	size_t num = 4;
	char* pdes = my_strncpy(des, src, num);
	des[num] = '\0';//将最后一个字符置为'\0',防止输出时出现乱码
	printf("%s\n", pdes);
	system("pause");
	return 0;
}

1.2.2 strncat

  定义格式:

char* strncat(char* des, const char* src, size_t num);
  •  函数功能:将src指向的字符串前num个字符粘接到des指向的字符串后面。

  •  输入参数:
       des:指向目标字符串的字符型指针,目标字符串存储的空间称为目标空间,des的值为目标空间的首地址;
       src:指向源字符串的常字符型指针,源字符串存储的空间称为源空间,src的值为源空间的首地址。

  •  输出参数:
       输出目标空间的首地址(类型:常字符型指针)。

  •  注意事项:
       目标空间要进行初始化
       目标空间要足够大,以保证能够存放源字符串;
       目标空间要保证可变。

  •  函数所在库:<string.h>

(1)使用例程
① 正确用法

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
	char arr[20] = "To be ";
	printf("%s\n", strncat(arr, "or not to be", 2));
	system("pause");
	return 0;
}

运行结果:
在这里插入图片描述
②错误示范,目标空间未初始化

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
	char arr[20];
	printf("%s\n", strncat(arr, "abc", 12));
	system("pause");
	return 0;
}

运行结果:
在这里插入图片描述

(2)模拟实现

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
char* my_strncat(char* des, const char* src, size_t num)
{
	assert(des != NULL);
	assert(src != NULL);
	char* ret = des;
	while (*des != '\0')//找到des中字符'\0'的位置
	{
		des++;
	}
	while(num--)
	{
		*des++ = *src++;//将src指向的字符串粘接在des指向的字符串后面
	}
	return ret;
}
int main()
{
	char arr[20] = "To be ";
	printf("%s\n", my_strncat(arr, "or not to be", 2));
	system("pause");
	return 0;
}

1.2.3 strncmp

  定义格式:

int strncmp(const char* str1, const char* str2, size_t num);
  •  函数功能:将str1指向的字符串前num个字符与str2指向的字符串的前num个字符进行比较

  •  输入参数:
       str1:指向第一个字符串的常字符型指针;
       str2:指向第二个字符串的常字符型指针。
       num:需要比较的字符个数。

  •  输出参数:
       两个字符串的对比结果(类型:整型)。
       第一个字符串大于第二个字符串,则返回数字 1
       第一个字符串等于第二个字符串,则返回数字 0
       第一个字符串小于第二个字符串,则返回数字 -1

  •  函数所在库:<string.h>

(1)使用例程
① 正确用法

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
	char* str1 = "abcadflads";
	char* str2 = "ablsdkjfal";
	int n = strncmp(str1, str2, 2);
	printf("%d\n", n);
	system("pause");
	return 0;
}

运行结果:

在这里插入图片描述

(2)模拟实现

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
int my_strncmp(const char* str1, const char* str2, size_t num)
{
	assert(str1 != NULL);
	assert(str2 != NULL);
	while (num--)
	{
		if (*str1 > * str2)// 第一个字符串大于第二个字符串,返回1
		{
			return 1;
		}		
		else if (*str1 == *str2)// 第一个字符串等于第二个字符串,返回0
		{
			if (*str1 == '\0' || num == 0)
				return 0;
			str1++;
			str2++;
		}
	}
	return -1;// 第一个字符串小于第二个字符串,返回-1
}
int main()
{
	char str1[] = { 'a','b','\0','f','e','f','\0' };
	char str2[] = { 'a','b','\0','d','e','f','\0' };
	int n = my_strncmp(str1, str2, 7);
	printf("%d\n", n);
	system("pause");
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值