【问题标题】:C++ class with char pointers returning garbage带有返回垃圾的 char 指针的 C++ 类
【发布时间】:2010-03-08 21:50:48
【问题描述】:

我创建了一个类“Entry”来处理字典条目,但是在我的 main() 中,我创建了 Entry() 并尝试计算 char 类型的公共成员,但我得到了垃圾。当我在调试器中查看监视列表时,我看到了正在设置的值,但是一旦我访问这些值,就会出现垃圾。谁能详细说明我可能遗漏了什么?

#include  <iostream>

using  namespace  std;

class Entry
{
    public:
            Entry(const char *line);
            char *Word;
            char *Definition;
};

Entry::Entry(const char *line)
{
    char tmp[100];
    strcpy(tmp, line);

    Word = strtok(tmp, ",") + '\0';
    Definition = strtok(0,",") + '\0';
}

int  main()
{
    Entry *e = new Entry("drink,What you need after a long day's work");
    cout << "Word: " << e->Word << endl;
    cout << "Def: " << e->Definition << endl;
    cout << endl;

    delete e;
    e = 0;

    return  0;
}

【问题讨论】:

  • 我很惊讶还没有人提供“不要使用 char*,使用 std::string”的建议。在这里。
  • 来自该赋值的说明:“你不能使用 C++ 标准库提供的 std::string 类。对于字符串数据的存储,使用以零结尾的字符数组。”

标签: c++ string pointers


【解决方案1】:

WordDefinition 都指向 tmp,它已经超出范围,因此包含垃圾。

【讨论】:

  • +1 表示停止,在我之后重复 - '从现在开始我将使用 std::string'
  • @pm100 : 他不能在作业中使用 std::string。
  • 我的意思是他应该自始至终使用字符串,裸 char*s 只能作为最后的手段。 Entry.Word 将是字符串,构造函数将使用 find_first,...
【解决方案2】:

strtok() 返回指向其输入字符串的指针。您正在将堆栈上的缓冲区传递给它,该缓冲区在 Entry::Entry 返回后不再有效。

【讨论】:

    【解决方案3】:

    tmp 应该是一个类成员,用来保存 Word 和 Definition 指向的字符串。否则,正如提到的其他答案一样,一旦构造函数返回, tmp 将超出范围。 另一件事是您不应该将该字符添加到指针中。我假设您想在字符串中添加一个终止符,但在 C/C++ 中事情并非如此。实际上,您将 ASCII 值(零)作为偏移量添加到指针中,这什么都不做。如果您想要一个终止符,您需要更改指针指向的字符,而不是更改指针本身。但无论如何,strtok 已经在找到的每个标记的末尾放置了终止符 - 在这种情况下不需要这样做。

    所以,我的建议:

    #include  <iostream>
    
    using  namespace  std;
    
    class Entry
    {
        public:
                Entry(const char *line);
                char *Word;
                char *Definition;
    
        private:
                char buffer[100];
    
    
    };
    
    Entry::Entry(const char *line)
    {
        strncpy(buffer, line, sizeof buffer);
        buffer[sizeof buffer - 1] = '\0';
    
        Word = strtok(buffer, ",");
        Definition = strtok(0,",");
    }
    
    int  main()
    {
        Entry *e = new Entry("drink,What you need after a long day's work");
        cout << "Word: " << e->Word << endl;
        cout << "Def: " << e->Definition << endl;
        cout << endl;
    
        delete e;
        e = 0;
    
        return  0;
    }
    

    我将名称从 tmp 更改为 buffer,因为它不再是临时值。我还使用 strncpy 来防止缓冲区溢出。行缓冲区[sizeof buffer - 1] = '\0';是否存在,因为如果 line 大于缓冲区,则调用后不会有终止符。

    【讨论】:

      【解决方案4】:

      实际上,如果在你的任务限制范围内,我建议放弃char*strtok() 转而支持stringistringstreamgetline()

      #include <string>
      #include <sstream>
      #include <iostream>
      
      using namespace std;
      
      class Entry
      {
        public:
          Entry(const string& line);
          string Word;
          string Definition;
      };
      
      Entry::Entry(const string& line)
      {
        istringstream iss(line);
        getline(iss, Word, ',');
        getline(iss, Definition, ',');
      }
      
      int main()
      {
        Entry e = Entry("drink,What comes between \"eat\" and \"be merry\"");
        cout << "Word: " << e.Word << endl;
        cout << "Def: " << e.Definition << endl;
        cout << endl;
      
        return  0;
      }
      

      【讨论】:

      • 来自该赋值的说明:“你不能使用 C++ 标准库提供的 std::string 类。对于字符串数据的存储,使用以零结尾的字符数组。”
      • 太糟糕了,他们强迫你以凌乱的方式做事。我会留下这个答案,以防它对找到它的其他人有用。
      • 理解并能够处理 C 风格的字符串是一项非常有用的技能。你不会总是有一个工作的 C++ 环境。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-07-28
      • 2014-07-20
      • 1970-01-01
      相关资源
      最近更新 更多