【问题标题】:String gets chopped when converted to char* c++字符串在转换为 char* c++ 时被截断
【发布时间】:2013-03-24 11:34:15
【问题描述】:

正如标题所暗示的,我在将字符串转换为 char 数组时遇到了一些问题。

首先让我明确我需要这样做的原因,因为如果我的方法是错误的,我很乐意采取不同的方式。 (虽然我更希望答案可以直接关注手头的问题)

我有一个包含几行的文件。每行都有格式

b 12 3 4

d 4 1 5.71

...

我正在尝试做的是读取每一行(使用 getLine 并将其保存在字符串变量中)并将它们用空格分隔,以便将每个字母/数字分开。

为了实现这一点,我采用了 strtok 方法,该方法将 char* 作为参数

这种转换是出了问题的地方。

我采取了几种方法,但总是以相同的方式结束:

尝试 #1 - .data()

const char *converted = new char[(line.size()+1)];
//The sentence is complete in this cout!
cout << line << " -printed string\n";
converted = line.data();
converted[line.size()] = '\0';
//sentence no longer complete!
cout << converted << " -printed char array\n";

尝试 #2 .c_str()

char *converted;
//The sentence is complete in this cout!
cout << line << " -printed string\n";
converted = (char*)line.c_str();
//sentence no longer complete!
cout << converted << " -printed char array\n";

尝试 #3 复制()

char *converted = new char[(line.size()+1)];
//The sentence is complete in this cout!
cout << line << " -printed string\n";
copy(line.begin(), line.end(), converted);
//sentence no longer complete!
cout << converted << " -printed char array\n";

我在前面的代码中可能有一些语法错误。我是从记忆中做的,因为我在尝试不同的方法时删除了代码。关键是,使用 .data()、copy() 和 .c_str() 他们都编译了,并且都给出了相同的输出:

b 12 3 4 打印字符串

b 打印的字符数组

现在我已经完成了我的作业,显然这还不是第一次。我想我在某处读到过,可能发生的事情是所有这些方法都将空白空间“”解释为“\0”,因此它在读取“b”后就停止了。解决它的方法之一是使用 boost 库。

不幸的是,这不是我的选择。我正在开发一个不能依赖外部库的可交付成果。一些帮助将不胜感激。

提前致谢。

编辑

代码:

(...)
if (fh.is_open()){
    while (fh.good()){
        getline(fh,line);
        char *converted = new char[(line.size()+1)];
        cout << line << " -printed string\n";
        strcpy(converted, line.c_str());
        
        cout << converted << " -printed char array\n";
(...)

【问题讨论】:

    标签: c++ string char type-conversion tokenize


    【解决方案1】:

    #1和#2同样的错误,你必须复制字符,你所做的只是复制指针。

    替换

    converted = line.data();
    converted[line.size()] = '\0';
    

    strcpy(converted, line.c_str());
    

    尝试 #3 更好,但忘记添加空终止符。

    也许你应该研究使用 std::string 的标记化方法,那么你就不会有这些麻烦了。

    【讨论】:

    • 在这两种情况下都按照你说的做了。输出是一样的。它打印的只是'b'。我将看看标记化字符串。但我无法让它工作真的让我很烦恼。
    • 那么您的代码中的其他地方似乎可能存在错误。尝试发布完整的代码。顺便说一句,您猜测空格被解释为 '\0' 是不正确的。
    • 老实说,虽然我发布的是我现在拥有的代码的确切结构,但它并不完全是原样。事实是我没有直接从从文件中读取的行进行转换。我实际上是从包含文件中所有行的 std::vector 转换而来的。我认为以这种方式呈现代码会更混乱,所以我把它放在这个更简单的形式上。
    • 您在上面发布的代码是正确的。截断输出的唯一解释是您的向量中没有您认为拥有的字符串。我猜想在从文件读取到向量的过程中发生了一些你没想到的事情。
    • 我决定采纳你的最后一条建议并标记 std::string。它现在正在工作。感谢您的帮助
    【解决方案2】:

    现在你的代码的问题已经指出了

    如果您打算用空格分割字符串(行),那么您可能想要使用格式化输入而不是标记化。类似的东西(这未经测试)

    #include <sstream>
    #include <string>
    while (std::getline(infile, line))
    {
        std::istringstream iss(line);
        string token;
        while(iss >> token) { 
    
           // Do your thing on token
    
        }
    }
    

    根据您的需要对其进行修改。

    【讨论】:

    • 也许我会试着走这条路。尽管逐个字符地遍历文本并不完全理想,因为上面可能有浮点数和高数字。一个字一个字地把它们拼凑起来听起来很麻烦。
    • 不一定是字符。它可以是任何东西。如果你愿意,可以串起来。我已经修改了代码。
    • 据我所知,您没有理由回退到 c 字符串。由于您无论如何都在使用 c++,因此仅使用流来标记字符串就不会那么令人头疼了。
    • 你说得对,我一开始就应该这样做。我实现了一个拆分字符串功能,现在一切正常。感谢您的帮助!
    • +1 这个标记化问题的一个非常好的和简短的解决方案。
    【解决方案3】:

    例如尝试 #1 中的问题:

    • 内存泄漏:首先将指针设置为新分配的内存块,然后将指针重置为line.data()

    • 未定义行为:不允许修改std::string::data()std::string::c_str() 返回的指针指向的内容。它可能是您的字符串对象所持有的实际缓冲区的内部副本。

    为了将字符串拆分为由空格分隔的部分,您可以尝试以下方法:

    split(const std::string &line, char &letter, std::vector<double> &numbers) {
        typedef std::string::size_t size_t;
        size_t n = line.find(' ');
        if (n == std::string::npos || n > 1) {
            // there aren't any spaces or the first part contains
            // more than one letter!
            // bad case? throw something or return an error code
        }
        letter = line[0];
        size_t n2 = line.find(' ', n);
        while (n2 != std::string::npos) {
            numbers.push_back(str2double(line.substr(n, n2 - n)));
            n = n2;
            n2 = line.find(' ', n);
        }
    }
    

    我没有测试代码。可能是您必须将n + 1 写入find 的调用或类似的东西。而且str2double函数还要自己写。

    【讨论】:

      猜你喜欢
      • 2010-09-07
      • 1970-01-01
      • 1970-01-01
      • 2015-04-30
      • 2018-03-27
      • 2013-05-13
      • 2012-01-16
      • 2018-09-02
      • 1970-01-01
      相关资源
      最近更新 更多