详解C语言string.h中常用的14个库函数(四)

这篇具有很好参考价值的文章主要介绍了详解C语言string.h中常用的14个库函数(四)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

本篇博客会讲解最后4个函数,分别是memset, memcpy, memmove, memcmp。这4个函数开头都是mem,即memory(内存)的缩写。

详解C语言string.h中常用的14个库函数(四)

memset

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

memset可以用来设置内存中的值。该函数可以把从ptr指向的空间开始,后面的num个字节设置成value的值。

举个简单的例子。假设有一个数组:

int arr[] = { 1,2,3,4,5 };

我们想把这个数组的前3个数都设置成0,就这么写:

memset(arr, 0, 3 * sizeof(int));

打开内存窗口观察一下,这是设置前:

详解C语言string.h中常用的14个库函数(四)

这是设置后:
详解C语言string.h中常用的14个库函数(四)
可以看到,成功把前3个数设置成了0。

memcpy

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

memcpy是用来拷贝内存中的数据的。拷贝的起始位置由第2个参数决定,目标位置由第1个参数决定,注意:目标在前,源头在后,后面的memmove同理。总共拷贝多少个字节的数据,由第3个参数决定。函数会返回目标空间的起始地址。

比如,假设有2个数组:

int arr1[5] = { 1,2,3,4,5 };
int arr2[5] = { 0 };

如果我想把arr1的数据都拷贝到arr2中,就应该这么写:

memcpy(arr2, arr1, sizeof(arr1));

拷贝完后,把arr2中的数据打印出来,就可以看到拷贝成功了。
详解C语言string.h中常用的14个库函数(四)
这个函数和接下来会讲解的memmove函数都是非常重要的,所以我模拟实现一下。模拟实现的思路很简单,每次从源头拷贝到目的地,拷贝num次即可。

void* my_memcpy(void* dst, const void* src, size_t num)
{
	assert(dst && src);
	void* ret = dst;

	while (num--)
	{
		*(char*)dst = *(char*)src;
		dst = (char*)dst + 1;
		src = (char*)src + 1;
	}

	return ret;
}

根据以上的实现,我们可以发现,使用memcpy进行内存拷贝时,源头和目的地的空间是不能重叠的。加入重叠了,比如:

int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
my_memcpy(arr + 2, arr, 5 * sizeof(int));

以上程序中,数组arr的内存分布是(左边是低地址):[1 2 3 4 5 6 7 8 9 10]。我们把[1 2 3 4 5]拷贝到了[3 4 5 6 7]所在的位置。预期的结果是:[1 2 1 2 3 4 5 6 7 8 9 10]。假设把拷贝后的arr数组打印出来,结果如下:
详解C语言string.h中常用的14个库函数(四)
可以看到并不符合预期。原因是,由于源头和目的地有重叠,在拷贝左边的数据时,其实已经把源头给覆盖了。

事实上,如果使用库里的memcpy来拷贝,源头和目的地有重叠时,结果是标准未定义的。此时不能使用memcpy,而应使用memmove。

memmove

oid * memmove ( void * destination, const void * source, size_t num );

memmove和memcpy的使用方式完全相同。唯一的区别是,使用memmove来拷贝时,源头和目的地是可以重叠的。

这里我们来模拟实现一下这个函数。假设源头和目的地没有重叠,前面memcpy的实现是没有任何问题的,但是一旦有重叠时,需要分类讨论。

  1. src<dst,此时源头在目的地的左边,应该先拷贝右边的数据,再拷贝左边的数据。
  2. dst<src,此时源头在目的地的右边,应该先拷贝左边的数据,再拷贝右边的数据。

以第1点为例,第2点同理。假设有一个数组,内存分布(左边是低地址)是:[1 2 3 4 5 6 7 8 9 10]。假设想把[1 2 3 4 5]所在位置的数据拷贝到[3 4 5 6 7]所在的位置,假设先拷贝左边的数据,再拷贝右边的数据。一上来先把1拷贝到3所在的位置,得:[1 2 1 4 5 6 7 8 9 10],再拷贝2:[1 2 1 2 5 6 7 8 9 10],此时我们应该拷贝3,但是3呢?不见了,已经被覆盖了。所以在这种情况下,先拷贝左边的数据是不对的,应该先拷贝右边的数据。

分类讨论后,实现如下:

void* my_memmove(void* dst, const void* src, size_t num)
{
	assert(dst && src);
	void* ret = dst;

	if (dst < src)
	{
		// 左->右
		while (num--)
		{
			*(char*)dst = *(char*)src;
			dst = (char*)dst + 1;
			src = (char*)src + 1;
		}
	}
	else
	{
		// 右->左
		while (num--)
		{
			*((char*)dst + num) = *((char*)src + num);
		}
	}

	return ret;
}

此时再运行:

int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
my_memmove(arr + 2, arr, 5 * sizeof(int));

把arr打印出来,如下:
详解C语言string.h中常用的14个库函数(四)
而如果是这样:

int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
my_memmove(arr, arr + 2, 5 * sizeof(int));

数组arr打印出来的结果如下:
详解C语言string.h中常用的14个库函数(四)

memcmp

int memcmp ( const void * ptr1, const void * ptr2, size_t num );

memcmp是用来比较内存中的值的,它会一个字节一个字节向后比较,直到遇到某一对数据比较出大小,或者所有num个字节的数据都相等。

返回值和strcmp类似,如果左边>右边返回正数,左边<右边返回负数,左边==右边返回0。

比如,在小端机器下,运行以下程序:

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

int main()
{
	int arr1[] = { 1,2,3,4,5 };
	int arr2[] = { 1,2,3,4,6 };
	int ret = memcmp(arr1, arr2, 4 * sizeof(int) + 1);
	if (ret > 0)
	{
		printf(">\n");
	}
	else if (ret < 0)
	{
		printf("<\n");
	}
	else
	{
		printf("==\n");
	}

	return 0;
}

得到的结果是“小于”。因为arr1的内存分布是(左边是低地址,字节和字节之间用空格分隔):[01 00 00 00 02 00 00 00 03 00 00 00 04 00 00 00 05 00 00 00],arr2的内存分布是:[01 00 00 00 02 00 00 00 03 00 00 00 04 00 00 00 06 00 00 00],一直比较,直到05<06,得到“小于”。如果把memcmp的第3个参数改成4*sizeof(int),结果将是“等于”。

总结

  1. 本篇博客主要讲解了4个内存操作函数。
  2. memset是用来设置内存中的值的。
  3. memcpy和memmove都可以用来拷贝内存中的值,如果源头和目的地空间有重叠,则必须用memmove。
  4. memcmp是用来比较内存中的值的大小的,返回值和strcmp类似,但是memcmp是比较出大小或者比较完num个字节就结束,而strcmp是比较出大小或者比较到\0就结束。

感谢大家的阅读!文章来源地址https://www.toymoban.com/news/detail-423165.html

到了这里,关于详解C语言string.h中常用的14个库函数(四)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • C语言标准库(常用函数)详解(含示例)数学公式:math.h

    目录 math.h的介绍 math.h的概述 库中定义的宏: HUGE_VAL 库函数(只讲解常用函数) 三角函数 示例代码 输出 双曲函数 示例代码 输出 指数和对数函数(只含常用函数) 示例代码  输出 常用函数pow,sprt,cbrt,hypot,fabs,abs 代码示例 输出 math.h 一般见于C,C++程序设计, #includema

    2024年02月09日
    浏览(38)
  • golang strings 常用函数

    官网 https://pkg.go.dev/strings 这里介绍最常用的函数 1、Fields 以空格为字段分割符,返回[]string 2、Contains 是否包含子串,返回bool 3、Split ,以子串分割,返回[]string 4、ReplaceAll 替换 5、其他 -------------end

    2024年02月13日
    浏览(35)
  • c语言进阶部分详解(详细解析字符串常用函数,并进行模拟实现(下))

    上篇文章介绍了一些常用的字符串函数,大家可以跳转过去浏览一下:c语言进阶部分详解(详细解析字符串常用函数,并进行模拟实现(上))_总之就是非常唔姆的博客-CSDN博客 今天接着来介绍一些:  目录 一.字符串查找 1.strstr() 1.1示例 1.2注意事项: 1.3模拟实现  2.

    2024年02月07日
    浏览(45)
  • C++中string类的常用函数

    引言:在C语言中对于字符串的一些操作,例如在字符串末尾增加字符,对字符串拷贝等,我们可以通过调用库中函数来完成这些操作,在C++中,我们把这些常规操作封装成了string类,可以通过类对象直接调用这些函数,使得更加符合了面向对象的思想。 作用:返回字符串的有效字符长度

    2024年02月08日
    浏览(40)
  • c++系列之string类的常用接口函数

    💗 💗 博客:小怡同学 💗 💗 个人简介:编程小萌新 💗 💗 如果博客对大家有用的话,请点赞关注再收藏 🌞 string时表示字符串的字符类 //使用 string类包含#include 头文件 以及 using namespace std string容量相关接口 (size(),capacity(),clear(),empty) 1.size()是元素个数 //. size()与length()方

    2024年02月10日
    浏览(35)
  • Unity中常用到的基础函数

    Awake() :当前控制脚本实例被装载的时候调用,常用于初始化; start() :当前控制脚本第一次执行 Update() 前调用; Update() :每帧执行一次; FixedUpdate() :每固定帧绘制时执行一次,和 Update() 的不同之处在于 FixedUpdate() 是渲染帧执行,如果渲染效率低下的时候,FixedUpdate() 的调

    2023年04月14日
    浏览(39)
  • C语言库函数——string.h

    目录 摘要: 一、头文件 string.h 中定义的函数 strcpy 用法: 代码示例: 参数: memchr 用法: 代码示例: 参数: strlen 用法: 代码示例: strcat 用法: 代码示例: 参数: strcmp 用法: 代码示例: 参数: memcmp 用法: 代码示例: 参数: strcpy  在学习C语言的过程中,当使用字符

    2024年02月02日
    浏览(34)
  • 【C++入门】string类常用方法(万字详解)

    1.STL简介 1.1什么是STL STL(standard template libaray-标准模板库):是C++标准库的重要组成部分,不仅是一个可复用的组件库,而且是一个包罗数据结构与算法的软件框架 。 1.2STL的版本 原始版本 Alexander Stepanov、Meng Lee 在惠普实验室完成的原始版本,本着开源精神,他们声明允许任何

    2024年02月10日
    浏览(36)
  • 【C++】STL——string的模拟实现、常用构造函数、迭代器、运算符重载、扩容函数、增删查改

    string使用文章   这里我们 实现常用的第四个string(const char* s)和析构函数     拷贝构造函数实现:   在堆上使用new为当前对象的成员变量_str分配内存空间,大小为s._capacity + 1字节,即字符串的容量加上一个结束符\\0的空间。   我们使用深拷贝而不是浅拷贝,

    2024年02月15日
    浏览(50)
  • 复习第七课 C语言-指针数组,函数,string

    目录 【1】指针和数组 【2】数组指针 【3】指针数组 【4】函数 【5】函数传参 【6】动态开辟堆区空间 【7】string函数族 【8】递归函数 练习: 直接访问:通过数组名访问 间接访问:通过指针访问 》1. 一维数组 运算方法: 1) *和++都是弹幕运算符,优先级相同 2) 单目运算

    2024年02月16日
    浏览(42)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包