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()函数对所有类型都适用,为内 ...
随机推荐
- linux线程间同步方式汇总
抽空做了下linux所有线程间同步方式的汇总(原生的),包含以下几个: 1, mutex 2, condition variable 3, reader-writer lock 4, spin loc ...
- linux 下手动编译安装无线网卡驱动
先参照 <本地yum源安装GCC >安装好gcc hp的笔记本上安装了CentOS6.3,没有安装无线网卡驱动,安装这个驱动,在Google上找了好多资料,最后终于解决了这个问题.在这里做 ...
- hdu 5104 Primes Problem(prime 将三重循环化两重)
//宁用大量的二维不用量小的三维 #include <iostream> #include<cstdio> #include<cstring> using name ...
- zoj 3708 Density of Power Network
/*看英文和图我头都大了,不过很简单的.*/ #include<string.h> #include<stdio.h> ][],q[],w[]; int main(int ar ...
- Visual Studio的ASP.NET修改默认打开浏览器
1.新建web空应用程序,输入项目名称. 2.右击项目名称,添加“新建项”—一般处理程序 3.右击新建一个HTML文件,任意命名. 4.右击新建的Html文件,选择“浏览方式” 5.选择后弹出浏览器选 ...
- Visual Studio 继续并运行上次的成功生成,未提示直接运行上一个版本解决方案!
Visual Studio ==>工具 ==> 选项==>项目和解决方案 ==>生成并运行_运行时,当出现生成或部署错误时_选择,提示启动
- Objective-c 字典对象
oc 中的 NSDictionary 的作用同 java 中的字典类相同,提供了 “键-值”对的组合.比如,是用字典类实现对学生姓名和学号的存放,编号是一个键(唯一性),姓名是值.它的方法有: 下面通 ...
- 数据库水平切分的实现原理解析——分库,分表,主从,集群,负载均衡器(转)
申明:此文为转载(非原创),文章分析十分透彻,已添加原文链接,如有任何侵权问题,请告知,我会立即删除. 第1章 引言 随着互联网应用的广泛普及,海量数据的存储和访问成为了系统设计的瓶颈问题.对于一个大 ...
- LintCode-子数组之和
题目描述: 给定一个整数数组,找到和为零的子数组.你的代码应该返回满足要求的子数组的起始位置和结束位置 样例 给出 [-3, 1, 2, -3, 4],返回[0, 2] 或者 [1, 3]. publ ...
- 帝国cms灵动标签下常用标签
这里简单整理下灵动标签下的常用标签 标题名称:<?=$bqr['title']?> <?=esub($bqr[title],22)?> 限制字符22个 标题链接:<?= ...