Класс C ++ с указателями на символы, возвращающие мусор - PullRequest
3 голосов
/ 09 марта 2010

Я создал класс "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;
}

Ответы [ 4 ]

11 голосов
/ 09 марта 2010

Word и Definition указывают на tmp, который вышел из области видимости и содержит мусор.

4 голосов
/ 09 марта 2010

strtok () возвращает указатель на входную строку. Вы передаете ему буфер в стеке, который больше не действителен после возврата Entry :: Entry.

3 голосов
/ 09 марта 2010

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'; потому что, если строка больше буфера, после вызова у нее не будет терминатора.

1 голос
/ 09 марта 2010

На самом деле, если это в пределах ограничений вашего назначения, я бы рекомендовал отказаться от char* и strtok() в пользу string, istringstream и getline():

#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;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...