• 请不要在回答技术问题时复制粘贴 AI 生成的内容
amiwrong123
V2EX  ›  程序员

strcpy 中,遇到内存重叠,为什么结果是这样?

  •  
  •   amiwrong123 · Jan 2, 2022 · 2921 views
    This topic created in 1771 days ago, the information mentioned may be changed or developed.
    #include <stdio.h>
    #include <string.h>
    
    int main()
    {
    	char s[10] = "hello"; 
    	printf("%s\n", strcpy(s, s + 1));
    	printf("%s\n", s);
    
    	return 0;
    }
    

    打印结果是:

    ello
    ello
    

    这个我理解,把ello\0往前复制了。

    #include <stdio.h>
    #include <string.h>
    
    int main()
    {
    	char s[10] = "hello"; 
    	printf("%s\n", strcpy(s + 1, s));
    	printf("%s\n", s);
    
    	return 0;
    }
    

    打印结果却是:

    helll
    hhelll
    

    这个hhelll我就不理解了。不应该是hhello吗

    本来想试一下 strcpy 的行为,自己写个实现。但现在它的行为我不理解了。

    vs2019 试的,需要按照 https://blog.csdn.net/oguro/article/details/52685662 添加宏才能运行。

    Supplement 1  ·  Jan 2, 2022
    谢谢各位,理解了。我本意只是根据这些基本函数的行为,自己写一遍实现练习一下。

    https://paste.ubuntu.com/p/H2Fc9gKkSK/
    上面写了 考虑内存重叠时,我写的 strcpy 函数,欢迎各位指正
    Supplement 2  ·  Jan 2, 2022
    说错了,不是指正,应该是交流。毕竟这是 未定义行为,我只是按照我自己想法写了一个
    10 replies  •  2022-01-02 15:51:06 +08:00
    fishCatcher
    fishCatcher
    Jan 2, 2022 via iPhone
    1
    这是个未定义行为,所以你怎么实现都可以,
    yulon
    yulon
    Jan 2, 2022❤️3
    2
    你要问这种有冲突的问题,当然只能得到有冲突的结果。

    strcpy 作为一个拷贝函数,自然是不会分配额外内存,不然直接给你返回一个新字符串不就完了。

    那么在有限的内存里,它有可能用算法解决内存重叠,也有可能解决不了。

    猜测你是 32 位程序,内部实现是以机器字为单位来拷贝,也就是 4 个字节,拷贝一次之后,第 5 个字节已经变了,自然就多出来一个 l 。

    建议别浪费时间在这种问题上,而且写出这种程序非常恐怖。
    wudicgi
    wudicgi
    Jan 2, 2022❤️1
    3
    yulon 已经把需要说的都说了,极有可能就是按 4 字节处理出来的结果,因为 s 在栈里分配,地址会是 4 字节对齐的
    如果有兴趣可以试试 s[10] = "_hello" 时 strcpy(s + 2, s + 1) 的情况,结果应该不一样
    不过其实深究这个意义不大,首先考虑把 strcpy() 换成 strncpy(), strncpy_s() 之类的函数,其次必要时自己加额外判断

    另外,看到你想自己写个 strcpy() 的实现,
    如果是 for 循环简单的逐字节复制,怕是这时 strcpy() 会直接运行到访问地址无读写权限的情况,
    把从 s 起始位置开始的所有的能读写的字节都改成 'h'

    标准库的实现会不一样,有的库可能先 strlen() 算好长度再调用 memcpy(), 这样不会有一直处理下去的问题,
    但具体结果如何得看具体代码了,一般会有不少优化的,毕竟 memcpy() 很常用
    wevsty
    wevsty
    Jan 2, 2022
    4
    不要纠结这些标准库函数内部怎么实现的,看你换个编译器,甚至换个版本就会变了。
    dangyuluo
    dangyuluo
    Jan 2, 2022
    5
    > The behavior is undefined if the strings overlap.
    2i2Re2PLMaDnghL
    2i2Re2PLMaDnghL
    Jan 2, 2022❤️3
    6
    未定义行为,电脑直接爆炸也是逻辑上允许的。
    直接按照标准去写就行,标准大于约定。
    thedrwu
    thedrwu
    Jan 2, 2022 via Android
    7
    未定义的。你的 code reviewer 会把这种情况打回来重写。
    kokutou
    kokutou
    Jan 2, 2022 via Android
    8
    不要研究未定义行为。。。
    除非你是搞编译器之类底层的。。。
    codehz
    codehz
    Jan 2, 2022 via Android❤️1
    9
    (这一系列函数中,只有 memmove 是保证重叠的时候正确的)
    agagega
    agagega
    Jan 2, 2022 via iPhone
    10
    只有 memmove 可以重叠
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Privacy   ·   Solana   ·   741 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 39ms · UTC 19:41 · PVG 03:41 · LAX 11:41 · JFK 14:41
    ♥ Do have faith in what you're doing.