栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

字符函数和字符串函数

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

字符函数和字符串函数

字符函数和字符串函数介绍及解析

常见字符串的库函数的使用和注意事项

求字符串长度字符串拷贝函数strcpy字符串追加函数strcat字符串比较函数strcmp 长度受限制的字符串函数

strncpy函数strncat函数strncmp函数strstr函数strtok函数strerror函数字符转换函数 内存操作函数

memcpy函数memmove函数memcmp函数memset函数—内存设置

常见字符串的库函数的使用和注意事项 求字符串长度

strlen函数
我们都知道C语言没有字符串类型,举个例子:char arr[ ]=" abcdef " ; arr作为数组名会被传递到strlen()函数中来计算字符串长度。了解一下strlen函数的基本信息:

strlen函数的函数声明

strlen函数的参数和返回类型
但这只是一个普通的字符串,abcdef后面会有‘’,但是如果没有‘’呢?

#include
//strlen函数的实现
int main()
{
	char arr[] = { 'a','b','c','d','e','f' };
	int ret = strlen(arr);
	printf("%dn", ret);
	return 0;
}

如上代码运行后发现,程序最终会打印一个不是我们意料中的数,这是因为strlen函数以 作为结束标志,strlen函数返回的是 前面字符出现的个数(不包含 )这里注意两个点:

第二点是使用者尤其会忽略的一个地方,这里再次提醒。
模拟实现strlen函数:

//模拟实现strlen
#include
#include
size_t my_strlen(const char* str)
{
	int count = 0;
	assert(str != NULL);
	while (*str != '')
	{
		count++;
		str++;
	}
	return count;
}
int main()
{
	char arr[] = "abcdef";
	int len = my_strlen(arr);
	return 0;
}
字符串拷贝函数strcpy
#include
int main()
{
	char arr1[20]={0};
	char arr2[]="abcdef";
	strcpy(arr1,arr2);
	printf("%sn",arr1);
	return 0;
}

参考如上代码可以知道strcpy函数的基本实现,就是把arr2的内容拷贝到arr1中。但是被拷贝的内容中要有 ‘’ , strcpy会把arr2中‘ ’之前的所有内容全部拷贝到arr1中,同时将 ‘ ’也进行拷贝。 如果arr2中没有‘ ’,就可能会导致程序崩溃。strcpy只会寻找‘ ’,如果没有找到,就会一直向后寻找,最终导致访问越界。但是看下面这个例子:

#include
#include
int main()
{
	char arr1[20] = { 0 };
	char arr2[10] = { 'a','b','c' };
	strcpy(arr1, arr2);
	printf("%sn", arr1);
	return 0;
}

运行一下会发现没有任何问题,这是因为arr2数组被初始化了,虽然只存放了三个元素,但是剩余的空间被初始化成了‘ ’。因此strcpy函数还是可以正常使用的。
目标空间必须足够大,以便确保字符串能存放到目标空间中。

此时就引出了strcpy函数的一个缺陷:strcpy函数不会考虑拷贝会不会导致程序崩溃,只会一股脑进行拷贝,因此此时程序员不能依靠函数本身来进行纠错,此时进行代码编写的时候要格外注意。

目标空间必须是可变的

这样的代码时错误的,在运行的时候会报错。
strcpy的模拟实现

//strcpy函数
#include
#include
char* my_strcpy(char* str1, const char* str2)
{
	assert(str1 && str2);
	char a = 0;
	char* ret = str1;
	while (*str1++ = *str2++)
	{
		;
	}
	*str1 = *str2;//拷贝''
	return ret;
}
int main()
{
	char arr1[20] = {0};
	char arr2[20] = "hello,bit";
	my_strcpy(arr1, arr2);

	printf("%sn", arr1);
	return 0;
}

字符串追加函数strcat


基本了解一下strcat的作用:

int main()
{
	char arr1[20] = "hello";
	char arr2[] = " bit";
	strcat(arr1, arr2);
	
	printf("%sn", arr1);
	return 0;
}


strcat函数在使用的时候,原字符串必须要有‘ ’,要以‘ ’作为结束标志,目标字符串中也要有‘ ’,从‘ ’向后追加。

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

目标空间必须可以修改
模拟实现strcat

//strcat函数
#include
#include
my_strcat(char* str1, const char* str2)
{
	assert(str1 && str2);
	char* ret = str1;
	while (*str1 != '')
	{
		str1++;
	}
	
	while (*str1++ = *str2++)
	{
		;
	}
	return ret;
}

int main()
{
	char arr1[20] = "hello";
	char arr2[] = " bit";
	//strcat(arr1, arr2);
	my_strcat(arr1, arr2);
	printf("%sn", arr1);
	return 0;
}

字符串比较函数strcmp


该函数返回int类型
第一个字符串大于第二个字符串,返回大于0的数字
第一个字符串等于第二个字符串,返回0
第一个字符串小于第二字符串,返回小于0的数字

注意,strcmp比较的不是字符串的长度,比较的方式是对每个元素的ASCII码值进行比较,比如上面的例子中,arr1中的‘ a ’与arr2中的 ‘ a ’相同,一直到arr1中的‘c’与‘q’进行比较,后者的ASCII码值比前者的ASCII码值大,因此输出-1.strcmp 的比较会一直进行到不同或者都遇到‘ ’。
模拟实现strcmp

#include
#include
int my_strcmp(const char* str1, const char* str2)
{
	assert(str1 && str2);
	while (*str1 != '' && *str2 != ''&&*str1==*str2)
	{
		str1++;
		str2++;
	}
	return *str1 - *str2;
}
int main()
{
	char arr1[] = "abcdef";
	char arr2[] = "abc";
	int ret = my_strcmp(arr1, arr2);
	printf("%dn", ret);
	return 0;
}

以上所有的函数都是长度不受限制的字符串函数

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



程序的运行基本演示了函数的使用方法和作用:
size_t num表示拷贝字符串的个数,这么做程序就看起来安全了,但这只是相对安全,毕竟你阻止不了一个想写bug的程序员。
看一下下面这个特殊情况:

#include
int main()
{
	char arr1[] = "abcdef";
	char arr2[] = "qwd";

	strncpy(arr1, arr2, 5);
	printf("%sn", arr1);
	return 0;
}

如果代码是这样,arr2只有四个字符,但是却要求操作五个字符,当超出操作字符的数量时,会用‘ ’补齐,直到num个。

strncat函数


代码实现如下:

strncat会从‘ ’处进行追加,但是不同于上面的情况,当num越界时:

#include
int main()
{
	char arr1[20] = "abcdexxxxxx";
	char arr2[] = "qwe";
	strncat(arr1, arr2, 5);
	printf("%sn", arr1);
	return 0;
}



经过调试发现,并没有多余的‘ ’。

strncmp函数


函数参数中的size_t num表示的是比较几个元素。

//strncmp函数
#include
int main()
{
	char arr1[] = "abcdef";
	char arr2[] = "abcettyu";
	int ret=strncmp(arr1, arr2,4);
	printf("%dn", ret);
	return 0;
}
strstr函数


函数的作用是看一个字符串是不是另一个字符串的子串,也就是str2是不是在str1中,如果在返回字符串第一次出现的位置(地址)没有出现,就会返回空指针。 下面来看代码:

#include
int main()
{
	char arr1[] = "abcdeafgcdefxxxx";
	char arr2[] = "cdef";
	char*p=strstr(arr1, arr2);
	if (p == NULL)
	{
		printf("找不到子串n");
	}
	else
	{
		printf("%sn", p);
	}
	return 0;
}


模拟实现strstr

//strstr函数
#include
char* my_strstr(char* str1, char* str2)
{
	char* s1 = str1;
	char* s2 = str2;

	char* cur = str1;
	while (*cur)
	{
		s1 = cur;
		s2 = str2;

		while (*s1 == *s2&&*s1&&*s2)
		{
			s1++;
			s2++;
		}
		if (*s2 == '');
		{
			printf("找到了n");
			return cur;
		}
		cur++;
		
	}
	return NULL;
}
int main()
{
	char arr1[] = "abcdeafgcdefxxxx";
	char arr2[] = "cdef";
	char*p=my_strstr(arr1, arr2);
	if (p == NULL)
	{
		printf("找不到子串n");
	}
	else
	{
		printf("%sn", p);
	}
	return 0;
}
strtok函数


sep参数是个字符串,定义了用作分隔符的字符集合。

第一个参数指定一个字符串,它包含了0个或者多个由sep字符串中一个或者多个分隔符分割的标记。也就是说,str指向的字符串是sep中的字符分开的。

strtok函数要找到str中的下一个标记,并将其用‘ ’结尾,返回一个指向这个标记的指针。strtok函数会改变被操作的字符串,所以在使用strtok函数切分的字符串一般是临时拷贝的内容并且可修改

strtok函数的第一个参数不为NULL,函数将找到str中第一个标记,strtok函数将保存它在字符串中的位置。
strtok函数的第一个参数为UNLL,函数将在同一个字符串中被保存的位置开始,查护下一个标记。
如果字符串中不存在更多的标记,则返回NULL指针。
好像有些不好懂,我们来看一下代码:

//strtok函数
#include
#include
int main()
{
	char arr[] = "adffvgb@year.net";
	char buf[30] = { 0 };
	strcpy(buf,arr);
	//strtok函数
	//"@."定义为一个字符串
	const char* str = "@.";
	char* pp = NULL;
	//printf("%sn",strtok(buf, str));//只找第一个标记
	//printf("%sn", strtok(NULL, str));//从保存好的位置开始继续往后查找
	//printf("%sn", strtok(NULL, str));
	for (pp = strtok(buf, str); pp != NULL; pp=strtok(NULL, str))
	{
		printf("%sn",pp);
	}
	return 0;
}

这里注意,只要含有str内容中的字符,就会进行分割。

strerror函数

全局变量errno(错误码)–>一旦某一个库函数调用失败,就会返回一个错误码,将错误码放进errno中

返回值为错误码对应错误信息的指针。

strerror函数和errno的使用(malloc函数是在堆区开辟空间)

字符转换函数

int tolower ( int c ) ; 函数实现大写转换小写
int toupper ( int c ) ; 函数实现小写转换大写

内存操作函数 memcpy函数


参数类型之说以是void*是因为作者在实现memcpy的时候,并不知道使用者会传递一个什么样的参数进去(与qsort函数类似)

代码基本包含了函数的作用和使用方法,其中count的意思是拷贝的字节数,是一个无符号整型数据。

模拟memcpy函数

void* my_memcpy(void* str1, const void* str2,size_t count)
{
	assert(str1 && str2);
	while (count--)
	{
		*((char*)str1) = *((char*)str2);
		str1 = (char*)str1 + 1;
		str2 = (char*)str2 + 1;
	}
}

但是还是会有一些意外:

这个程序,我们预期的结果是1 2 1 2 3 4 5 8 9 10,但实际上结果是1 2 1 2 1 2 1 8 9 10,这是因为程序改变了源数组中的内容,数组内部的拷贝发生了重叠,这时就引出了另外一种函数:memmove函数

memmove函数

memmove函数可以实现重叠内存的拷贝


但是如果模拟这个函数,还有很多细节要注意:

以上的这两种拷贝字符串如果使用同一种拷贝顺序,必然会导致拷贝出现问题,综上,memmove函数的模拟实现要分情况。

src是源数组首元素的地址,dest是目标数组的首元素的地址

如果src的地址比dest大,就从前往后进行拷贝。

如果src的地址dest小,但是二者仍然重叠,就从后往前进行拷贝。

dest继续向后二者不在重叠的时候,可以从后向前拷贝,也可以从前向后拷贝。

#include
#include
void* my_memcpy(void* str1, const void* str2,size_t count)
{
	assert(str1 && str2);
	while (count--)
	{
		*((char*)str1) = *((char*)str2);
		str1 = (char*)str1 + 1;
		str2 = (char*)str2 + 1;
	}
}
void*my_memmove(void* str1, const void* str2,size_t count)
{
	if (str1 < str2&&str1<(char*)str2+count)
	{
		//前->后
		assert(str1 && str2);
		while (count--)
		{
			*(char*)str1 = *(char*)str2;
			str1 = (char*)str1 + 1;
			str2 = (char*)str2 + 1;
		}
		
	}
	else if(str1>str2)
	{
		//后—>前
		assert(str1 && str2);
		while (count--)
		{
			*((char*)str1 + count) = *((char*)str2 + count);
		}
	}
}
int main()
{
	int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
	int arr2[5] = { 0 };
	//my_memcpy(arr2, arr1, 20);
	memmove(arr1 + 2, arr1, 20);//实现重叠内存的拷贝
	return 0;
}
memcmp函数


对于函数的返回值

函数的比较是一个字节一个字节进行比较的。

memset函数—内存设置


dest是数组地址,c是改变的内容,count是改变的字节数,修改的是每个字节,而不是某个字节

函数的意思就是把内存中的每个字节都改成6。

内容有点多,大家慢慢学习,希望大家收获知识。心之所向,素履以往!

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/779461.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号