memcpy函数是不是已经解决了内存重叠的问题呢?

ringyang88 2012-10-19 10:18:30
1 #include <stdio.h>
2 #include <string.h>
3
4 int main(void)
5 {
6 int i;
7 char a[] = "12345";
8
9 memcpy(a + 1, a, 3);
10 for (i = 0; i < 5; i++)
11 printf("a[%d] = %c\n", i, a[i]);
12
13 return 0;
14 }

输出结果:
a[0] = 1
a[1] = 1
a[2] = 2
a[3] = 3
a[4] = 5

不是应该是下面的结果吗?请高手指点,感激不尽!
a[0] = 1
a[1] = 1
a[2] = 1
a[3] = 1
a[4] = 5
...全文
1283 39 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
39 条回复
切换为时间正序
请发表友善的回复…
发表回复
ForestDB 2014-05-27
  • 打赏
  • 举报
回复
我这里的man page显示: The memcpy() function copies n bytes from memory area s2 to memory area s1. If s1 and s2 overlap, behavior is undefined. Applications in which s1 and s2 might overlap should use memmove(3) instead. 所以作为实现,它即可以不管overlap,也可以实现得像memmove一样。 所以,这个看库的实现。
赵4老师 2014-05-26
  • 打赏
  • 举报
回复
memcpy永远也解决不了内存重叠问题。因为: copy操作的意思是操作完成后,目标的内容和旧源的内容一样,且新源的内容也维持旧源的内容不变。 move操作的意思是操作完成后,目标的内容和旧源的内容一样,新源的内容不一定维持旧源的内容不变。
arbboter 2014-05-26
  • 打赏
  • 举报
回复
int main(void)
{
	int i;
	char a[] = "12345";
	// 先做a[3] = a[2]的话,输出结果是:1 1 2 3 5
	// 先做a[1] = a[0]的话,输出结果是:1 1 1 1 5
	memcpy(a + 1, a, 3);
	for (i = 0; i < 5; i++)
		printf("a[%d] = %c\n", i, a[i]);
	return 0;
}
看memcpy怎么实现的了。
TheNewIpad 2014-05-26
  • 打赏
  • 举报
回复
引用 35 楼 q191201771 的回复:
我上次用memmove写一个buffer类 被公司新来的一位大拿说这种函数不能用的,效率非常低。。 我当时只能呵呵了
呵呵。
就想叫yoko 2014-05-26
  • 打赏
  • 举报
回复
我上次用memmove写一个buffer类 被公司新来的一位大拿说这种函数不能用的,效率非常低。。 我当时只能呵呵了
zheng222222 2014-05-25
  • 打赏
  • 举报
回复
还能回复结果吗
赵4老师 2012-10-22
  • 打赏
  • 举报
回复
[Quote=引用 22 楼 的回复:]
先把copy和move的概念分清楚吧:
copy的意思是操作结束后保证目标和旧源的数据一致,且旧源不会变;
move的意思是操作结束后保证目标和旧源的数据一致,但旧源不一定不变;
[/Quote]
提醒:按照这个理解的话,在内存有重叠时根本无法实现copy!
AndyZhang 2012-10-22
  • 打赏
  • 举报
回复
赵老师说的有道理
xpingping 2012-10-22
  • 打赏
  • 举报
回复
帮楼主顶下,……
求大侠解释memcpy函数。
从楼上提供的memcpy源代码,
运行结果应该是11115。
*a给*(a+1),即a[1]=a[0];1
*(a+1)给*(a+2),即a[2]=a[1];1
*(a+2)给*(a+3),即a[3]=a[2];1
实际运行结果咋是反的?
*(a+2)给*(a+3),即a[3]=a[2];3
*(a+1)给*(a+2),即a[2]=a[1];2
*a+给*(a+1),即a[1]=a[0];1
下面是参考memcpy改的,这个效果才是11235
void *mymemcpy(void *dest, const void *source, size_t count) 
{
assert((NULL != dest) && (NULL != source));
//char *tmp_dest = (char *)dest;
//char *tmp_source = (char *)source;
char *tmp_dest = (char *)dest + count - 1;
char *tmp_source = (char *)source + count - 1;
while(count --)
//*tmp_dest ++ = *tmp_source ++;
*tmp_dest -- = *tmp_source --;
return dest;
}
吉米芽菜 2012-10-22
  • 打赏
  • 举报
回复
[Quote=引用 7 楼 的回复:]

C/C++ code

If copying takes place between objects that overlap, the behavior is undefined.

$ cat overlap.c
#include <stdio.h>
#include <string.h>

int main(void)
{
int i;
char a[] ……
[/Quote]

7 楼的答案可以用以下实现揭晓(该code摘自Linux 3.2.7)
执行第一次,此时类型为char,结果是: 11345
执行第二次,此时类型为short,结果为:11135

void *
memcpy(void *pdst, const void *psrc, size_t pn)
{


/* When src is aligned but not dst, this makes a few extra needless
cycles. I believe it would take as many to check that the
re-alignment was unnecessary. */
if (((unsigned long) dst & 3) != 0
/* Don't align if we wouldn't copy more than a few bytes; so we
don't have to check further for overflows. */
&& n >= 3)
{
if ((unsigned long) dst & 1)
{
n--;
*dst = *src;
src++;
dst++;
}

if ((unsigned long) dst & 2)
{
n -= 2;
*(short *) dst = *(short *) src;
src += 2;
dst += 2;
}
}
吉米芽菜 2012-10-22
  • 打赏
  • 举报
回复
看来不同的编译环境,所得结果是有差异的。
在32位X86平台上,每次copy一个字节需要一条指令,每次copy4个字节也只需要一条指令。
所以memcpy函数的实现尽可能4个字节4个字节的copy。
flytask 2012-10-22
  • 打赏
  • 举报
回复
[Quote=引用 22 楼 的回复:]

先把copy和move的概念分清楚吧:
copy的意思是操作结束后保证目标和旧源的数据一致,且旧源不会变;
move的意思是操作结束后保证目标和旧源的数据一致,但旧源不一定不变;
[/Quote]

++
wzb56 2012-10-21
  • 打赏
  • 举报
回复
[Quote=引用 26 楼 的回复:]

有一函数,如 char * getMemery(){
char * m = "212313";

return m;

}

这个函数最大的问题是什么?如何才能改正确?
此外,m指向的常量存储区是否在函数调用结束后,就被释放掉了,还是要等程序结束后,才会被释放?
[/Quote]
字符串常量在整个应用程序运行期间只有一份拷贝。字符串常量的内存分配在只读存储区,是不可 改写的。
字符串的字面值是指向其首字符的指针。

返回一个指向只读存储区的地址,无法修改其内容。
显然该常量字符串所占的内存是程序运行结束后,释放的。

从函数的用意来看,好像是getMemory,分配内存,那么可以通过malloc, calloc(初始化),realloc(对malloc,calloc分配的内存再分配),注意,在外部要显示free()。

方法一: 使用静态数组

char * getMemery(){
static char m[] = "212313";

return m;

}




方法二: 使用动态内存分配


char * getMemery(){
const char * str = "212313"
char * m = malloc(strlen(str) + 1);
memcpy(m, str, strlen(str)+1);

return m;

}






nanmushiyuan 2012-10-21
  • 打赏
  • 举报
回复
有一函数,如 char * getMemery(){
char * m = "212313";

return m;

}

这个函数最大的问题是什么?如何才能改正确?
此外,m指向的常量存储区是否在函数调用结束后,就被释放掉了,还是要等程序结束后,才会被释放?
Joseph_1118 2012-10-20
  • 打赏
  • 举报
回复
“未定义”导致很奇怪!
[Quote=引用 19 楼 的回复:]

文档说,memcpy在发生内存重叠时,在语言中是未定义行为。

比如下面的代码也引发未定义行为
int i = 1;
i++ + i++ == ? /* ERROR */
[/Quote]
ringyang88 2012-10-20
  • 打赏
  • 举报
回复
嗯,嗯,好,好,非常感谢大家!
thanks!
ctreewang 2012-10-20
  • 打赏
  • 举报
回复
赵老师一出手,我就明白了~~~~

速速膜拜赵老师

[Quote=引用 22 楼 的回复:]

先把copy和move的概念分清楚吧:
copy的意思是操作结束后保证目标和旧源的数据一致,且旧源不会变;
move的意思是操作结束后保证目标和旧源的数据一致,但旧源不一定不变;
[/Quote]
manpages 2012-10-20
  • 打赏
  • 举报
回复
未定义就是不可预期。你应该避免这样的情形,而不是去猜测它的结果。

Q: What's the difference between memcpy and memmove?

A: memmove offers guaranteed behavior if the memory regions pointed to by the source and destination arguments overlap. memcpy makes no such guarantee, and may therefore be more efficiently implementable. When in doubt, it's safer to use memmove.
赵4老师 2012-10-20
  • 打赏
  • 举报
回复
先把copy和move的概念分清楚吧:
copy的意思是操作结束后保证目标和旧源的数据一致,且旧源不会变;
move的意思是操作结束后保证目标和旧源的数据一致,但旧源不一定不变;
wuzhiwenk3001 2012-10-20
  • 打赏
  • 举报
回复
跟实现这个memcpy的库的实现方法有关吧
加载更多回复(19)

70,023

社区成员

发帖
与我相关
我的任务
社区描述
C语言相关问题讨论
社区管理员
  • C语言
  • 花神庙码农
  • 架构师李肯
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧