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

C语言字符串函数内存函数(详解+实现)

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

C语言字符串函数内存函数(详解+实现)

文章目录
  • 字符串函数
    • 长度不受限的字符串函数
    • strlen
    • strcpy
    • strcat
    • strcmp
    • 长度受限的字符串函数:
    • strncpy
    • strncat
    • strncmp
    • strstr
    • strtok
    • strerror
    • 内存操作函数
    • memcpy
    • memmove
    • memcmp
    • memset
  • 字符串函数的模拟实现和注意
    • strlen模拟实现
    • strcpy模拟实现
    • strcat模拟实现
    • strcmp模拟实现
    • strstr模拟实现
    • memcpy模拟实现
    • memmove模拟实现

字符串函数 长度不受限的字符串函数 strlen

strlen的作用就是求字符串长度,从开始位置一直计数到之前,返回的是之前出现的字符个数。

strlen返回的是无符号数,所以如果比较两个字符串长度的时候不可以用strlen相减,因为无符号数-无符号数最后还是无符号数。

int main()
{
    if(strlen("abc")-strlen("abcd")<0)
        printf("<");
    return 0;   
}
strcpy

字符串拷贝函数,函数原型为:

因为source是不会被修改的所以加上source修饰。
注意:这里的source必须是以结尾的,不然拷贝找不到停不下,就会越界
拷贝会连着src末尾的一起拷贝过去。
dest的空间必须足够大,可以容纳下src
dest的空间必须可以修改,不可以是常量字符串

strcat

字符串追加函数:

将src这个字符串追加到dest后面,从dest的开始,最后会连同src的一同追加过去。
这里注意,strcat不可以自己给自己追加,因为追加的第一个字符覆盖了,这样子src就找不到了,就会陷入死循环最后越界。
注意:
目标空间必须足够大可以容纳下两个字符串的内容,目标空间必须可以修改。
源字符串必须有,不然就会越界。

strcmp

比较两个字符串的大小,比较原理是,先比较第一个字符的ASCII码值,如果相同就比较第二个字符,直到两个字符串都到了,或者遇到不相等的字符,根据ascii码值,如果第一个字符串的这个字符的ASCII码值大就返回>0的数字,如果小就返回小于0,相等的时候会返回0.

长度受限的字符串函数:

上面介绍的字符串函数都是长度不受限制的字符串函数,下面这些都是长度受到限制的字符串函数。我们知道长度不受限制很可能会出现安全隐患,比如,拷贝和字符串连接的时候目标空间够。这时候可以用strncpy进行字节决定长度的拷贝或者连接。

strncpy

该函数的作用就是将源字符串的前num个字节拷贝到dest处,如果num大于src的长度,这时候会在拷贝完之后在dest后面追加直到数目达到num。

strncat

在dest后面连接num字节数个src的字符。如果src的长度小于num那么只连接到src的处(也即是全部将src追加过去),就相当于是strcat了。这个函数也和strcat一样都会在末尾补上。

strncmp

比较两个字符串的前n个字节的字符

这个就是比较两个字符串的前num个字符,直到遇到不相等的字符串或者是遇到字符串结束,或者是达到了num个。

strstr

查找子串

在str1中查找str2这个子字符串,如果找到了就返回这个子字符串在str1中的首地址,找不到就返回空指针。

strtok

字符串分割函数

del字符串保存了分割字符串,就是作为分隔符的字符的集合。
注意:这个函数分割字符串的时候会改变原来的字符串,所以一般是使用拷贝的字符串进行分割。所以str不可以是常量字符串。
该函数找到了分隔符之后会将分隔符置为,然后返回这个分隔符前的字符串的首地址。并且函数会保存在字符串中的位置。下次寻找分割符的时候直接从该位置向后查找。所以下一次查找的时候第一个参数就不需要了,只需要传空指针即可。

int main()
{
	char arr[] = "hello@world&kisskernel";
	char copy[40];
	strcpy(copy, arr);
	for (char* ret = strtok(copy, "@&"); ret != NULL; ret = strtok(NULL, "@&"))
	{
		printf("%sn", ret);
	}
	return 0;
}

如果最后查找不到了就会返回NULL,这里如果多个分隔符连在一起比如@@或者@&&&,这种只有第一个分隔符有效剩下的忽略掉,因为这每两个分隔符之间没有字符串,所以也不会额外打印出来空行

strerror

这个函数就是返回错误码对应的错误信息。C语言中如果程序执行过程中遇到错误就会生成一个错误码,并且保存在全局变量errno中,所以只要引用头文件#include然后给strerror传参errno即可打印出来错误信息。

内存操作函数

上面的函数只能操作字符串,那么int,float等其他的类型的数组该怎么操作呢?这就用到了内存操作函数。

memcpy

内存拷贝函数:

将src的前num个字节拷贝到dest中最后返回的是dest的地址。该函数不管什么情况总是将src的num个字节拷贝到dest中,所以至少以保证dest的空间要是大于num的src的有效字节数也应该是大于等于num的。同时dest和src不可以是重叠的,如果重叠的拷贝使用memmove会更安全,因为如果内存重叠,memcpy默认从前向后拷贝就会将要拷贝过去的数据修改。
例如将:[1,2,3,4,5,6,7,8,9]将这个数组的1234拷贝到3456的位置,在拷贝12的时候已经将34改成了12,所以后面的拷贝会让56也变成12。

memmove

上面的memcpy不能拷贝发生重叠的数据,所以库函数提供了memmove来处理重叠的数据拷贝,在vs编译器里面memcpy可以拷贝重叠数据就是实现了memmove的功能,但是C语言标准规定memcpy只需要实现不重叠的内存拷贝即可。

memmove的使用方法是和memcpy一样的。

memcmp

内存比较函数,比较两块内存空间的内容,注意这里的比较方法是每个字节每个字节的比较。

如果两块内存空间相等就返回0,这个函数直到将所有num字节比较完,或者是遇到不相等的字节就停下来。
ptr1>ptr2的某个字节就返回>0的数字,ptr1

memset

内存设置函数,可以将ptr的num字节全部设置成为value,要注意设置int的时候如果value是1,并不是吧每个元素都初始化成1,而是这个元素的每个字节都是1。

字符串函数的模拟实现和注意 strlen模拟实现

这里实现strlen有三种方式
1,循环
2,递归(不创建变量)
3,指针-指针

size_t my_strlen(const char* str)
{
	assert(str);
	size_t count = 0;
	while (*str)
	{
		count++;
		str++;
	}
	return count;
}

断言要注意,str不能是空指针所以需要断言。然后就让指针不等于不断向后移动,计数器++,最后返回计数器的值。

//递归
int my_strlen1(const char* str)
{
	assert(str);
	if (*str == '')
		return 0;
	else
		return 1 + my_strlen1(str + 1);
}
//指针-指针
int my_strlen2(const char* str)
{
	assert(str);
	char* begin = str;
	while(*str!='')
	{ 
		str++;
	}
	return str - begin;
}
strcpy模拟实现
char* my_strcpy(char* des, const char* sur)
{
	assert(des && sur);
	char* ans = des;
	while (*des++ = *sur++)
	{}
	return ans;
}

这里的实现很巧妙,用while判断条件,先将sur的值拷贝过去,然后判断sur是不是为,不是就继续,是就会退出循环,因为的ASCII码值就是0,所以可以直接当作判断为假的条件。这样可以省去最后再补上这一句代码。

strcat模拟实现
char* my_strcat(char* dest, const char* src)
{
	assert(dest && src);
	char* ans = dest;
	while(*(++dest))
	{ }
	while (*dest++ = *src++)
		;
	return ans;
}

思路就是,先找到dest的位置然后进行字符串拷贝。要连着src的一起拷贝过去。

strcmp模拟实现
int my_strcmp(const char* str1, const char* str2)
{
	assert(str1 && str2);
	while (*str1 == *str2 && *str1!='')
	{
		str1++;
		str2++;
	}
	return *str1 - *str2;
}

思路就是循环比较两个字符串对应字符,相等就继续,直到字符串不相等或者str1遇到了就跳出循环。为什么str1遇到就跳出循环?str2遇到呢?这里写str1或者str2都是可以的。因为这里情况:如果str1先遇到,这时候str2不为,不相等,跳出循环,str2遇到也是这样。如果两个同时遇到这时候还是相等的,但是不可以继续++了需要第二个str1!=这个条件跳出循环。
最后返回两个的差值就可以了。str1大差值为+,str2大差值为-,str1str2就会返回0.

strstr模拟实现
char* my_strstr(const char* str1, const char* str2)
{
	assert(str1 && str2);
	if (*str2 == '')
		return str1;
	char* p = str1;

	while (*p)
	{
		char* s1 = p;
		char* s2 = str2;
		while (*s1 == *s2 && *s1!='')
		{
			s1++;
			s2++;
		}
		if (*s2 == '')
			return p;
		p++;
	}
	return NULL;
}

思路:如果str2是空字符串直接返回str1,然后str2不为空的时候就进行比较
情况1:直接从前向后比较成功了。
情况2:就是部分字符相同,比较到后面不相同了。这时候就需要重新匹配从刚刚str1开始匹配的下一个字符开始。
所以使用了s1和s2两个指针,用来移动比较,p用来标记str1中的位置。如果s1和s2的字符相同则开始比较,如果比较到了s2为也即是比较完毕,完全匹配,就返回首字符的地址,也就是从p位置开始匹配的这个字符串首地址也就是p指针。如果不相等,就让p向后移动然后如果p没到str1的结尾就将p赋值给s1,s2也回到str2的开头再次进行比较。

memcpy模拟实现
void* my_memcpy(void* dest, const void* src, int size)
{
	assert(dest && src);
	void* ret = dest;
	while (size--)
	{
		*(char*)dest = *(char*)src;
		++(char*)dest;
		++(char*)src;
	}
	return ret;
}

思路:就是将src和dest他们强转成为char*类型的指针一个字节一个字节的拷贝。

memmove模拟实现

关于memmove的内存重叠,我们可以发现如果是这种情况src是源头,dest是要拷贝过去的目的地

这时候需要从前——》后拷贝,如果从后向前就会先覆盖掉src还没有拷贝的内容

而这种情况则需要从后——》前拷贝,所以综合这两种情况,我们可以得出一个判断条件就是
dest>src的时候从后向前,dest

void* my_memmove(void* dest, const void* src, size_t num)
{
	assert(dest && src);
	void* ret = dest;
	if (dest < src)//从前向后
	{
		while (num--)
		{
			*(char*)dest = *(char*)src;
			dest = (char*)dest + 1;
			src = (char*)src + 1;
		}
	}
	else
	{
		while (num--)
		{
			*((char*)dest + num) = *((char*)src + num);
		}
	}
	return ret;
}
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/1009017.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

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

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