【问题标题】:C-String implementation in C++ outputs incorrectlyC++ 中的 C-String 实现输出不正确
【发布时间】:2021-11-11 19:31:53
【问题描述】:

我最近正在研究一个问题,教 C++ 的新用户,我自己就是,如何使用 cstrings 以及与 C++ 中导入的字符串对象相比它们的不同实现。当我处理这个问题时,我遇到了一个错误,尽管将 cstring 的大小初始化为正在执行的操作的适当长度,但 cstring 的输出却很奇怪。

当我使用 cout 打印出 cstring 时,它会正确打印一些 cstring,但通常前几个字符是随机字符,与对 cstring 执行的操作无关。但是,我找到了一种方法可以明确地阻止这些字符被打印出来。但是,我很好奇为什么这样做以及这里的问题是什么。

我发现在打印 cstring 之前在其自己的行上添加 cout << ""; 解决了打印 cstring 时输出随机字符的问题。然而,这似乎只是一个临时解决方案,我正在寻找一种更有教育意义的方法来解决这个问题。

下面我包含了导致错误的代码。

#include <iostream>
#include <vector>
#include <string>
#include <cstring>

using namespace std;

int main() {
    vector<string> words = {"Hello,", "and", "welcome", "to", "the", "world", "of", "C++!"};
    
    // Calculate the total number of characters in the words vector 
    // (including an additional character for space)
    int length = 0;
    for(int i = 0; i < words.size(); i++) {
        length += words.at(i).length() + 1;
    }
    
    cout << ""; // Removing this line of code will cause the output to do strange things
    
    // Initialize the cstring to be of size length
    char cstring[length];
    // Build the cstring using cstring library functions
    for(int i = 0; i < words.size(); i++) {
        strcat(cstring, (words.at(i) + " ").c_str());
    }
    
    // Null-terminate the cstring
    cstring[length-1] = '\0';
    
    // Output the cstring
    cout << cstring << " " << strlen(cstring) << endl;
    
    return 0;
}

如果删除包含cout &lt;&lt; "";的代码行,输出看起来像这样,每次输出的开头都是随机数量和随机字符集:

`k+��你好,欢迎来到 39 岁的世界

但是,通过包含该行,我能够实现所需的输出:

您好,欢迎来到 C++ 世界! 39

【问题讨论】:

  • char cstring[length]; 不受标准 C++ 支持。
  • 您不会将cstring 初始化为任何特定的东西,因此它的内容是任意的。然后你 strcat 进入它,所以它会在其中找到第一个 null 并附加文本。将数组的第一个元素初始化为零。
  • 大概char cstring[length] 没有初始化为零,strcat 从现有字符串中的第一个空字符开始复制。但是char cstring[length] 不是标准的 C++,它是一个扩展。它不应该教给新的 C++ 用户。总而言之,您应该停止使用 c 字符串并坚持使用std::string。您绝对应该向新用户介绍 c 字符串。它不是应该常用的东西,很难正确使用,并且主要是为了向后兼容而存在的。它应该被认为是语言中更高级的部分。
  • 您可能应该找到一个更现代的资源来学习 C++。如果有帮助,2011 年之前的任何东西都应该被认为是过时的。
  • 这并没有解决问题,但在那些 for 循环中,您知道 i 是一个有效索引,因为您是这样编写的。您无需浪费时间使用words.at(i) 进行检查。只需使用words[i]

标签: c++ loops for-loop c-strings string-concatenation


【解决方案1】:

对于初学者来说,可变长度数组不是标准的 C++ 特性

// Initialize the cstring to be of size length
char cstring[length];

其次,您定义了一个未初始化的数组。所以使用 strcat 会调用未定义的行为

strcat(cstring, (words.at(i) + " ").c_str());

此声明

// Null-terminate the cstring
cstring[length-1] = '\0';

是多余的,因为函数strcat 还附加了终止零,前提是您声明的字符数组有一个空间来容纳零字符(并且您忘记为数组中的终止零保留空间)。

如果编译器支持变长数组,那么程序可以如下所示

#include <iostream>
#include <string>
#include <vector>
#include <cstring>

int main() 
{
    std::vector<std::string> words = 
    {
        "Hello,", "and", "welcome", "to", "the", "world", "of", "C++!"
    };
    
    // Calculate the total number of characters in the words vector 
    // (including an additional character for space)
    size_t length = words.size();

    for ( const auto &s : words ) length += s.length();
    
    // Initialize the cstring to be of size length
    char cstring[length + 1];
    cstring[0] = '\0';
    
    // Build the cstring using cstring library functions
    for ( const auto &s : words )
    {
        std::strcat( cstring, ( s + ' ' ).c_str() );
    }
    
    // Output the cstring
   std:: cout << cstring << ' ' << length << std::endl;
   
    return 0;
}

程序输出是

Hello, and welcome to the world of C++!  40

【讨论】:

    猜你喜欢
    • 2022-11-03
    • 2018-09-13
    • 1970-01-01
    • 1970-01-01
    • 2017-06-28
    • 1970-01-01
    • 2023-03-26
    • 2021-06-24
    • 1970-01-01
    相关资源
    最近更新 更多