C的memset,memcpy,strcpy 的区别 及memset memcpy memmove源码
extern void *memcpy(void *dest,void *src,unsigned int count);
#include <string.h>
功能:由src所指内存区域复制count个字符串到dest所指内存区域.
说明:src和dest所指内存区域不能重叠,函数返回指向dest的指针.
memset
extern void *memset(void *buffer,int c,int count);
#include <string.h>
功能:把buffer所指内存区域的前count个字节设置成字符c
说明:返回指向buffer的指针.
二.区别
memset 用来对一段内存空间全部设置为某个字符,一般用于在对定义的字符串初始化为' '或者'\0';
例: char a[100];
memset(a,'\0',sizeof(a));
memcpy 是用来做内存拷贝,可以用来拷贝任何数据类型的对象,可以指定拷贝的数据长度;
例:
char a[100],b[50];
memcpy(b,a,sizeof(b)); //注意:如果使用sizeof(a),会造成内存溢出
mem是一段内存,他的长度,必须自己记住.memcpy是见着什么拷贝什么。
strcpy 就只能拷贝字符串,它遇到'\0'就结束拷贝;
例:char a[100],b[50];
strcpy(a,b);
如用strcpy(b,a)要注意a中的字符串长度(第一个'\0'之前) 是否超过50,如果超过,则会造成b的
内存溢出.它是不会拷贝'\0'的,所以一般还有加一个语句:
*a='\0';
三.使用技巧
memset 可以方便的清空一个数据结构的变量或数组.
如:
struct sample_struct
{
char csName[16];
int iSeq;
int iType;
};
对于变量
struct sample_struct stTest;
一般情况下,初始化stTest的方法:
stTest.csName[0]='\0';
stTest.iSeq=0;
stTest.iType=0;
而用memset:
memset(&stTest,0,sizeof(struct sample_struct));
如果是数组:
struct sample_struct TEST[100];
memset(TEST,0,sizeof(struct sample_struct)*100);
strcpy的原型为
char *strcpy(char *dest, const char *src)
而memcpy是给定来源和目标后,拷贝指定大小n的内存数据,而不管拷贝的内容是什么(不仅限于字符)
memcpy的原型为
void *memcpy(void *dest, const void *src, size_t n);
memcpy源码:
/***
*memcpy.c - contains memcpy routine *Purpose:
* memcpy() copies a source memory buffer to a destination buffer.
* Overlapping buffers are not treated specially, so propogation may occur.
*
**********/ #include <cruntime.h>
#include <string.h> #pragma function(memcpy) /***
*memcpy - Copy source buffer to destination buffer
*
*Purpose:
* memcpy() copies a source memory buffer to a destination memory buffer.
* This routine does NOT recognize overlapping buffers, and thus can lead
* to propogation.
*
* For cases where propogation must be avoided, memmove() must be used.
*
*Entry:
* void *dst = pointer to destination buffer
* const void *src = pointer to source buffer
* size_t count = number of bytes to copy
*
*Exit:
* Returns a pointer to the destination buffer
*
*Exceptions:
*******************************************************************************/ void * __cdecl memcpy (
void * dst,
const void * src,
size_t count
)
{
void * ret = dst; #if defined (_M_IA64) { __declspec(dllimport) void RtlCopyMemory( void *, const void *, size_t count ); RtlCopyMemory( dst, src, count ); } #else /* defined (_M_IA64) */
/*
* copy from lower addresses to higher addresses
*/
while (count--) {
*(char *)dst = *(char *)src;
dst = (char *)dst + 1;
src = (char *)src + 1;
}
#endif /* defined (_M_IA64) */ return(ret);
}
实现很简单,count一直减,把src值赋给dest,唯一值得注意的是函数原型。
void * __cdecl memcpy (
void * dst,
const void * src,
size_t count
) 可以看到参数为void 类型的指针,也返回一个void *指针。
我们可以利用void *类型指针为任何类型实现copy,如结构体:
struct A{
int x;
int y;
};
A *a=new A();
A *b=new A();
a->x=;
a->y=; memcpy(b,a,sizeof(A));
printf("%d%d\n",b->x,b->y);
输出53。
memset源码:
/***
*char *memset(dst, val, count) - sets "count" bytes at "dst" to "val"
*
*Purpose:
* Sets the first "count" bytes of the memory starting
* at "dst" to the character value "val".
*
*Entry:
* void *dst - pointer to memory to fill with val
* int val - value to put in dst bytes
* size_t count - number of bytes of dst to fill
*
*Exit:
* returns dst, with filled bytes
*
*Exceptions:
*
*******************************************************************************/ void * __cdecl memset (
void *dst,
int val,
size_t count
)
{
void *start = dst; #if defined (_M_IA64) || defined (_M_AMD64) { __declspec(dllimport) void RtlFillMemory( void *, size_t count, char ); RtlFillMemory( dst, count, (char)val ); } #else /* defined (_M_IA64) || defined (_M_AMD64) */
while (count--) {
*(char *)dst = (char)val;
dst = (char *)dst + ;
}
#endif /* defined (_M_IA64) || defined (_M_AMD64) */ return(start);
}
1.memmove
函数原型:void *memmove(void *dest, const void *source, size_t count)
返回值说明:返回指向dest的void *指针
参数说明:dest,source分别为目标串和源串的首地址。count为要移动的字符的个数
函数说明:memmove用于从source拷贝count个字符到dest,如果目标区域和源区域有重叠的话,memmove能够保证源串在被覆盖之前将重叠区域的字节拷贝到目标区域中。
2.memcpy
函数原型:void *memcpy(void *dest, const void *source, size_t count);
返回值说明:返回指向dest的void *指针
函数说明:memcpy功能和memmove相同,但是memcpy中dest和source中的区域不能重叠,否则会出现未知结果。
3.两者区别
函数memcpy() 从source 指向的区域向dest指向的区域复制count个字符,如果两数组重叠,不定义该函数的行为。
而memmove(),如果两函数重叠,赋值仍正确进行。
memcpy函数假设要复制的内存区域不存在重叠,如果你能确保你进行复制操作的的内存区域没有任何重叠,可以直接用memcpy;
如果你不能保证是否有重叠,为了确保复制的正确性,你必须用memmove。
memcpy的效率会比memmove高一些,如果还不明白的话可以看一些两者的实现:

void *memmove(void *dest, const void *source, size_t count)
{
assert((NULL != dest) && (NULL != source));
char *tmp_source, *tmp_dest;
tmp_source = (char *)source;
tmp_dest = (char *)dest;
if((dest + count<source) || (source + count) <dest))
{// 如果没有重叠区域
while(count--)
*tmp_dest++ = *tmp_source++;
}
else
{ //如果有重叠
tmp_source += count - 1;
tmp_dest += count - 1;
while(count--)
*--tmp_dest = *--tmp;
}
return dest;
}

void *memcpy(void *dest, const void *source, size_t count)
{
assert((NULL != dest) && (NULL != source));
char *tmp_dest = (char *)dest;
char *tmp_source = (char *)source;
while(count --)//不对是否存在重叠区域进行判断
*tmp_dest ++ = *tmp_source ++;
return dest;
}
memmove普通实现
memmove - Copy source buffer to destination buffer
;
;Purpose:
; memmove() copies a source memory buffer to a destination memory buffer.
; This routine recognize overlapping buffers to avoid propogation.
; For cases where propogation is not a problem, memcpy() can be used.
;
; Algorithm:
void* memmove(void* dest, void* source, size_t count)
{
void* ret = dest;
if (dest <= source || dest >= (source + count))
{
//Non-Overlapping Buffers
//copy from lower addresses to higher addresses
while (count --)
*dest++ = *source++;
}
else
{
//Overlapping Buffers
//copy from higher addresses to lower addresses
dest += count - 1;
source += count - 1;
while (count--)
*dest-- = *source--;l
}
return ret;
}
另一种实现:
void* mymemcpy( void* dest, const void* src, size_t count )
{
char* d = (char*)dest;
const char* s = (const char*)src;
// int n = (count + 7) / 8; // count > 0 assumed
int n = count >> 3;
switch( count & 7 )
{
do { *d++ = *s++;
case 7: *d++ = *s++;
case 6: *d++ = *s++;
case 5: *d++ = *s++;
case 4: *d++ = *s++;
case 3: *d++ = *s++;
case 2: *d++ = *s++;
case 1: *d++ = *s++;
case 0 } //while (--n > 0);
while (n-- > 0)
}
return dest;
}
C的memset,memcpy,strcpy 的区别 及memset memcpy memmove源码的更多相关文章
- gcc和g++的区别【转自中国源码网】
gcc和g++的区别[转自中国源码网] gcc和g++都是GNU(组织)的一个编译器. 误区一:gcc只能编译c代码,g++只能编译c++代码两者都可以,但是请注意:1.后缀为.c的,gcc把它当作是 ...
- python_way day10 python和其他语言的作用域 、 python2.7多继承和3.5多继承的区别 、 socket 和 socketserver源码(支持并发处理socket,多进程,多线程)
python_way day10 1.python的作用域和其他语言的作用域 2.python2.7多继承和3.5多继承的区别 3.socket和socketserver源码(并发处理socket) ...
- 面试题:HashMap和ConcurrentHashMap的区别,HashMap的底层源码。
Hashmap本质是数组加链表.根据key取得hash值,然后计算出数组下标,如果多个key对应到同一个下标,就用链表串起来,新插入的在前面. ConcurrentHashMap:在hashMap的基 ...
- HashMap和ConcurrentHashMap的区别,HashMap的底层源码。
Hashmap本质是数组加链表.根据key取得hash值,然后计算出数组下标,如果多个key对应到同一个下标,就用链表串起来,新插入的在前面. ConcurrentHashMap:在hashMap的基 ...
- HashMap和ConcurrentHashMap的区别,HashMap的底层源码
HashMap本质是数组加链表,根据key取得hash值,然后计算出数组下标,如果多个key对应到同一个下标,就用链表串起来,新插入的在前面. ConcurrentHashMap在HashMap的基础 ...
- vue打包时,assets目录 和static目录下文件的处理区别(nodeModule中插件源码修改后,打包后的文件应放在static目录)
为了回答这个问题,我们首先需要了解Webpack如何处理静态资产.在 *.vue 组件中,所有模板和CSS都会被 vue-html-loader 及 css-loader 解析,并查找资源URL.例如 ...
- memcpy、memmove、memset及strcpy函数实现和理解
memcpy.memmove.memset及strcpy函数实现和理解 关于memcpy memcpy是C和C++ 中的内存拷贝函数,在C中所需的头文件是#include<string.h> ...
- c语言中几个常见的库函数strlen、strcmp、strcat、strcpy、strncpy、memset、memcpy、memmove、mmap
1.strlen() 1)计算给定字符串的长度,不包括’\0’在内 unsigned int strlen(const char *s) { assert(NULL != s);//如果条件不满足,则 ...
- memmove和memcpy函数的区别及实现
一.memmove()和memcpy()函数和strcpy()函数的区别: (1)使用的类型不同,strcpy()函数只对字符串进行操作:memmove()和memcpy()函数对所有类型都适用,为内 ...
随机推荐
- 黑客瑞士军刀NC使用教程
###################################################################### 1. 写在前面的话 ################### ...
- C++ Primer 学习笔记_88_用于大型程序的工具 --异常处理[续1]
用于大型程序的工具 --异常处理[续1] 四.又一次抛出 有可能单个catch不能全然处理一个异常.在进行了一些校正行动之后,catch可能确定该异常必须由函数调用链中更上层的函数来处理,catch能 ...
- 万圣节福利:红孩儿3D引擎开发课程《3ds max导出插件初步》
ds max文件夹,插件文件夹以及3ds max的可执行程序文件夹: 位的,这里要改成x64,否则启动程序后3ds max会提示"不是有效的win32程序"之类的对话框. 然后要将 ...
- 初探ListView
ListView可能是Android开发中最常用的一个控件,但要用的纯熟还需要不断的锻炼. 建立简单的ListView 1.在布局文件(.xml)中添加<ListView>标签 2.在Ma ...
- wamp+thinkphp环境配置
下载wamp并安装,启动wamp,会出现一个小图标,然后点击它——>Start All Services.我点击之后是橙色,不是绿色.绿色代表成功启动.我是IIS占用了80端口的缘故,所以我修改 ...
- python初探-collections容器数据类型
collections容器数据类型是对基本数据类型的补充,简单介绍下计数器.有序字典.默认字典.可命名元祖.队列. 计数器(Counter) Counter是对字典类型的补充,用于追踪值得出现次数 c ...
- 03-C语言编码规范和变量
目录: 一.C语言的编码规范 二.变量 三.浮点型float 四.变量名命名规则 五.变量作用域与生命周期 回到顶部 一.C语言的编程规范 1 语句可以分开放在任意位置 2 空格可以让代码更清晰 3 ...
- 转: 深入理解 AngularJS 的 Scope
查看 DEMO.参考 StackOverflow. ng-switch ng-switch 的原型继承和 ng-include 一样.所以如果你需要对基本类型数据进行双向绑定,使用 $parent ...
- 射频识别技术漫谈(18)——Mifare Desfire
Mifare DESFire(MF3 IC D40/D41,本文以D40为例)遵守14443 TypeA协议,卡内的数据以文件形式存储,所以有人认为它是准CPU卡,主要用于安全性要求较高的非接触式领 ...
- C语言 HTTP上传文件-利用libcurl库上传文件
原文 http://justwinit.cn/post/7626/ 通常情况下,一般很少使用C语言来直接上传文件,但是遇到使用C语言编程实现文件上传时,该怎么做呢? 借助开源的libcurl库,我们 ...