【问题标题】:strcpy works fine, even though memory is not allocatedstrcpy 工作正常,即使没有分配内存
【发布时间】:2015-09-10 13:29:45
【问题描述】:

以下 c++ 程序运行良好,即使我没有为chr 分配任何内存。 我浏览了谷歌,所以遇到了这个 Why does this intentionally incorrect use of strcpy not fail horribly?

这里程序适用于空间小于源的目标。 这是否也适用于我的情况,strcpy 写入堆中的随机位置?

#include<iostream>
using namespace std;

class Mystring
{
    char *chr;
    int a;
    public:
    Mystring(){}
    Mystring(char *str,int i);
    void Display();

};

Mystring::Mystring(char *str, int i)
{
   strcpy(chr,str);
   a = i;
}

void Mystring::Display()
{
    cout<<chr<<endl;
    cout<<a<<endl;
}


int main()
{
    Mystring a("Hello world",10);
    a.Display();
    return 0;
}
output:-
Hello world
10

我用另一个 c++ 程序尝试了同样的事情,使用任何类和类成员,我能够看到崩溃。

#include<iostream>
using namespace std;

int main()
{
    char *src = "Hello world";
    char *dst;
    strcpy(dst,src);
    cout<<dst<<endl;
    return 0;
}

请帮助我理解第一个 c++ 程序中的行为。内存是否以某种方式分配或strcpy 正在写入某个随机内存位置。

【问题讨论】:

  • 这只是未定义的行为,不会自动分配任何内容。
  • 很好,你只是没有看到问题。然而。这是最“可怕的失败”,因为你可能直到真正糟糕的事情发生之前才意识到这样的错误(不是在这个玩具程序中,而是在现实世界的使用中......丢失所有数据,在金钱上做错事等等等等.)
  • 是否像写入某个随机内存位置一样?如果是这样的话,如果chr 只指向那个位置怎么办?请帮助我理解这一点。
  • Is it like writing into some random memory location? 是的。

标签: c++ memory constructor strcpy


【解决方案1】:

C++ 标准未定义程序的行为。

这意味着任何 C++ 实现(例如编译器)都可以为所欲为。打印“你好!”在标准输出上将是一个可能的结果。就涉及 C++ 标准而言,格式化硬盘仍然是可以接受的。但实际上,堆上的一些随机内存将被覆盖,产生不可预测的后果。

请注意,甚至允许程序按预期运行。目前。除非是星期五。或者直到你修改一些完全不相关的东西。这就是你的情况,从程序员的角度来看,这是最糟糕的事情之一。

稍后,您可能会添加一些代码并看到您的程序严重崩溃,并认为问题出在您刚刚添加的代码上。这可能会导致您花费很长时间调试代码的错误部分。如果发生这种情况,欢迎下地狱。

因此,您永远不应该依赖未定义的行为。

【讨论】:

  • 给我送披萨也是可以接受的结果吗?我知道我今晚要编译什么!
  • @Mercious 当然。但如果发生这种情况,C++ 标准并不能保证披萨上有什么。当然,吃了它的后果是不确定的。
  • 我明白了。我想这是一次有趣的旅程。当你在 C++ 中有 UB 时谁需要药物!
  • 它还应具有未指定的营养价值。
【解决方案2】:

strcpy() 确实在写入随机位置。

如果你的程序运行良好并且没有崩溃,那就是盲目的运气。

您已在堆栈上的 MyString 类对象上创建。在该对象中有一个成员指针chr,它指向某个任意位置。您的构造函数是否注意初始化该指针或为指向的指针分配内存? ——不,它没有。所以chr 指向某个地方。

strcpy() 反过来不关心任何指针的有效性,它相信你的专业精神来提供有效的输入。所以它完成了复制刺痛的工作。幸运的是,在未初始化的chr 指向的位置覆盖内存不会使您的程序崩溃,但这只是“幸运”。

【讨论】:

    【解决方案3】:

    众所周知,strcpy() 会导致溢出错误,因为没有检查数据是否适合新数组。 这种溢出的结果有时可能从未被注意到,这完全取决于数据写入的位置。然而,常见的结果是堆和/或程序损坏。

    strcpy() 的一个安全替代方法是使用 strcpy_s(),它还需要数组的大小。您可以在MSDNhere 上阅读有关 strcpy_s() 用法的更多信息

    【讨论】:

    • 不是每个人都使用 microcrap bub。
    • @πάνταῥεῖ ῥεῖ 好吧,strcpy_s() 是 C++11 标准函数,因此它与 Microsoft 无关。不过,我添加了一个额外的来源。
    • @AB - 无法确认 - 从哪里找到这个标准功能的想法? cppreference.com 和 cplusplus.com 都没有。
    • en.cppreference.com/w/c/string/byte/strcpy 有 strcpy_s(虽然它的 C 是 11)
    • 它是在 C++ 11 标准 (ISO/IEC 9899:2011) 中引入的,详情请查看我的第二个链接。
    【解决方案4】:

    实际上,strcpy() 做了这样的事情:

    char *strcpy(char *dest, const char *src)
    {
      unsigned i;
      for (i=0; src[i] != '\0'; ++i)
        dest[i] = src[i];
      dest[i] = '\0';
      return dest;
    }
    

    因此,当您将指向某个字符数组的指针传递给strcpy 时,它会将数据从src 复制到dest,直到到达NULL 终止字符。
    字符指针不包含任何有关字符串长度的信息,因此当您传递dest 指针时,即使您没有为其分配内存,它也会复制数据。

    运行这个示例代码,你就会明白我的意思了:

    #include <cstring>
    #include <iostream>
    
    using namespace std;
    
    int main()
    {
        char str1[] = "Hello_World!";
        char str2[5];
        char str3[10];
        strcpy(str2,str1);
        cout << "string 1:" << str1 << endl;
        cout << "string 2:" << str2 << endl;
        cout << "string 3:" << str3 << endl;
        return 0;
    }
    

    这不会显示任何错误,但您可以通过我的示例了解这不是一个好习惯。

    【讨论】:

      猜你喜欢
      • 2014-03-15
      • 2013-03-30
      • 1970-01-01
      • 2017-12-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-04-06
      相关资源
      最近更新 更多