views:

266

answers:

4

I created a class "Entry" to handle Dictionary entries, but in my main(), I create the Entry() and try to cout the char typed public members, but I get garbage. When I look at the Watch list in debugger, I see the values being set, but as soon as I access the values, there is garbage. Can anyone elaborate on what I might be missing?

#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  A: 

strtok() returns a pointer into its input string. You are passing it a buffer on the stack, which is no longer valid after Entry::Entry returns.

crazyscot
+10  A: 

Word and Definition both point into tmp, which has gone out of scope and so contains garbage.

Paul R
+1. Almost verbatim what I was typing.
Fred Larson
+1 for dead on, repeat after me - 'I will use std::string from now on'
pm100
@pm100 : he can't use std::string in the assignment.
Hogan
what i meant was that he should use strings throughout , naked char*s should only be used as a last resort. Entry.Word would be string, constructor would use find_first,...
pm100
+3  A: 

tmp should be a class member, to hold the string that Word and Definition point to. Otherwise, as the other answers mentioned, tmp will get out of scope once the constructor returns. Another thing is that you shouldn't add that char to the pointers. I assume you wanted to put a terminator in the string, but things don't work that way in C/C++. In effect you are adding the ASCII value (zero) to the pointer as an offset, which does nothing. If you want a terminator you need to change the characters pointed by the pointer, not change the pointer itself. But strtok already puts terminators at the end of each token found, anyway - there's no need for that in this case.

So, my suggestion:

#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;
}

I changed the name from tmp to buffer, since it's not a temporary value anymore. I also used strncpy to prevent a buffer overflow. The line buffer[sizeof buffer - 1] = '\0'; is there because if line is bigger than buffer, it won't have the terminator after the call.

Fabio Ceconello
+1  A: 

Actually, if it's within the constraints of your assignment, I'd recommend abandoning char* and strtok() in favor of string, istringstream, and 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;
}
Fred Larson
From the instructions for this assignment: "You are not allowed to use the std::string class provided by the C++ Standard Library. For storage of string data, use zero-terminated character arrays."
JMP
It's too bad they force you to do things the messy way. I'll leave this answer in case it's useful for others who find it.
Fred Larson
Understanding and being able to deal with C-style strings is a very useful skill to have. You won't always have a working C++ environment.
crazyscot