理解并熟悉库函数中的几个常见字符串函数

本文介绍了C语言中几个重要的字符串处理函数,包括strtok用于字符串分割,memcpy用于内存拷贝,以及strerror用于将错误码转化为错误信息。文章通过示例代码详细解释了这些函数的使用方法和应用场景,并讨论了内存重叠时如何使用memmove函数来避免问题。此外,还提到了memcmp和memset函数在比较和初始化内存块中的作用。
摘要由CSDN通过智能技术生成

首先常用字符串函数有:

strlen函数

strcpy函数

strcmp函数

strcat函数

strstr函数

strtok函数

memcpy函数

memmove函数

strerror函数

本次模拟的是strtok函数,memcpy函数,strerror函数,memmove函数,这三个比较难的函数

首先是

strtok函数

通过一个案例

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>
int main()
{
	char arr[] = "hanchun@yeah.net";
	char buf[30] = { 0 };//"hanchun@yeah.net"
	strcpy(buf,arr);
	//将arr数组内的字符串拷贝到buf中
	printf("%s\n",buf);
	const char* p = "@.";
	char *str = strtok(buf, p);//切割buf字符串,找到@改为\0变为"hanchun\0yeah.net",同时返回'h'的地址
	printf("%s\n",str);
	str = strtok(NULL, p); //从刚刚保存好的地址开始找, 找到.改为\0变为"hanchun\0yeah\0net", 同时返回'y'的地址
	printf("%s\n", str);
	str = strtok(NULL,p);//从'y'的地址开始找,往后找不到要修改的字符了,遇到\0就会停止
	printf("%s\n", str);
	return 0; 
}

运行结果如下:

 知道了如何使用srtok函数,如何更高效的使用这个函数呢,可以参考for循环初始化和判断最后执行代码块的思路

int main()
{
	char arr[] = "192.168.3.212";
	char buf[30] = { 0 };
	strcpy(buf, arr);
	const char* p = ".";
	//首先初始化str为空指针
	char* str = NULL;
	for (str = strtok(buf, p); str != NULL; str = strtok(NULL, p))
	{
		printf("%s\n", str);
	}
	return 0;
}

运行结果也没有问题

 

既然已经搞懂了如何使用,那么他的应用场景也能看出来,用于像是邮箱的后缀名的切割和剪切之后传输数据,

strerror函数

        这个函数比较重要,需要模拟他在库函数里面的实现,还是老样子,先看看这个函数如何使用

这个函数是将错误码翻译成错误信息

:C语言的库函数在调用失败的时候,会将一个错误码存放在一个叫:errno的变量中

当我们想知道调用库函数的时候发生了什么错位信息,就可以将Lerrno中的错误码进行翻译成错误信息,下面是该函数的使用情况:当需要打开文件需要确保有打开还是没有打开都需要用这个文件,进行报错

#include<stdio.h>
#include<errno.h>
#include <string.h>

#define _CRT_SECURE_NO_WARNINGS fopen,strerror
int main()
{
	//打开文件
	// 打开文件的时候,如果文件的打开方式是"r"
	//打开文件失败的话,会返回NULL
	FILE* pf = fopen("test.txt","r");
	if (pf == NULL)
	{
		printf("打开文件失败,原因是 %s\n",strerror(errno));
		return 1;
	}
	//读写文件
	//关闭文件
	fclose(pf);
	pf = NULL;
	return 0;
}

 

 这里替换printf("打开文件失败,原因是 %s\n",strerror(errno));为perror("打开文件失败")

可以把perror函数理解成printf+strerror

接下来就是重头戏了

memcpy函数

意为内存拷贝函数

#include<stdio.h>
int main()
{
	int arr1[] = {1,2,3,4,5,6,7,8,9,10};
	int arr2[8] = { 0 };
	//把arr1中的前五个数据拷贝到arr2中
	memcpy(arr2,arr1,20);
	//将arr1的值赋给arr2,通过访问arr1中的20个字节=刚好是五个int元素

	return 0;
}

 当然如果是其他数据类型呢?memset函数又会报错吗?代码所示

void test01()
{
	int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
	int arr2[8] = { 0 };

	//把arr1中的前五个数据拷贝到arr2中
	memcpy(arr2, arr1, 20);
	//将arr1的值赋给arr2,通过访问arr1中的20个字节=刚好是五个int元素

}

        

 很明显是不会错误的,因此memcpy函数甚至适应程度高于strcpy函数(仅用于拷贝字符串)

那么重点来了,该如何模拟实现呢?------我们可以查一下他的源代码

注意:

1. 这里的void*--通用类型的指针,可以接收任何数据类型的地址,这下懂了吧,废话不多说,模拟实现

2.返回的是目标空间的起始地址

#include<stdio.h>
#include <corecrt_memory.h>
void* my_memcpy(void *dest,const void *str,size_t byte)
{
	void* ret = dest;
	while(byte--)
	{
		//将指针的地址的数据类型转换为char*类型再进行解引用,访问一个字节的替换
		*(char*)dest = *(char*)str;
		//右值可修改,左值不可修改,因此不可以使用(char*)dest = (char*)dest+1
		dest = (char*)dest + 1;
		str = (char*)str + 1;
	}
	return ret;




}

那如果任何数据类型的数组都可以进行拷贝,那么如果出现了自己拷贝自己呢?

此时如果自己拷贝自己,就会报错或者拷贝的值不一样,这是为什么呢?,其实是因为拷贝过程中两个数组之间有重叠部分,当重叠部分进行拷贝,可能会出现将自身str2自己更改了元素,因此我们使用另一种函数memmove

memmove函数

memmove函数的三个参数跟memcpy函数功能相同,不再赘述

这里语言会繁琐,因此使用图像进行分析

例如:我要拷贝数组str到dest中,就会出现从前->后拷贝和从后->前拷贝,两种情况不一样,如图所示:

 因此代码也要分为两种情况

void* my_memmove(void*dest, const void*str,size_t byte)
{
	//从前->后
	void* ret = dest;
	
		
		if (dest > str)
		{
			while (byte--)
			{
				*(char*)dest = *(char*)str;
				dest = (char*)dest + 1;
				str = (char*)str + 1;
			}
			
		}
		//从后->前
		else
		{
			while (byte--)
			{
				 *((char*)dest + byte) = *((char*)str + byte);
			}
			
		}
	
	return ret;


}
void test02()
{
	int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
	
	my_memmove(arr1,arr1+4,20);
	for (int i = 0; i < 10; i++)
	{
		printf("%d ", arr1[i]);
	}
}
int main()
{
	
	test02();
	return 0;
}

因此在C语言中,memcpy拷贝不重叠的内存,出现了重叠的就交给memmove函数

 memcmp函数

其实是strcmp函数的优化版,也是无论什么数据类型的数组或者字符串进行比较,都可以个需要比较,多少个字节内谁大,一般要考虑机器是大小端后才能进行比较,以小端为例

void test03()
{
	int arr1[] = {1,2,3,4,5};//01 00 00 00 02 00 00 00 03 00 00 00 04 00 00 00 05        00 00 00后面这俩部分都没进行比较
	int arr2[] = {1,2,3,4,6};//01 00 00 00 02 00 00 00 03 00 00 00 04 00 00 00 06        00 00 00后面这俩部分都没进行比较
	int ret = memcmp(arr1,arr2,17);
	printf("ret = %d\n",ret);//结果为-1,arr1<arr2

}

该函数模拟实现与strcmp函及其类似就不实现了

memset函数

这个函数用得很广,一定需要掌握

 

代码演示如下:

void test04()
{
	char arr[] = "hello world";
	memset(arr,'x',5);
	printf("%s",arr);//结果为xxxxx world
}

错误使用案例

void test05()
{
	int arr[10] = {0};
	//想将数组内的所有元素都变为1
	memset(arr,1,sizeof(arr));
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		printf("%d ",arr[i]); //结果为16843009 16843009 16843009 16843009 16843009 16843009 16843009 16843009 16843009 16843009
	}
}

这是为什么?原来是因为memset函数是对着每个字节都进行更改,二进制表达是101010 ,换算结果就为16843009,因此在初始化数组为0时不能用memset函数

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值