memcpy的使用方法总结
1、memcpy 函数用于 把资源内存(src所指向的内存区域) 复制到目标内存(dest所指向的内存区域);拷贝多少个?有一个size变量控制
拷贝的字节数;
函数原型:void *memcpy(void *dest, void *src, unsigned int count);
使用方法:(1)能够拷贝不论什么类型的对象,由于函数的參数类型是void*(没有定义类型指针),也就是说传进去的实參能够是int*,short*,char*等等,
可是由于函数拷贝的过程是一个字节一个字节的拷贝的,所以实际操作的时候要把void*强制转化为char*,这样在指针加的时候才会保证每次加一个字节,呵呵
函数源码实现:
void *memcpy1(void *desc,const void * src,size_t size)
{
if((desc == NULL) && (src == NULL))
{
return NULL;
}
unsigned char *desc1 = (unsigned char*)desc;
unsigned char *src1 = (unsigned char*)src;
while(size-- >0)
{
*desc1 = *src1;
desc1++;
src1++;
}
return desc;
}
int _tmain(int argc, _TCHAR* argv[])
{
int dest[2] = {0};
const char src[5] = "1234";
//printf(src);
memcpy1(dest,src,sizeof(src));
//*(dest+5) = '/0';
printf((char *)dest);
int m = -1;
return 0;
}
注意事项:(1)void* 一定要返回一个值(指针),这个和void不太一样!
(2)首先要推断指针的值不能为空,desc为空的话肯定不能拷贝内存空间,src为空相当于没有拷贝;所以之间return掉;
(3)""空串是指内容为0,NULL是0,不是串;两个不等价;
(4)int dest[2] = {0};这是对int 类型的数组初始化的方法;假设是char类型,就用char a[5] = "1234"; 注意数组下标要
多于实际看到的字符数,由于还有'/0'
(5)printf((char *)dest);这句话,是把 char 类型 src 传到 int 类型的 dest的内存强制转化成char类型,然后打印出来;
由于直接看int类型的dest是看不到里面的内容的;由于有unsigned char *desc1 = (unsigned char*)desc;所以字符能够传
到dest里面保存起来,dest所指向的内存长度4个字节,强制转化为char 就是把四个字节分成一个一个的字节,这样就能够看到
一个个字符了,假设定义成char dest[5] = "1234";就不用转化;呵呵,表达起来真累人;
(6)memcpy1(dest,src,sizeof(src));注意里面的sizeof(src),这个是包括字符串的结束符'/0'的;所以不用操心printf(dest);
可是假设用memcpy1(dest,src,4);没有'/0'就要*(dest+5) = '/0';这样保证是一个完整的字符串;
(7)假设初始化的时候:
char dest[1024] = "12345666";//{0};
const char src[5] = "3333";
那么拷贝的时候,假设用memcpy1(dest,src,sizeof(src));则printf(dest);出来是3333
假设memcpy1(dest,src,4);则printf(dest);出来是33335666;由于上面的sizeof(src),包括'/0',所以拷贝过去的字符串以'/0'
结束,就仅仅有3333,而假设传4个字符,'/0'是第五个字符,那就遇到dest[1024] 的'/0'结束,所以是33335666
字符串的'/0'问题一定要注意啊!!!
实际应用:
unsigned char g_pData[1024] = "";
DWORD g_dwOffset = 0;
bool PackDatatoServer(const unsigned char *pData, const unsigned int uSize)
{
memcpy(g_pData+g_dwOffset, pData, uSize);
g_dwOffset += uSize;
//g_pData += uSize;
return true;
}
void main()
{
const unsigned char a[4] = "123";
PackDatatoServer(a, 3);
PackDatatoServer(a, 1111);
int b = -1;
}
PackDatatoServer()函数的作用是把每次的资源内存复制到目标内存里面,并且是累加的拷贝;也就是后一次紧接着上一次的拷贝;
显然用到了memcpy函数;
实现原理是用到了一个全局变量g_dwOffset 保存之前拷贝的长度,最開始没有想到这一点,结果每次拷贝都是一次性的,下一次拷贝把
上一次的冲掉了;所以用全局变量记录拷贝的长度;
第二个须要注意的是,拷贝的过程中注意不要改变目标指针的指向,即目标指针始终指向初始化的时候指向的位置;那么怎么实现累积拷贝呢?
就是用的指针偏移;第一次实现的时候,把g_pData += uSize;写到了函数里面,这样写是可以实现指针位移的目标,可是指针指向也发生改变;
另外:g_pData += uSize;也有报错:left operand must be l-value,原因是:把地址赋值给一个不可更改的指针!
比方:
char a[100];
char *p = new char[10];
a = p; //这里出错,注意了:数组的首地址也是一个常量指针,指向固定不能乱改的~~
char * const pp = new char[1];
pp = a; //也错
所以既不能改变首地址,又要满足累积赋值(就是赋值的时候要从赋过值的地方開始向下一个内存块赋值,想到指针加),所以想到把指针加写到
函数參数里面,这时就要充分了解memcpy的实现过程,里面是一个一个字符的赋值的,想连续赋值,就要把指针指向连续的内存的首地址,所以,
真的非常不好表达,呵呵,就这样了,一大推零散的知识。。。
memcpy的使用方法总结相关推荐
- memcpy 内存优化方法
内存拷贝的优化方法 http://www.blogcn.com/blog/cool/main.asp?uid=flier_lu&id=1577430 http://www.blogcn.com ...
- C语言 memcpy和memcpy_s区别 - C语言零基础入门教程
目录 一.memcpy 和 memcpy_s 函数区别 1.语法对比 memcpy_s 函数语法 memcpy 函数语法 2.memcpy 和 memcpy_s 相同点 3.memcpy 和 memc ...
- 内存拷贝函数 void * memcpy ()
函数原型:void * memcpy(void * dest, void * src, int n); 函数的功能是从源内存地址的起始位置开始拷贝若干个字节到目标内存地址中,即从源source中拷贝n ...
- android stringbuilder清空,StringBuffer 清空StringBuffer的实例的三种方法
@Test public void testStringbuffer(){ //StringBuffer类没有clear方法,不过可以通过下面两种方法来清空一个StringBuffer的实例: Str ...
- C语言 memcpy_s 函数 - C语言零基础入门教程
目录 一.memcpy_s 函数简介 1.memcpy 函数报错:error C4996 2.memcpy 函数没有方法来保证有效的缓冲区尺寸,使用不安全 二.memcpy_s 函数语法 三.memc ...
- 面试 C++ 程序员,什么样的问题是好问题?
原文:https://www.zhihu.com/question/20184857 默认排序 陈硕 编程.C++ 话题的优秀回答者 306 人赞同了该回答 对于应届生: 标准库各容器的基本操作的复杂 ...
- 在 Oracle Enterprise Linux 和 iSCSI 上构建您自己的 Oracle RAC 11g 集群
作者:Jeffrey Hunter 了解如何以低于 2,700 美元的费用在 Oracle Enterprise Linux 上安装并配置 Oracle RAC 11g 第 2 版开发集群. 本指南中 ...
- Java面试题大全2021版
一.Java 基础 JDK 和 JRE 有什么区别? JDK:Java Development Kit 的简称,java 开发工具包,提供了 java 的开发环境和运行环境. JRE:Java Run ...
- 最保险的函数间数组作为参数值传递与返回方法,用memcpy函数
举例代码如下: void mycvCalcHist(IplImage *img,double out_hist[256]) {int i=0, j=0; double temp1=0;int temp ...
最新文章
- Swift - 简单的原生与网页交互
- jQuery replaceWith replaceAll end的用法
- Spring5参考指南:基于注解的容器配置
- [Java网络编程基础]端口,协议
- 可扩展的TextView,ExpandableTextView与Scroller类的使用
- 戴尔电脑好还是华为好_华硕和戴尔笔记本哪种好 华硕和戴尔优缺点分析【详解】...
- 设计模式之单例模式8种实现方式,其一:饿汉式-静态常量饿汉式
- VCC、VDD、VEE、VSS的区别
- [转]AAuto编程语言官方站 网站服务条款
- java中io创建文件和读取文件
- java中如何查看代码运行时间?
- rs485数据线接反_rs485接口怎么接线?弱电人必学RS485接口基础知识讲解
- android rxbus github,RxBus
- 中柏平板u盘启动_中柏A13笔记本如何进bios设置u盘启动
- 【OpenGL游戏开发之一】MAC OS X And Win7 vs2010 搭建OpenGL
- android 高度百分比,Android 屏幕适配-百分比布局适配
- gcc警告选项汇总 转
- 大厂面试必考题:三行布局之圣杯布局和双飞翼布局的区别
- scipy.statis统计学的常用Python包
- 联通光猫f677v2改桥接的辛酸历程
热门文章
- python中字典的find_python-re.findall返回命名捕获组的字典?
- 超级vga显示卡_VGA 显示卡简介
- linux csr蓝牙驱动,csr4.0蓝牙适配器驱动下载
- vue树形多列_[vue]使用Element-ui的el-table实现多列同时排序。
- Zookeeper分布式一致性原理(八):Zookeeper典型应用场景
- Java基础:char类型字节占用数
- java md5包_JAVA中有没有提供MD5算法的包啊?
- java 注解学习_java注解的学习
- git--分支管理:创建、合并、冲突解决
- echarts自定义提示框数据