why am I getting the C version of getline()?

T

theronnightstar

I seem to be having a problem with getline(). I have tried to find it
on
google, but I'm not seeing the answer. The goal of this section of
code
is simply to read in a line from a file to a string according to the
conditions of the do...while statement.

/////code

void populate( vector<string>& unplayed_anagrams, string& word, const
ifstream& dict_word_list )
{
const int max_size = word.size() + 1;
int letters_left;
char word_array[max_size];
char test_word_array[max_size];
string measure_word = " ";
vector<int> used_letters;
vector<int>::iterator iter;

used_letters.clear();
memset( test_word_array, '\0', max_size);
memset( word_array, '\0', max_size);
strcpy( word_array, word.c_str() );

cout << "Please wait... Populating the arrays." << endl;

while( !dict_word_list.eof() )
{
letters_left = (max_size - 1 ) ;
do
{
getline( dict_word_list, measure_word ); //<-This is the
offending code
}
while((measure_word.size() > word.size() && measure_word.size() <
3) || measure_word == word);

\\\\\code

I have another section of code that does almost the same thing, with
the
exception that it works.

/////code

void load_words( string& word, ifstream& dict_file )
{
vector<string> temp_vector;
int random_num = 0;
int temp_size = 0;
string line = " ";

temp_vector.clear();

while( word.size() < 6 )
{
while( !dict_file.eof() )
{
getline( dict_file, line );
temp_vector.push_back( line );
++temp_size;
}
random_num = ( rand() % temp_size );
word = temp_vector[random_num];
}
}

\\\\\code

When I compile the code, I get a compile time error pointing to the
getline() in the first chunk of code.

/////error

jaag.cc: In function 'void
populate(std::vector<std::basic_string<char,
std::char_traits<char>, std::allocator<char> >,
std::allocator<std::basic_string<char, std::char_traits<char>,
std::allocator<char> > > >&, std::string&, const std::ifstream&)':
jaag.cc:126: error: invalid conversion from 'void*' to 'char**'
jaag.cc:126: error: cannot convert 'std::string' to 'size_t*' for
argument '2' to '__ssize_t getline(char**, size_t*, FILE*)'

\\\\\error

I was using these includes:

/////code

#include <iostream>
#include <vector>
#include <cstdlib>
#include <cctype>
#include <ctime>
#include <fstream>
#include <string>

\\\\\code

as best as I can figure it I am getting the C version of getline() in
the first one and the C++ version in the second one. I can't figure
it
out. That's not what I need. I want them both to be C++. Any help on
this
would be greatly appreciated.

Thanks

PS I am using gcc-4.1.2 on amd64-gentoo-linux. If you need, I can
post
the code that is calling these functions. Thanks again.
 
J

John Harrison

I seem to be having a problem with getline(). I have tried to find it
on
google, but I'm not seeing the answer. The goal of this section of
code
is simply to read in a line from a file to a string according to the
conditions of the do...while statement.

/////code

void populate( vector<string>& unplayed_anagrams, string& word, const
ifstream& dict_word_list )

Here is the error, drop the const

void populate( vector<string>& unplayed_anagrams, string& word,
ifstream& dict_word_list )

And of course in *both* your functions, you should have istream not
ifstream. Using istream in the function means the function can be used
with any input stream, i.e. ifstream, fstream, istringstream,
stringstream, cin, plus any others you care to define. Why limit your
function to reading files only?

john
 
T

theronnightstar

Thank you - it worked. I could have swore I tried that. *smacks self
in head*. Anyway, thanks. As for the function - I have no use for
anymore functionality. "Do one thing and do it well" from what I
understand. If I ever need it again, I should know more about it and
it shouldn't be too hard to modify.
 
J

John Harrison

Thank you - it worked. I could have swore I tried that. *smacks self
in head*. Anyway, thanks. As for the function - I have no use for
anymore functionality. "Do one thing and do it well" from what I
understand. If I ever need it again, I should know more about it and
it shouldn't be too hard to modify.

LOL, all you have to do is delete the 'f' from ifstream, not too hard?
And it's a good habit to get into, shows you understand one of the key
points of OO programming.

john
 
T

theronnightstar

LOL, all you have to do is delete the 'f' from ifstream, not too hard?
And it's a good habit to get into, shows you understand one of the key
points of OO programming.

john

I'll mark that one to you. I am still real new to anything past the
most basic aspects of C++. You say istream can be bound to any input
stream? I assume I don't have to set ios:: Correct?
 
J

John Harrison

I'll mark that one to you. I am still real new to anything past the
most basic aspects of C++. You say istream can be bound to any input
stream? I assume I don't have to set ios:: Correct?

Correct, when you declare a stream variable, you have to say ifstream,
stringstream or whatever kind of stream it is.

But when you write a function that reads some input you should always
declare the stream parameter as istream&, as in

void some_function_that_reads(istream& the_stream_to_read)
{
...
}

That way the function will work with any kind of input stream. Once you
understand, it's a no-brainer.

Technically the reason is that ifstream, fstream, istringstream, cin
etc. all inherit from istream, so any of them will bind to to istream&.

john
 
J

John Harrison

John said:
Correct, when you declare a stream variable, you have to say ifstream,
stringstream or whatever kind of stream it is.

But when you write a function that reads some input you should always
declare the stream parameter as istream&, as in

void some_function_that_reads(istream& the_stream_to_read)
{
...
}

That way the function will work with any kind of input stream. Once you
understand, it's a no-brainer.

Technically the reason is that ifstream, fstream, istringstream, cin
etc. all inherit from istream, so any of them will bind to to istream&.

john

Same goes for ostream& as well of course.

john
 
T

theronnightstar

Same goes for ostream& as well of course.

john

Nice - thanks for that very valuable lesson. I will have to make sure
I use that.

I still have a problem though. I put a few cout statements in as
visual checks, but it is still failing on the getline statement. No
compiler error, but the cout that should show what is in the string I
am reading into says nothing. . One line above the getline() is
another cout that does display what it is supposed to.

/////code

void populate( vector<string>& unplayed_anagrams, string& word,
ifstream& word_file )
{
const int max_size = word.size() + 1;
int letters_left;
char word_array[max_size];
char test_word_array[max_size];
string measure_word;
vector<int> used_letters;
vector<int>::iterator iter;

used_letters.clear();
memset( test_word_array, '\0', max_size);
memset( word_array, '\0', max_size);
strcpy( word_array, word.c_str() );
cout << "word_array in populate() is: "; //<-Debug statement
for(int z = 0; z < max_size; ++z) //<-Debug statement
{
cout << word_array[z]; //<-Debug statement
}
cout << endl; //<-Debug statement
cout << "Please wait... Populating the arrays." << endl;

do
{
letters_left = (max_size - 1 ) ;
cout << "\nletters_left is: " << letters_left << endl; //<-Debug
statement
do
{
if( word_file.is_open() ) //<-Debug statement
cout << "The word_file is open." << endl; //<-Debug statement -
works
getline( word_file, measure_word ); //<-Problem
cout << "\nmeasure_word in populate() is: " << measure_word <<
endl; //<-Debug statement - doesn't work
}
while( ( measure_word.size() > word.size() && measure_word.size() <
3 ) || measure_word == word );

strcpy( test_word_array, measure_word.c_str() );

I went back with the ifstream in the declaration though - is_open()
doesn't work otherwise.
 
J

John Harrison

Nice - thanks for that very valuable lesson. I will have to make sure
I use that.

I still have a problem though. I put a few cout statements in as
visual checks, but it is still failing on the getline statement. No
compiler error, but the cout that should show what is in the string I
am reading into says nothing. . One line above the getline() is
another cout that does display what it is supposed to.

The only explanation is that word_file isn't in the state you think it
is. Possibly it's already at the end of file. Possibly you were reading
something before and got an error. Possibly the file simply isn;t
positioned where you think it is. In any case it must be something about
how you used word_file before you call the populate function. Perhaps
you could post that code.
/////code

void populate( vector<string>& unplayed_anagrams, string& word,
ifstream& word_file )
{
const int max_size = word.size() + 1;
int letters_left;
char word_array[max_size];
char test_word_array[max_size];

Neither of the above two line are legal C++ because max_size is not a
compile time constant. I know it's a constant, but it's not a compile
time constant as the value must be worked out at runtime.

There is one compiler I know which allows this kind of code, but if you
try this code on a different compiler you will likely get an error.

john
 
T

theronnightstar

As you can tell I am trying to do a simple anagram game for my fiance.
She loves them and I thought it would be an excellent learning
exercise. I was very right, but this I can't figure out. I know there
are a million better ways to this, but like I said, I am on a quest to
learn by this. This is the full code as it runs (sorry about the
length):

/////code

#include <iostream>
#include <vector>
#include <cstdlib>
#include <cctype>
#include <ctime>
#include <fstream>
#include <string>

using namespace std;

void test_functions();
void test2(vector<string>& unplayed, vector<string>& played);
void load_words( string& word, istream& dict_file ); //Loads the words
from the dict_file to memory and chooses a game word
void populate( vector<string>& unplayed_anagrams, string& word,
ifstream& word_file );

void test_functions()
{
srand(time(0));
vector<string> unplayed_anagrams;
vector<string> played_anagrams;
string word;
ifstream file;
char again = 'y';

file.open("test_list");
unplayed_anagrams.clear();
played_anagrams.clear();

load_words(word, file);
cout << "\nChosen word is: " << word << endl;

populate(unplayed_anagrams, word, file); //<- Everthing is fine to
here

test2(unplayed_anagrams, played_anagrams);

string test_word;
here:
int y = 1;
while( y == 1 )
{
cout << "\nChoose an anagram: ";
getline(cin, test_word);
y = anagram_test(unplayed_anagrams, played_anagrams, test_word);
if( y == 1)
{
cout << "Anagram is not valid." << endl;
}
else
{
cout << "Anagram should be valid." << endl;
}
}
test2(unplayed_anagrams, played_anagrams);
cout << "\nTest more? ";
cin.get(again);
cin.ignore(1, '\n');
if( again == 'y' )
{
goto here;
}

}

void test2(vector<string>& unplayed, vector<string>& played)
{
vector<string>::iterator iter;

cout << "unplayed_anagrams are:" << endl;
int x = 1;
for( iter = unplayed.begin(); iter != unplayed.end(); ++iter)
{
cout << x << ". " << *iter << endl;
}
x = 1;
cout << "\nplayed_anagrams are:" << endl;
for( iter = played.begin(); iter != played.end(); ++iter)
{
cout << x << ". " << *iter << endl;
}
}
void populate( vector<string>& unplayed_anagrams, string& word,
ifstream& word_file )
{
const int max_size = word.size() + 1;
int letters_left;
char word_array[max_size];
char test_word_array[max_size];
string measure_word;
vector<int> used_letters;
vector<int>::iterator iter;

used_letters.clear();
memset( test_word_array, '\0', max_size);
memset( word_array, '\0', max_size);
strcpy( word_array, word.c_str() );
cout << "word_array in populate() is: ";
for(int z = 0; z < max_size; ++z)
{
cout << word_array[z];
}
cout << endl;
cout << "\nPlease wait... Populating the arrays." << endl;

do
{
letters_left = (max_size - 1 );
cout << "\nletters_left is: " << letters_left << endl; //<- Works
here
do
{
if( word_file.is_open() )
cout << "The word_file is open." << endl; //<-this displays
getline( word_file, measure_word );
cout << "\nmeasure_word in populate() is: " << measure_word <<
endl; //<-This does not
}
while( ( measure_word.size() > word.size() && measure_word.size() <
3 ) || measure_word == word );

strcpy( test_word_array, measure_word.c_str() );

for( int x1 = 0; x1 < max_size; ++x1)
{
for( int x2 = 0; x2 < max_size; ++x2 )
{
if( test_word_array[x2] == word_array[x1] )
{
for( iter = used_letters.begin(); iter != used_letters.end();
++iter )
{
if( x2 != *iter )
{
continue;
}
else
{
break;
}
}
if( iter == used_letters.end() )
{
used_letters.push_back(x1);
--letters_left;
}
else
{
continue;
}

}
else
{
continue;
}
}
}
if( letters_left == 0 )
{
string blah = test_word_array;
unplayed_anagrams.push_back(blah);
}
else
{
continue;
}
}
while( !word_file.eof() );
cout << "\nDone." << endl;
}
void load_words( string& word, istream& dict_file )
{
vector<string> temp_vector;
int random_num = 0;
int temp_size = 0;
string line = " ";

temp_vector.clear();

while( word.size() < 6 )
{
while( !dict_file.eof() )
{
getline( dict_file, line );
cout << line << endl;
temp_vector.push_back( line );
++temp_size;
}
random_num = ( rand() % temp_size );
word = temp_vector[random_num];
}
}

//irrelevant code removed

int main()
{
test_functions();
return 0;
}
 
J

John Harrison

As you can tell I am trying to do a simple anagram game for my fiance.
She loves them and I thought it would be an excellent learning
exercise. I was very right, but this I can't figure out. I know there
are a million better ways to this, but like I said, I am on a quest to
learn by this. This is the full code as it runs (sorry about the
length):

No problem. The issue is that you read the "test_list" all the way to
the end of file in load_words. It's still at the end of file when you
call populate. Even worse when you read past the end of file that puts
the stream into an error state. When a stream is in an error state
nothing works until you clear the error state.

Now I'm not sure exactly what you are trying to do, but I would guess
that you want to go back to the beginning of the file before you call
the populate function, so that populate starts reading from the
beginning of "test_list". If so then see the additional code below
/////code

#include <iostream>
#include <vector>
#include <cstdlib>
#include <cctype>
#include <ctime>
#include <fstream>
#include <string>

using namespace std;

void test_functions();
void test2(vector<string>& unplayed, vector<string>& played);
void load_words( string& word, istream& dict_file ); //Loads the words
from the dict_file to memory and chooses a game word
void populate( vector<string>& unplayed_anagrams, string& word,
ifstream& word_file );

void test_functions()
{
srand(time(0));
vector<string> unplayed_anagrams;
vector<string> played_anagrams;
string word;
ifstream file;
char again = 'y';

file.open("test_list");
unplayed_anagrams.clear();
played_anagrams.clear();

load_words(word, file);
cout << "\nChosen word is: " << word << endl;

// load_words has placed file in an error state
// since it read to end of file, so first thing
// to do is clear the error state
file.clear();

// now we want to start reading from the beginning
// of the file again, so seek to start of file
file.seekg(0, ios_base::beg);

// now (hopefully) everything should be OK
populate(unplayed_anagrams, word, file); //<- Everthing is fine to
here

john
 
T

theronnightstar

You are so absolutely the man. That solved it all. Thanks for the
lesson. I'll take it to heart. lol such a simple solution. Thanks
again.
Raymond
 
J

Jerry Coffin

[ ... ]
while( !word_file.eof() );

[ ... ]
while( !dict_file.eof() )

I haven't looked through all your code, but these jumped out at first
glance. For all practical purposes, a loop like this can never work
correctly. whatever.eof() only returns true when you attempt to read
from the file but you've _already_ read all the input. Usually, you need
to read the input, and check the return from that attempt to read, to
see whether it encountered the end of the file or not. A typical
(correct) loop would looks something like:

while (getline(dict_file, line)) {
cout << line << endl;
temp_vector.push_back(line);
++ temp_size;
}

Since it looks like you have quite a few places that you read strings a
line at a time, I'd consider writing a small proxy class that works that
way:

class line {
std::string data;
public:
operator std::string() const { return data; }

friend std::istream &operator>>(std::istream &is, line &l) {
return std::getline(is, l.data);
}
};

This allows you to read a line at a time using the normal stream
extraction operator (>>). stream_iterators use insertion and extraction
operators, so once you support them, you can use standard algorithms for
quite a bit of what you're doing. For example, I'd rewrite your
load_words something like this:

string load_words(string &word, istream &dict_file) {
vector<string> temp_vector;

// read data from file to vector:
copy(istream_iterator<line>(dict_file),
istream_iterator<line>(),
back_inserter(temp_vector));

// write data from vector to cout
std::copy(temp_vector.begin(), temp_vector.end(),
ostream_iterator<string>(std::cout, "\n"));

// return randomly chosen word
return temp_vector[rand() % temp_vector.size()];
}

I didn't look at it in detail, but I did notice that part of your code
uses strcpy -- chances are that you'd be better off using std::string
instead, in which case you can just use the assignment operator.

I should also add that if you're going to call load_words very often
(like anything more than once), it would generally be quite a bit better
to read the file only once during initialization, and from then on use
the data from memory.

As a general rule, I'd also advise that when you post code like this,
you provide at least some minimal explanation of 1) what you want it to
do, and 2) what it's not doing that you want it to (or what it's doing
that you don't want). It might be reasonable to assume people remember
your post from a few days ago in a newsgroup that gets only a half dozen
posts a week (or something on that order), but in a newsgroup this busy,
most people have to rely almost entirely on _this_ post to figure out
what it's about.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,962
Messages
2,570,134
Members
46,692
Latest member
JenniferTi

Latest Threads

Top