Re: How to load a text file into a char **?
James Kanze <james.kanze@gmail.com> wrote:
"Daniel T." <danie...@earthlink.net> wrote:
ampheta...@gmail.com wrote:
Is there a safe (unlikely to cause overflows or segfaults)
way to load a text file into a char ** array?
A char** array? Are you sure you got that right?
Maybe he needs to interface with some legacy C code.
(Otherwise, of course, std::vector< std::string > is the obvious
choice.)
A vector<string> would equate to a char* array, not a char** array.
char[] char_array = "hello world";
char*[] char_ptr_array = { "a", "b", "c" };
char**[] char_ptr_ptr_array = ?
Maybe the OP just messed up a bit in his terminology?
I thought of using getline, but it needs a fixed-length
string, and I don't know how many lines or characters per
line the file has.
The below is the same as what I had before, except the last step of
turning the vector<vector<char> > into a char** is added.
template < typename T >
struct PtrToFirst : unary_function< vector< T >, T* > {
T* operator()( vector< char >& vec ) const {
return &vec[0];
}
};
typedef vector< vector< char > > temp_type;
temp_type tmp;
string str;
while ( getline( file, str ) ) {
tmp.push_back( vector<char>( str.begin(), str.end() ) );
tmp.back().push_back( 0 ); // null terminate each line?
}
vector< char* > result;
transform( tmp.begin(), tmp.end(), back_inserter( result ),
PtrToFirst<char>() );
// or the above line could be done with:
//for ( temp_type::iterator it = tmp.begin(); it != tmp.end(); ++it )
// result.push_back( &it->at( 0 ) );
result.push_back( 0 );
char** wow = &vector[0]
I think he wants one string per line. But I'd still use a
vector of string for the reading, only converting into char**
once the file had been read, e.g.:
std::vector< std::string > tmp ;
std::string line ;
while ( std::getline( file, line ) ) {
tmp.push_back( line ) ;
}
std::vector< char const* > result ;
for ( std::vector< std::string >::const_iterator
iter = tmp.begin() ;
iter != tmp.end() ;
++ iter ) {
result.push_back( iter->c_str() ) ;
}
result.push_back( NULL ) ; // if needed.
// use &result[0].
(In fact, I just did exactly this yesterday, to interface with
openldap.)
Note that in this case, you cannot simply return &result[0], and
expect it to work. For obvious reasons, you must use &result[0]
before either tmp or result go out of scope. In a larger
application, the solution, I think would be to create a class
which contained these two members, contructed the above in its
constructor, and had a function to return the char**. (It the
needed type really is char**, as was the case with openldap,
you'll have to const_cast.)
I agree, but I say avoid the (multiple) const_casts by using a vector<
vector< char > > instead of a vector< string >.
Note that our solutions are remarkably similar. The only difference is
that I don't have to go through the extra step to remove the const.