调用 strcpy 的结果与预期不同
Posted
技术标签:
【中文标题】调用 strcpy 的结果与预期不同【英文标题】:Result of calling strcpy is different than expected 【发布时间】:2015-02-17 05:56:48 【问题描述】:#include <stdio.h>
#include <string.h>
int main()
char src[]="123456";
strcpy(src, &src[1]);
printf("Final copied string : %s\n", src);
当我使用 Visual Studio 6 编译器时,它给了我预期的答案“23456
”。
为什么这个程序在使用 gcc 4.7.2 编译时会打印“23556
”?
【问题讨论】:
未定义的行为,使用 memmov() 代替 你是怎么知道它在哪里重叠的? &Src[1]="23456" 对!?!那么重叠在哪里? @PeterMiehle 是的,memmov 加上一个额外的e
。
src
衰减为指向数组src
的第一个元素的指针。 &src[1]
是指向数组第二个元素的指针。由于源字符串的长度不是 0,它们显然是重叠的。
这意味着我必须从另一个字符串“char dest[]="123456";
”复制并执行“strcpy(src, &dest[1]);
”
【参考方案1】:
strcpy(src, &src[1]);
是未定义的行为:
C11 §7.24.2.3
strcpy
函数
strcpy
函数复制s2
指向的字符串(包括终止的null 字符) 到s1
指向的数组中。 如果复制发生在对象之间 重叠,行为未定义。
顺便说一句,memcpy
是相似的(但不是memmove
)。见C FAQ: What's the difference between memcpy
and memmove
。
【讨论】:
嗯...似乎类似于memcpy
vs memmove
问题。
您在哪里可以找到这些信息?你怎么这么快就找到了?或者你写过自己的书吗:D?
@Rizier123 我在附近有一份 C 标准草案的副本,如果这就是你要问的 :)。见Where do I find the current C or C++ standard documents?。
@Rizier123:在我的系统上,它在 glibc 手册页 (man 3 strcpy
) 中有描述:字符串可能不重叠。
@Blood-HaZaRd:这是未定义的行为,实现可以为所欲为。【参考方案2】:
这是未定义的行为。请改用memmove
函数。 memmove
旨在允许源缓冲区和目标缓冲区重叠。
memmove(src, &src[1], strlen(&src[1]) + 1) ; // + 1 for copying the terminating zero
【讨论】:
是的,内存重叠。 为了清晰起见,您可以使用src+1
,而不是看起来很尴尬的&src[1]
。
@Jongware 你是对的,但我故意把它和原来的问题一样。【参考方案3】:
来自 ISO/IEC 9899:TC3 (c99)
7.21.2.3 strcpy 函数
概要
1
#include <string.h>
char *strncpy(char * restrict s1,
const char * restrict s2,
size_t n);
说明
2 strcpy 函数复制 s2 指向的字符串(包括终止的 null 字符) 到 s1 指向的数组中。 如果复制发生在对象之间 重叠,行为未定义。
所以你所做的只是未定义的行为;)
您还可以查看附件 J.2
说明未定义行为的情况并说明如何防止:
在以下情况下行为未定义:
[...]
- 尝试使用库将对象复制到重叠对象 功能,除非明确允许(例如,memmove)(第 7 条)。
【讨论】:
以上是关于调用 strcpy 的结果与预期不同的主要内容,如果未能解决你的问题,请参考以下文章