IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> 字符串+内存函数的介绍 -> 正文阅读

[C++知识库]字符串+内存函数的介绍

与字符有关的较复杂库函数:

前言:当我们只是简单的了解C语言,我们会认识和掌握strcpy,strcmp等简单的库函数,如果想更进一步,我们或许需要掌握更加复杂的库函数。本篇文章就介绍了strtok、strerror、字符判断函数、memcpy、memcmp以及memset函数。

1、strtok函数

在这里插入图片描述

在函数定义中的str是目标字符串的地址,sep是分隔符的地址。
在使用这个函数之前我们需要知道这个隐藏的使用规则。
strtok函数找到str中的下一个标记,并将其用 \0 结尾,返回一个指向这个标记的指针。(注:strtok函数会改变被操作的字符串,所以在使用strtok函数切分的字符串一般都是临时拷贝的内容并且可修改。)
strtok函数的第一个参数不为 NULL ,函数将找到str中第一个标记,strtok函数将保存它在字符串中的位置。
strtok函数的第一个参数为 NULL ,函数将在同一个字符串中被保存的位置开始,查找下一个标记。
如果字符串中不存在更多的标记,则返回 NULL 指针。
有以上规则我们可以敲一个例子:

int main()
{
	const char* p = "@.";
	char arr[] = "123456789@qq.com";
	char buf[50] = { 0 }; //123456789@qq.com
	strcpy(buf, arr);
	char* str = NULL;
	//1、已知字符串情况下
	str = strtok(arr, p);//123456789
	printf("%s\n", str);
	str = strtok(NULL, p);//qq
	printf("%s\n", str);
	str = strtok(NULL, p);//com
	printf("%s\n", str);
	//之后返回NULL

	//2、未知字符串情况
	for (str = strtok(buf, p); str != NULL; str = strtok(NULL, p))
	{
		printf("%s\n", str);
	}

	return 0;
}

注:当我们知道字符串的时候我们可以确定使用strtok的此时,当未知字符串我们可使用for循环来完美实现。(第二种方法可以包含第一种)
运行结果:
在这里插入图片描述

2、strerror函数

报错函数
我们先来实现报错:

#include <errno.h>
int main()
{
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		printf("%s\n", strerror(i));
	}
	return 0;
}

运行结果:
在这里插入图片描述
同时strerror函数有一个头文件与之对应—#include <errno.h>
然后我们再举一个现实的例子:

#include <errno.h>
int main()
{
	FILE* p =  fopen("test.txt", "r");
	//当库函数使用发生错误会把errno这个
	//全局的错误遍历设置为本次库函数产生的
	//错误码
	//errno是C语言提供的一个全局变量,可直接使用,头文件errno.h

	if (NULL == p)
	{
		printf("%s\n", strerror(errno));
		return 0;
	}
	//........
	//关闭文件
	fclose(p);
	p = NULL;
	return 0;
}

此时我的工程内并没有这个test.txt文件。我们当然读取不到,所以就会报错,我们可以用strerror这个函数来找到报错原因。
运行结果:
在这里插入图片描述

3、字符串分类函数

在这里插入图片描述
这个函数也有自己的头文件—#include <ctype.h>。
例子:

//字符判断函数
int main()
{
	printf("%d\n", isspace('!'));//0
	printf("%d\n", isspace(' '));//随机返回不是0的数
	//函数好处
	//旧方法判断
	char ch = '0';
	if (ch >= '0' && ch <= '9')
	{
		printf("1\n");
	}
	//优化
	if (isdigit(ch)) 
	{
		printf("2\n");
	}
	return 0;
}

在这里插入图片描述
还有例子:

//字符转换函数
int main()
{
	char ch = 0;
	ch = getchar();
	if (islower(ch))
	{
		ch = toupper(ch);
	}
	else
	{
		ch = tolower(ch);
	}
	printf("%c\n", ch);
	return 0;
}

在这里插入图片描述

4、memcpy

在这里插入图片描述
memcpy类似与strcpy,但是strcpy只能作用在字符串,而memcpy是利用内存而复制,所以可以作用于所有的数据类型。
他的函数定义:
分别是目标地址,源地址以及复制内容的字节大小。

void * memcpy ( void * destination, const void * source, size_t num );

例子:

//内存复制函数----memcpy(无关内容)
//strcpy是拷贝整个字符串内容(仅仅字符串)
int main()
{
	char arr1[] = "abcdef";
	char arr2[20] = { 0 };


	int arr3[] = { 1,2,3,4,5,6,7,8,9 };
	int arr4[5] = { 0 };
	memcpy(arr4, arr3, 5*sizeof(arr3[0]));//20是字节
	int i = 0;
	for (i = 0; i < 5; i++)
	{
		printf("%d\n", arr4[i]);
	}
	return 0;
}

运行结果:
在这里插入图片描述
因为原理比较明显,所以我们可以尝试进行memcpy的模拟实现。

//memcpy函数的模拟实现
void* my_memcpy(void* dest,const void* src, size_t num)
{
	void* ret = dest;
	assert(dest && src);
	while (num--)
	{
		*(char*)dest = *(char*)src;
		dest = (char*)dest + 1;
		src = (char*)src + 1;
	}
	return ret;
}
//内存复制函数----memcpy(无关内容)
//strcpy是拷贝整个字符串内容(仅仅字符串)
void* my_memcpy(void* dest, const void* src, size_t num);

int main()
{
	char arr1[] = "abcdef";
	char arr2[20] = { 0 };
	int arr3[] = { 1,2,3,4,5,6,7,8,9 };
	int arr4[5] = { 0 };
	my_memcpy(arr4, arr3, 5 * sizeof(arr3[0]));
	my_memcpy(arr2, arr1, 6*sizeof(arr1[0]));
	int i = 0;
	for (i = 0; i < 5; i++)
	{
		printf("%d ", arr4[i]);
		if (4 == i)
		{
			printf("\n");
		}
	}
	for (i = 0; i < 6; i++)
	{
		printf("%c ", arr2[i]);
	}
	return 0;
}

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

5、memmove

和memcpy的差别就是memmove函数处理的源内存块和目标内存块是可以重叠的。
如果源空间和目标空间出现重叠,就得使用memmove函数处理。

//定义和memcpy函数类似
void * memmove ( void * destination, const void * source, size_t num )

两者对比例子:

void test1()
{
	int arr3[] = { 1,2,3,4,5,6,7,8,9,10 };
	//my_memcpy(arr3 + 2, arr3, 5 * sizeof(arr3[0]));//内存有重叠
	memcpy(arr3 + 2, arr3, 5 * sizeof(arr3[0]));//memcpy经过了优化

	int arr4[] = { 1,2,3,4,5,6,7,8,9,10 };
	memmove(arr4 + 2, arr4, 5 * sizeof(arr3[0]));
	//my_memmove(arr3 + 2, arr3, 5 * sizeof(arr3[0]));
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		printf("%d ", arr3[i]);
		if (i == 9)
		{
			printf("\n");
		}
	}
	for (i = 0; i < 10; i++)
	{
		printf("%d ", arr4[i]);
	}
}
int main()
{
	test1();

	return 0;
}

运行结果;
在这里插入图片描述
我们看到两者一样,其实并不是因为两者没有差别,而是经过时间的流逝,在最新的vs里,memcpy的功能已经被优化了,达到了和memmove一样的效果,但是两者的实现方式还是有着根本性的不同的。

memmove的模拟实现:

void* my_memmove(void* dest,const void* src,size_t num)
{
	void* ret = dest;
	assert(dest && src);
	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;
}

我们要根据内存中数据向前移动还是向后移动的情况下进行相反方向的拷贝。
运行结果:
在这里插入图片描述

6、memcmp

函数定义:

int memcmp ( const void * ptr1, const void * ptr2, size_t num );
//memcmp----比较内存
int main()
{
	int arr1[] = { 1,2,3,4,5 };
	int arr2[] = { 1,2,3,4,5 };
	int ret = memcmp(arr1, arr2, 8);//8是字节大小
	printf("%d\n", ret);//相等返回0
	return 0;
}

运行结果:
在这里插入图片描述
其模拟实现可以参考:

int my_memcmp(const void *p1, const void *p2, size_t count)
{
    assert(p1);
    assert(p2);
    char *dest = (char *)p1;
    char *src = (char *)p2;
    while (count && *dest == *src)
    {
        count--;
        dest++;
        src++;
    }
    if (count == 0)
    {
        return 0;
    }    
    else
    {
         return *dest  - *src - ‘\0;
    }
       
}

7、memset

它的功能是将s所指向的某一块内存中的每个字节的内容全部设置为ch指定的ASCII值, 块的大小由第三个参数指定,这个函数通常为新申请的内存做初始化工作, 其返回值为指向S的指针。memset的作用是在一段内存块中填充某个给定的值,它是对较大的结构体或数组进行清零操作的一种最快方法。
函数定义:

void * memset ( void * ptr, int value, size_t num )

其中ptr是起始设置地址、value是要是设置的值、num是字节长度。

例子:

//memset---设置内存函数
int main()
{
	char arr[20] = { 0 };
	memset(arr, 'x', 10);
	int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };
	memset(arr1, 0, 20); 
	printf(arr);
	printf("\n");
	for (int i = 0; i < 10; i++)
	{
		printf("%d ", arr1[i]);
	}
	return 0;
}

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

void* my_memset(void* buf, int set, int sz)
{
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		*((char*)buf + i) = set;
	}
	return buf;
}
int main()
{
	char buf[5];
	int i = 0;
	my_memset(buf, 0, 5);
	for (i = 0; i < 5; i++)
	{
		printf("%s\n", buf[i]);
	}
	system("pause");
	return 0;
}

其中的set 是ASCII值

今天函数的介绍到此为止???

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-02-06 13:38:43  更:2022-02-06 13:39:42 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 8:27:07-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码