Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >C语言strcpy(),memcpy(),memmove() | 数组赋值给数组

C语言strcpy(),memcpy(),memmove() | 数组赋值给数组

作者头像
CtrlX
发布于 2023-03-21 03:48:23
发布于 2023-03-21 03:48:23
3.9K01
代码可运行
举报
文章被收录于专栏:C++核心编程C++核心编程
运行总次数:1
代码可运行

一个数组赋值给另一个数组的方法

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
int arr1[5] = {1, 2, 3, 4, 5};
int arr2[5];
arr2 = arr1;  // 错误,不能直接赋值

方法一

使用循环遍历数组中的每一个元素

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
int arr1[5] = {1, 2, 3, 4, 5};
int arr2[5];
for (int i = 0; i < 5; i++) {
  arr2[i] = arr1[i];
}

使用std::array时,可以使用赋值运算符来复制:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
std::array<int, 5> arr1 = {1, 2, 3, 4, 5};
std::array<int, 5> arr2;
arr2 = arr1;

方法二

使用C语言库函数解决

1.使用strcpy()和strncpy()函数处理字符串数组

strcpy()函数用于复制一个字符串到另一个字符串。该函数的语法如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
char *strcpy(char *dest, const char *src);

它从源字符串src复制字符到目标字符串dest,包括NULL字符(即字符串结束标志)。

strncpy()函数与strcpy()类似,但是其复制的字符数可以限制。该函数的语法如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
char *strncpy(char *dest, const char *src, size_t n);

它从源字符串src复制字符到目标字符串dest,但是最多复制n个字符。

举个例子:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include <iostream>
#include <cstring>

int main()
{
    char source[] = "Hello, World!";
    char destination[50];

    // using strcpy
    strcpy(destination, source);
    std::cout << "After using strcpy: " << destination << std::endl;

    // using strncpy
    strncpy(destination, source, 5);
    destination[5] = '\0';
    std::cout << "After using strncpy: " << destination << std::endl;

    return 0;
}

输出:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
After using strcpy: Hello, World!
After using strncpy: Hello

PS:详见C Primer Plus P351

2.使用string.h库中memcpy()和memmove()函数处理任意类型的数组

memcpy() 和 memmove() 是 string.h 库中的两个常用的内存复制函数。这两个函数可以用来处理任意类型的数组,并复制从源数组到目标数组。

memcpy() 函数把一块内存复制到另一块内存,但是不会去处理内存是否重叠。它可以被用来处理整个数组或仅仅一部分。它的语法如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
void *memcpy(void *dest, const void *src, size_t n);

memmove() 函数的作用与 memcpy() 类似,可以处理内存重叠的情况。它的语法如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
void *memmove(void *dest, const void *src, size_t n);

如果你想复制一个整数数组,例如:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
int source[5] = {1, 2, 3, 4, 5};
int target[5];

memcpy(target, source, sizeof(source));

这两个函数是 C 语言中非常有用的内存复制函数,可以用来处理任意类型的数组,也可以用来处理字符数组。

PS:详见C Primer Plus P558

c和c++使用的内存拷贝函数,memcpy函数和memmove函数的功能都是从源src所指的内存地址的起始位置开始拷贝n个字节到目标dest所指的内存地址的起始位置中。

要使用这两个库函数需要引用头文件 <string.h> 函数原型: void* memcpy(void* destination,const void* source,size_t num); voidmemmove(void destination,const void* source,size_t num); destination:目的地指针(首地址) source:源头指针(首地址) num:需要复制的字节数

memcpy和memmove都是C语言标准库函数,用于内存拷贝。两者的主要区别在于:

  • memcpy是直接在内存中复制数据,不会考虑内存重叠的情况。如果源区域和目标区域有重叠的部分,可能会出现未定义的行为。
  • memmove是在内存中复制数据,考虑内存重叠的情况。如果源区域和目标区域有重叠的部分,会先把数据复制到临时空间,再从临时空间复制到目标区域,保证数据不会被覆盖。

因为memcpy的运行速度比memmove快,所以memcpy常常被用于内存拷贝。在程序员能确保源区域和目标区域没有重叠或者能够接受重叠部分数据被覆盖的情况下memcpy是很好的选择。但是在不能确定源区域和目标区域是否重叠或者不能接受重叠部分数据被覆盖的情况下,应该使用memmove以保证数据完整性

举个例子,假设我们有一个字符数组char arr[10],我们想把arr[2]arr[5]这4个字符移动到arr[6]arr[9]这4个位置上。 如果使用memcpy(arr+6, arr+2, 4),结果就会是这样的:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
原数组: | A | B | C | D | E | F | G | H | I | J |
拷贝后: | A | B | C | D | E | C | D | E | C | J |

可以发现,原本arr[6]~arr[9]的数据被覆盖了。 如果使用memmove(arr+6, arr+2, 4),结果就会是这样的:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
原数组: | A | B | C | D | E | F | G | H | I | J |
拷贝后: | A | B | C | D | E | C | D | E | F | J |

可以发现,原本arr[6]~arr[9]的数据没有被覆盖,源区域的数据也没有丢失。 在这个例子中,memmove 保证了数据完整性,而memcpy没有。 简而言之,memcpy是一个快速的内存拷贝函数,memmove是一个安全的内存拷贝函数,当你不能确保源区域和目标区域是否重叠或者不能接受重叠部分数据被覆盖的情况下,应该使用memmove来保证数据完整性。

借一下图:https://blog.csdn.net/m0_66363962/article/details/126903690

通过上图的变化路程可知:memcpy总是从低地址开始往高地址复制的,但是当dest>src,并且目的地与源头有重叠时,使用memcpy会覆盖掉源头后面的数据,导致结果出错。这个时候就需要进行判断,如果再次出现上面的事件,我们应当从高地址往低地址开始复制但是memcpy函数在设计时没有这种判断。所以使用memmove函数解决。

memcpy从高地址往低地址复制不会受内存重叠时的问题的影响。 从低地址往高地址复制时需要使用memmove函数。

memcpy比循环赋值快,原因如下:

1.在 C 语言中,使用 memcpy 函数进行内存复制通常比使用循环赋值更快。这是因为 memcpy 是一个底层的函数,它可以直接操作内存,而不需要进行额外的运算。它使用缓存和高级的内存管理技术来提高性能。

2.另外,memcpy 函数可以并行执行,因此多核处理器上能够更高效地运行,而循环赋值串行执行的,所以性能更差。

下面是一个使用 memcpy 函数进行内存复制的示例代码:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include <string.h>

int main() {
    int arr1[5] = {1, 2, 3, 4, 5};
    int arr2[5];
    memcpy(arr2, arr1, sizeof(arr1));
    // arr2 is now {1, 2, 3, 4, 5}
    return 0;
}
 

请注意,当源和目标内存块有重叠时,memcpy 函数可能会出现不确定的行为,因此在这种情况下应该使用 memmove 函数代替。

PS:并行执行是指多个任务在同时进行,也就是多个任务同时执行。串行执行是指一个任务执行完成后再执行下一个任务,也就是一个任务一个任务地执行。

memcpy 函数是如何实现并行执行的?

memcpy 函数通常是通过硬件加速来实现并行执行的。例如,许多现代处理器都具有内置的存储器控制器,可以并行地从一个地址拷贝数据到另一个地址。这些控制器可以利用多个通道和多个缓存来并行执行数据拷贝操作,从而大大提高了数据拷贝的速度。

memcpy本身不支持多核并行,它是由系统底层实现的,通常使用的是硬件级的指令来提高复制效率。

关于memcpy并行,通常指的是在单核内部使用SIMD(单指令多数据)指令来并行执行复制操作。SIMD指令可以在一个时钟周期内处理多个数据。例如,128位的AVX指令可以同时处理8个32位整数或4个64位整数。这样可以减少数据处理时间,提高复制效率。

所以memcpy并行指的是在单核内部使用SIMD指令来并行执行复制操作。

memcpy 函数也可以使用多线程和多核处理器来实现并行执行。 例如,如果将数据分成若干块,每个线程分别处理一块数据,这样就可以并行执行数据拷贝操作。

如果要在多核并行的情况下使用memcpy,可以使用多线程或多进程的方式,将大块数据分割成多个小块,分别在不同的核上进行复制。这样可以利用多核的计算能力来提高复制效率。

具体实现的方式可以使用pthread库或OpenMP来实现多线程,或者使用MPI来实现多进程。其中使用OpenMP是目前并行计算中比较流行的方式。

但是这种方式需要更多的编程工作量和空间复杂度,而且对于小块数据来说反而会增加开销,所以通常在复制大块数据的场景下使用。

总之,memcpy函数实现并行执行的方式有很多,具体实现取决于具体环境。

关于线程亲和度

线程可以设置亲和度,这样可以指定它运行在哪个 CPU 核上。这样做的目的是为了提高性能,因为在同一个 CPU 核上运行的线程可以共享缓存和其他硬件资源,而在不同核上运行则不能。不过,这需要程序员手动设置,并且需要操作系统的支持。

在不同的操作系统和编程语言中,设置线程亲和度的方式可能有所不同。下面给出一些常见的例子:

  • Linux: 可以使用 sched_setaffinity() 函数来设置线程的亲和度。
  • Windows: 可以使用 SetThreadAffinityMask() 函数来设置线程的亲和度。
  • Java: 可以使用 Thread.setAffinity() 方法来设置线程的亲和度。
  • C++11: 可以使用 std::thread::set_affinity() 方法来设置线程的亲和度。

在设置亲和度之前,需要先确定系统中可用的 CPU 核数量,并将线程亲和度设置为对应的核的标识。一般来说,亲和度是一个位图,每个位对应一个 CPU 核。

需要注意的是, 设置线程亲和度可能会导致系统性能变差,因为这需要额外的上下文切换.

PS:上下文切换是指 CPU 从一个线程切换到另一个线程时所需要进行的操作。在切换过程中,需要保存当前线程的环境(如寄存器的值),并将新线程的环境加载到 CPU 中。这个过程会消耗一定的时间,如果频繁发生,会导致系统性能下降。

在设置线程亲和度时,如果线程频繁地在不同的 CPU 核之间切换,就会导致上下文切换频繁发生,从而导致系统性能变差。因此,在设置线程亲和度时,需要谨慎考虑,确保它对系统性能的影响是最小的。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022-10-03,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
内存函数​(memcpy、memmove、memset、memcmp)
当ptr1<ptr2时,返回值<0 当ptr1=ptr2时,返回值=0 当ptr1>ptr2时,返回值>0
走在努力路上的自己
2024/01/26
9820
内存函数​(memcpy、memmove、memset、memcmp)
memcpy的使⽤和模拟实现
•函数memcpy从source的位置开始向后复制num个字节的数据到destination指向的内存位置。
ljw695
2024/10/18
1410
C语言库函数 memcpy 和 memmove 的区别
memcpy和memmove都是 C 语言的库函数,相比于 strcpy和 strncpy只能针对于字符类型的数组(),这两个函数可以拷贝其他类型的数组,对于 memcpy和 memmove的区别是什么呢?这里,在 Linux 里通过 man命令查看两个函数的区别,查询的结果如下所示,首先是 memcpy函数的阐述。
wenzid
2021/08/13
3.5K0
C语言库函数 memcpy 和 memmove 的区别
内存函数memcpy和memmove详解及模拟实现
                     大家好,我学习完memmove函数后做了如下一些总结,和大家一起探讨交流,如有错误和遗漏欢迎大家在评论区指出。
咬咬
2024/06/12
1630
内存函数memcpy和memmove详解及模拟实现
字符串与内存函数的介绍+模拟实现
C语言中对字符和字符串的处理很是繁琐,但是C语言本身是没有字符串类型的字符串通常存放在常量字符串或者字符数组中。 字符串常量适用于那些对它不做修改的字符串函数。
Yui_
2024/10/16
880
字符串与内存函数的介绍+模拟实现
【C】内存操作函数
注: 因为是void类型,所以不管什么类型都可以进行拷贝,这里可以与前面所学的strncpy函数进行比较学习,具体内容见【C】字符函数和字符串函数(上) size_t num指的是拷贝的内容的大小。
阿伟@t
2023/10/10
1900
【C】内存操作函数
C语言内存函数精讲
在C语言编程中,内存管理是核心技能之一。C语言提供了一系列内存操作函数,这些函数在动态内存分配、数据拷贝和比较等方面发挥着重要作用。本文将详细介绍这些内存函数的用法和注意事项。
平凡之路.
2024/10/09
1280
C语言内存函数精讲
C语言学习系列-->一篇带你看懂内存函数
#include <stdio.h> #include <string.h> #include<assert.h>
南桥
2024/01/26
1190
C语言学习系列-->一篇带你看懂内存函数
内存函数(C语言)
通过函数原型也发现,这个memcpy函数是一个函数参数,函数返回类型都是void无符号类型,这是说明该函数是一个,泛型函数,它可以接收任意类型的参数,使同一个函数能用于多种类型的数据。
技匠晓晨
2024/11/26
610
内存函数(C语言)
C语言_字符串和内存函数
描述: strncmp() 是一个标准库函数,用于比较两个字符串的前 n 个字符是否相等。 strncmp() 函数通常用于比较两个字符串,以确定它们是否相等或哪个字符串在字典顺序上更小。
用户10782096
2023/10/26
2600
C语言_字符串和内存函数
【C语言】字符串函数、字符函数和内存操作函数
注意:(1)strlen函数返回的是在字符串中 ‘\0’ 前面出现的字符个数(不包 含 ‘\0’)
YoungMLet
2024/03/01
1480
C语言(内存函数)
memcpy 前面的 mem 指的是 memmory ,英文单词“记忆”,在C语言中指的是内存。后面要介绍的 memmove、memset 和 memcmp 都是如此。
_小羊_
2024/10/16
910
C语言(内存函数)
【C】剖析C语言内存函数
字符串函数针对的是一个个的字符,而内存函数顾名思义关注的是内存,存储在内存中的一个个字节。
用户11316056
2024/10/16
850
【C】剖析C语言内存函数
C:内存函数
上篇文章介绍了C语言字符串函数,我们学会了一些对字符串的操作,比如说将字符串从一个字符数组拷贝到另一个字符数组中,我们可以通过使用strcpy函数实现。但是,如果我们想要拷贝一个整型数组到另一个整型数组中时,strcpy函数就失效了,那我们应该怎么才能实现这个操作呢?不要着急,本篇文章将带大家搞定这个问题。
LonlyMay
2024/10/21
650
C:内存函数
C语言进阶——字符串&&内存函数
  这是牛客网上的一道简单题:判断输入字符是否为字母,一般的解决方法是通过ASCII码判断,不过这样做的话判断表达式较长,此时我们可以利用C语言中的库函数isalpha(判断是否为字母) 来完成这个题目,不仅代码量少,而且通俗易懂。要实现这种效果,就需要学习C语言中的各种库函数,而本文会列出大多数字符串函数和内存函数的使用及其实现,如果你想学习C语言库函数或对字符串、内存有好奇之心,不妨仔细来看看吧!🎉🎉🎉
北 海
2023/07/01
5110
C语言进阶——字符串&&内存函数
string头文件中常用函数
strlen是一个库函数所包含的头文件为#include<string.h>,这里我们可以在C plusplus上找到strlen所包含的头文件以及strlen传入后函数所生成的一个参数
如烟花般绚烂却又稍纵即逝
2024/11/26
1430
string头文件中常用函数
【C进阶】——内存操作函数memcpy、memmove、memcmp、memset详解及其模拟实现
看它们的前两个参数及返回类型,唯一的区别就是一个是char* ,而一个是void*。 因为strcpy是char *,所以strcpy只能拷贝字符类型的数据。 而memcpy是void *,我们知道void *可以接收任何类型变量的地址,因此,对于memcpy,不管内存块种放的是什么类型的数据,使用memcpy都可以拷贝(将source指向空间的内容拷贝到destination指向的空间中去),参数size_t num 则用来指定想要拷贝的数据的字节个数。
YIN_尹
2024/01/23
6020
【C进阶】——内存操作函数memcpy、memmove、memcmp、memset详解及其模拟实现
字符串函数&&内存函数(从零到一)【C语言】
 strlen函数是库函数中我们最常使用的函数,它可以求出字符串的长度(不包含‘\0’)
see.
2024/06/04
940
字符串函数&&内存函数(从零到一)【C语言】
C语言——K/C语言内存函数
• 函数 memcpy 从 source 的位置开始向后复制num个字节的数据到destination指向的内存位置。 • 这个函数在遇到 '\0' 的时候并不会停下来。 • 如果 source 和 destination 有任何的重叠,复制的结果都是未定义的。
用户11015888
2024/03/11
1230
C语言——K/C语言内存函数
C语言(进阶)—字符函数和字符串函数
1.size_t len1 = strlen("abcdef"); size_t len2 = strlen(str);两者是一样的
小李很执着
2024/06/15
970
C语言(进阶)—字符函数和字符串函数
相关推荐
内存函数​(memcpy、memmove、memset、memcmp)
更多 >
领券
💥开发者 MCP广场重磅上线!
精选全网热门MCP server,让你的AI更好用 🚀
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验