代码之家  ›  专栏  ›  技术社区  ›  Georgy90

而内环换内环

  •  2
  • Georgy90  · 技术社区  · 7 年前

    我在一本书中读到了这个示例代码。我不明白为什么以下示例代码的函数声明的这一部分是必要的:

    while (i <= n)
        p[i++] = '\0'; // set rest of string to '\0'
    

    以下是全部代码:

    #include <iostream>
    
    const int ArSize = 80;
    
    char * left(const char * str, int n = 1);
    
    int main()
    {
        using namespace std;
        char sample[ArSize];
    
        cout << "Enter a string:\n";
    
        cin.get(sample,ArSize);
    
        char *ps = left(sample, 4);
        cout << ps << endl;
    
        delete [] ps; // free old string
    
        ps = left(sample);
        cout << ps << endl;
    
        delete [] ps; // free new string
        return 0;
    }
    // This function returns a pointer to a new string
    // consisting of the first n characters in the str string.
    char * left(const char * str, int n)
    {
        if(n < 0)
            n = 0;
    
        char * p = new char[n+1];
        int i;
    
        for (i = 0; i < n && str[i]; i++)
            p[i] = str[i]; // copy characters
    
        while (i <= n)
            p[i++] = '\0'; // set rest of string to '\0'
    
        return p;
    }
    

    我在删除代码后运行了它,没有问题。

    1 回复  |  直到 7 年前
        1
  •  3
  •   besc    7 年前

    循环是不必要的。以Null结尾的字符串以第一个Null字节结尾。如果分配的内存比实际字符串所需的内存多,那么这些额外字节中的内容并不重要。所有未中断的C字符串处理代码都会在第一个空终止符处停止。所需的只是一个

    p[i] = '\0';
    

    之后 for 环但是,一个空字节是必需的。C-string函数依赖于它,如果缺少它,它会很高兴地溢出分配的内存。本质上,它们会(尝试)继续运行,直到在内存中偶然发现下一个空字节。如果超过了分配的内存,它会导致未定义的行为,如果幸运的话会导致崩溃;如果你运气不好的话,数据也会被破坏。

    也就是说: 昨天把那本书扔掉。 代码从头到尾都是一场灾难。它几乎没有C++的资格。大多数都是普通的C语言,即使是C语言代码,它也是非常可疑的。

    • Why to avoid using namespace std @vol7ron在评论中指出,主要投诉是针对 using namespace std 在里面 标题 .在这里,它用于 .cpp 文件,从而显著减少了影响。虽然在我看来,这仍然值得避免。如果你不知道你的标准库的具体实现,你就不会真正了解你的范围内所有的符号。如果你需要它的可读性,拉在特定的符号(例如。 using std::cout; )是更好的选择。此外,我相信我并不是唯一一个期待未来的人 std:: 前缀例如 std::string 这就是我期待看到的。 string 看起来有点不对劲。人们一直怀疑它可能不是std库字符串,而是一种自定义字符串类型。所以,包括前缀可以 利益 可读性也很好。
    • 为什么所有的C弦都痛?我们有 std::string 暂时
    • 在循环中复制字符?认真地就是这样 std::strcpy() 是给你的。
    • 未经加工的 new delete 无处不在:容易出错,因为您必须手动跟踪新/删除对,以避免内存泄漏。
    • 更糟糕的是:不对称拥有原始指针。 left() 分配并返回指针;这就是 来电者 删除它的责任。没有比这更容易出错的了。

    这些只是第一眼看到的问题。

    这段代码应该是什么样子的:

    #include <iostream>
    #include <string>
    
    std::string left(const std::string& str, std::size_t len = 1);
    
    int main()
    {
        // getline can fail. If that happens we get an empty string.
        std::string sample;
        std::getline(std::cin, sample);
    
        auto ps = left(sample, 4);
        std::cout << ps << '\n';
    
        ps = left(sample);
        std::cout << ps << '\n';
    
        return 0;
    }
    
    // `len` may be longer than the string. In that case a copy
    // of the complete input string is returned.
    std::string left(const std::string& str, std::size_t len)
    {
        return str.substr(0, len);
    }