C++ 而内循环为循环

C++ 而内循环为循环,c++,for-loop,while-loop,C++,For Loop,While Loop,我在一本书中读到了这个示例代码。我不明白为什么以下示例代码的函数声明的这一部分是必要的: while (i <= n) p[i++] = '\0'; // set rest of string to '\0' while(i循环是不必要的。以Null结尾的字符串在第一个Null字节处结束。如果分配的内存超过实际字符串需要的内存,则这些额外字节中的内容无关紧要。所有未中断的C字符串处理代码都会在第一个Null结尾处停止。只需一个 p[i] = '\0'; 在for循环之后。但是,

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

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

while(i循环是不必要的。以Null结尾的字符串在第一个Null字节处结束。如果分配的内存超过实际字符串需要的内存,则这些额外字节中的内容无关紧要。所有未中断的C字符串处理代码都会在第一个Null结尾处停止。只需一个

p[i] = '\0';
for
循环之后。但是,一个空字节是必需的。C字符串函数依赖于它,如果缺少它,它会很高兴地溢出分配的内存。基本上,它们会(尝试)继续,直到他们在内存中偶然发现下一个空字节。如果超过分配的内存,则会导致未定义的行为,如果幸运的话会导致崩溃;如果幸运的话,则会导致数据损坏

< > >强> >将该书扔掉。<强>代码是从第一行到最后一行的灾难。它几乎不符合C++的要求。大部分是纯C,甚至作为C代码,这也是非常可疑的。

  • @vol7ron在评论中指出,主要的抱怨是反对在头文件中使用命名空间std
。这里它被用在.cpp文件的函数中,这大大减少了影响。虽然在我看来这仍然值得避免。如果你不深入了解标准库的实现,你就不知道了“我真的不知道您将哪些符号引入范围。如果为了可读性需要,请引入特定符号(例如,
使用std::cout;
)是一个更好的选择。此外,我相信我不是唯一一个期待
std::
前缀的人。例如,
std::string
就是我期待看到的。
string
看起来有点不对劲。人们总是怀疑它可能不是std库字符串,而是自定义字符串类型。因此,包含前缀可以也有利于可读性
  • 为什么所有的C字串都痛?我们已经有一段时间了
  • 在循环中复制字符?真的吗?这就是
    std::strcpy()
    的用途
  • Raw
    new
    delete
    无处不在:容易出错,因为您必须手动跟踪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);
    }
    
    #包括
    #包括
    std::string left(常量std::string&str,std::size\u t len=1);
    int main()
    {
    //getline可能会失败。如果发生这种情况,我们将得到一个空字符串。
    std::字符串样本;
    std::getline(std::cin,样本);
    自动ps=左侧(样本,4);
    
    不需要循环,但是
    p[i++]如果要将
    p
    视为以null结尾的字节字符串,则需要使用='\0'
    。此外,请学习如何缩进代码。它很可能是在书中缩进的,虽然编译器不需要缩进,但它确实有助于人们阅读代码。而且while循环没有嵌套在for循环中-没有打开的大括号i紧跟在for语句的结尾之后),因此它只循环
    p[i]=str[i];
    这种混乱/不清晰是某些编码标准要求所有for/while/if/else语句在语句后面加上{}的原因即使只涉及一条语句,它们也会进行控制。阅读起来要简单得多。你可以用
    p[i]='\0';
    替换它,一个终止null应该是充分的。while循环是荒谬的。在
    for
    循环之后需要做的就是
    p[i]=0;
    以正确终止字符串。如果输入字符串
    str
    的长度小于
    n
    ,则为
    p
    分配的内存量也会过多。这是哪本书?无意冒犯,但他在main中设置了名称空间,这对于本示例来说似乎已经足够好了。虽然我喜欢提到的是cautious,特别是如果这是一本旧书,我不认为在函数中设置名称空间是一个糟糕的决定。是的,冲突的风险是现实,但代码的可读性也很重要。这本书是“C++初级读物Plus”斯蒂芬·普拉塔的第六版。@vol7ron Hm,也许抱怨
    使用名称空间std
    变得有点太自动化了。我仍然认为这是值得避免的。但这是一个小问题,我应该更新答案。
    #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);
    }