I want to write an Item to a binary file, close it, and open it again to read it. The code is simple and straightforward, it compiled and ran without error using Visual Studio 2008.
However, it got 'segment fault' when running with the GCC compiler.
What am I doing wrong?
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
class Item
{
private:
string itemID;
string itemName;
string itemState;
public:
Item( const string& id = "i0000", const string& name = "Zero item", const string& state = "not init" )
: itemID( id ) , itemName( name ) , itemState( state )
{
}
string& operator []( int x )
{
if ( 0 == x )
return itemID;
if ( 1 == x )
return itemName;
if ( 2 == x )
return itemState;
return ( string& )"";
}
const string& operator []( int x ) const
{
if ( 0 == x )
return itemID;
if ( 1 == x )
return itemName;
if ( 2 == x )
return itemState;
return ( string& )"";
}
public:
friend istream& operator >>( istream& i, Item& rhs )
{
cout << " * ItemID: ";
getline( i, rhs.itemID );
cout << " - Item Name: ";
getline( i, rhs.itemName );
cout << " - Item State: ";
getline( i, rhs.itemState );
return i;
}
friend ostream& operator <<( ostream& o, const Item& rhs )
{
return o << "ID = " << rhs.itemID
<< "\nName = " << rhs.itemName
<< "\nState = " << rhs.itemState << endl;
}
};
void write_to_file( const string& fn, const Item& item )
{
fstream outf( fn.c_str(), ios::binary | ios::out );
Item temp( item );
outf.write( reinterpret_cast<char *>( &temp ), sizeof( Item ) );
outf.close();
}
void read_from_file( const string& fn, Item& item )
{
fstream inf( fn.c_str(), ios::binary | ios::in );
if( !inf )
{
cout << "What's wrong?";
}
Item temp;
inf.read( reinterpret_cast<char *>( &temp ), sizeof( Item ) );
item = temp;
inf.close();
}
int main()
{
string fn = "a.out";
//Item it( "12", "Ipad", "Good" );
//write_to_file( fn, it );
Item temp;
read_from_file( fn, temp );
cout << temp;
return 0;
}
The two lines:
outf.write( reinterpret_cast<char *>( &temp ), sizeof( Item ) );
and
inf.read( reinterpret_cast<char *>( &temp ), sizeof( Item ) );
are wrong. You are writing the binary layout of the object, including std::string instances. This means you are writing the value of pointers to a file and reading them back.
You cannot simply read pointers from a file and assume they point to valid memory, especially if it was held by a temporary std::string instance, which should have freed the memory in it's destructor when it went out of scope. I'm surprised you got this to run "correctly" with any compiler.
Your program should write the content and read it back using your operator<< and operator>> methods. It should look like the following:
void write_to_file( const string& fn, const Item& item )
{
fstream outf( fn.c_str(), ios::binary | ios::out );
outf << item << std::endl;
outf.close();
}
void read_from_file( const string& fn, Item& item )
{
fstream inf( fn.c_str(), ios::binary | ios::in );
if( !inf )
{
cout << "What's wrong?";
}
inf >> item;
inf.close();
}
BONUS: There are a few quirks with your code.
This statement is, thankfully, presently unused in your program (the method is not called).
return ( string& )"";
It is invalid because you will be returning a reference to a temporary string object. Remeber that a string literal "" is not a std::string object and you can't get a reference to it of type std::string&. You should probably raise an exception, but you could get away with:
string& operator []( int x )
{
static string unknown;
if ( 0 == x )
return itemID;
if ( 1 == x )
return itemName;
if ( 2 == x )
return itemState;
return unkonwn;
}
This is a poor solution given that the string is returned by reference. It can be modified by the caller, so it might not always return the "" value you thought it would. However, it will remove undefined behavior for your program.
The .close() method invocations on std::fstream objects are not necessary, the destructor calls it automagically when the object goes out of scope. Inserting the call there is extra clutter.
Also, what's with the redundant naming convention?
class Item
{
private:
string itemID;
string itemName;
string itemState;
// ...
};
What's wrong with calling them ID, name and state?
Related
I want to write an Item to a binary file, close it, and open it again to read it. The code is simple and straightforward, it compiled and ran without error using Visual Studio 2008.
However, it got 'segment fault' when running with the GCC compiler.
What am I doing wrong?
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
class Item
{
private:
string itemID;
string itemName;
string itemState;
public:
Item( const string& id = "i0000", const string& name = "Zero item", const string& state = "not init" )
: itemID( id ) , itemName( name ) , itemState( state )
{
}
string& operator []( int x )
{
if ( 0 == x )
return itemID;
if ( 1 == x )
return itemName;
if ( 2 == x )
return itemState;
return ( string& )"";
}
const string& operator []( int x ) const
{
if ( 0 == x )
return itemID;
if ( 1 == x )
return itemName;
if ( 2 == x )
return itemState;
return ( string& )"";
}
public:
friend istream& operator >>( istream& i, Item& rhs )
{
cout << " * ItemID: ";
getline( i, rhs.itemID );
cout << " - Item Name: ";
getline( i, rhs.itemName );
cout << " - Item State: ";
getline( i, rhs.itemState );
return i;
}
friend ostream& operator <<( ostream& o, const Item& rhs )
{
return o << "ID = " << rhs.itemID
<< "\nName = " << rhs.itemName
<< "\nState = " << rhs.itemState << endl;
}
};
void write_to_file( const string& fn, const Item& item )
{
fstream outf( fn.c_str(), ios::binary | ios::out );
Item temp( item );
outf.write( reinterpret_cast<char *>( &temp ), sizeof( Item ) );
outf.close();
}
void read_from_file( const string& fn, Item& item )
{
fstream inf( fn.c_str(), ios::binary | ios::in );
if( !inf )
{
cout << "What's wrong?";
}
Item temp;
inf.read( reinterpret_cast<char *>( &temp ), sizeof( Item ) );
item = temp;
inf.close();
}
int main()
{
string fn = "a.out";
//Item it( "12", "Ipad", "Good" );
//write_to_file( fn, it );
Item temp;
read_from_file( fn, temp );
cout << temp;
return 0;
}
The two lines:
outf.write( reinterpret_cast<char *>( &temp ), sizeof( Item ) );
and
inf.read( reinterpret_cast<char *>( &temp ), sizeof( Item ) );
are wrong. You are writing the binary layout of the object, including std::string instances. This means you are writing the value of pointers to a file and reading them back.
You cannot simply read pointers from a file and assume they point to valid memory, especially if it was held by a temporary std::string instance, which should have freed the memory in it's destructor when it went out of scope. I'm surprised you got this to run "correctly" with any compiler.
Your program should write the content and read it back using your operator<< and operator>> methods. It should look like the following:
void write_to_file( const string& fn, const Item& item )
{
fstream outf( fn.c_str(), ios::binary | ios::out );
outf << item << std::endl;
outf.close();
}
void read_from_file( const string& fn, Item& item )
{
fstream inf( fn.c_str(), ios::binary | ios::in );
if( !inf )
{
cout << "What's wrong?";
}
inf >> item;
inf.close();
}
BONUS: There are a few quirks with your code.
This statement is, thankfully, presently unused in your program (the method is not called).
return ( string& )"";
It is invalid because you will be returning a reference to a temporary string object. Remeber that a string literal "" is not a std::string object and you can't get a reference to it of type std::string&. You should probably raise an exception, but you could get away with:
string& operator []( int x )
{
static string unknown;
if ( 0 == x )
return itemID;
if ( 1 == x )
return itemName;
if ( 2 == x )
return itemState;
return unkonwn;
}
This is a poor solution given that the string is returned by reference. It can be modified by the caller, so it might not always return the "" value you thought it would. However, it will remove undefined behavior for your program.
The .close() method invocations on std::fstream objects are not necessary, the destructor calls it automagically when the object goes out of scope. Inserting the call there is extra clutter.
Also, what's with the redundant naming convention?
class Item
{
private:
string itemID;
string itemName;
string itemState;
// ...
};
What's wrong with calling them ID, name and state?
I want to keep track of the linenumber in a istream and therefore wanted to use a streambuffer filter:
class LineNumberStreambuf : public std::streambuf
{
std::streambuf* mySource;
std::istream* myOwner;
bool myIsAtStartOfLine;
int myLineNumber;
char myBuffer;
protected:
int underflow()
{
int ch = mySource->sbumpc();
if ( ch != EOF ) {
myBuffer = ch;
setg( &myBuffer, &myBuffer, &myBuffer + 1 );
if ( myIsAtStartOfLine ) {
++ myLineNumber;
}
myIsAtStartOfLine = myBuffer == '\n';
}
return ch;
}
public:
LineNumberStreambuf( std::streambuf* source )
: mySource( source )
, myOwner( nullptr )
, myIsAtStartOfLine( true )
, myLineNumber( 0 )
{
}
LineNumberStreambuf( std::istream& owner )
: mySource( owner.rdbuf() )
, myOwner( &owner )
, myIsAtStartOfLine( true )
, myLineNumber( 0 )
{
myOwner->rdbuf( this );
}
~LineNumberStreambuf()
{
if ( myOwner != nullptr ) {
myOwner.rdbuf( mySource );
}
}
int lineNumber() const
{
return myLineNumber;
}
};
Source: https://stackoverflow.com/a/24861313/7483073
When i try to read istreams current position via tellg() it fails after applying the stream buffer filter:
int main()
{
std::istringstream input("i am a dummy test string");
std::cout << input.tellg() << std::endl; //prints 0
char c;
input >> c;
std::cout << input.tellg() << std::endl; //prints 1
LineNumberStreambuf ln(input);
std::cout << input.tellg() << std::endl; //prints -1 ??
return 0;
}
Edit:
I still couldn't find out why tellg() returns -1 after redirecting the streambuffer. The strange thing is that reading from istream is still possible. How can this be, if tellg() returns an invalid position?
I have a file, at the end of each line there is possibly a newline:
111\n
100\n
101
In C++ you can load the lines of a file into an array of byte strings like this:
auto lines_from( istream& is )
-> vector<string>
{
string line;
vector<string> result;
while( getline( is, line ) )
{
result.push_back( line );
}
return result;
}
auto main() -> int
{
vector<string> const lines = lines_from( cin );
// Use it.
}
Here string is std::string from the <string> header, getline is std::getline from the same header, and vector is std::vector from the <vector> header. I chose to use a descriptive name for the function, lines_from. However, it's commonly named readall.
Where you absolutely need a char**, presumably with an assumption of some given buffer size for each string, then you can use a vector of pointers, pointing to buffers that e.g. are managed by a class like this:
class C_strings
{
private:
vector<string> buffers_;
vector<char*> pointers_;
int bufsize_;
C_strings( C_strings const& ) = delete;
auto operator=( C_strings const& ) -> C_strings& = delete;
public:
auto pointer() -> char** { return pointers_.data(); }
auto bufsize() const -> int { return bufsize_; }
C_strings( vector<string> const& strings, int const bufsize )
: buffers_( strings )
, bufsize_( bufsize )
{
pointers_.reserve( buffers_.size() + 1 );
for( string& s : buffers_ )
{
s.reserve( bufsize );
if( s.empty() or s.back() != '\0' ) { s += '\0'; }
pointers_.push_back( &s[0] );
}
pointers_.push_back( nullptr );
}
C_strings( C_strings&& other )
: buffers_( move( other.buffers_ ) )
, pointers_( move( other.pointers_ ) )
{}
};
Then let's say you want to call a double-star function like this:
void doublestarfunc( char** const lines )
{
using std::cout;
for( char** pps = lines; *pps != nullptr; ++pps )
{
if( strlen( *pps ) < 40 ) { strcat( *pps, " < Oh la la!" ); }
cout << *pps << '\n';
}
cout << '\n';
}
It can be done very simply:
using namespace std; // cin, cout
int const columns = 80;
int const cstring_bufsize = columns + 1;
auto c_strings = C_strings( lines_from( cin ), cstring_bufsize );
doublestarfunc( c_strings.pointer() );
But is it a good idea? No, except when you have to relate to an existing C style API. For C++ code, better restructure it to use C++ std::string throughout.
I'm designing a simple program that takes an object of the Symbol class which I have defined and inserts into a HashTable. I've been given the HashTable.h file which came from our textbook and as you'll see, it is designed to be able to handle any object.
I'm trying to insert my object via:
hashtable.insert(&temp) //where temp is the object
However, I'm getting these errors:
Driver.cpp: In function 'int main()':
Driver.cpp:127:27: error: no matching function for call to 'HashTable<Symbol>::insert(Symbol*)'
Driver.cpp:127:27: note: candidates are:
In file included from Driver.cpp:12:0:
SeperateChaining.h:50:10: note: bool HashTable<HashedObj>::insert(HashedObj&) [with HashedObj = Symbol]
SeperateChaining.h:50:10: note: no known conversion for argument 1 from 'Symbol*' to 'Symbol&'
SeperateChaining.h:72:10: note: bool HashTable<HashedObj>::insert(HashedObj&&) [with HashedObj = Symbol]
SeperateChaining.h:72:10: note: no known conversion for argument 1 from 'Symbol*' to 'Symbol&&'
Would you guys mind taking a look?
EDIT: When I try to insert by value as many of you suggested, I get back a ton of garbage but parsed out for errors there are two:
opt/local/include/gcc47/c++/bits/stl_algo.h:135:7: error: no match for 'operator==' in '__first.std::_List_iterator<_Tp>::operator*<Symbol>() == __val'
and
opt/local/include/gcc47/c++/bits/stl_algo.h:135:7: error: no match for 'operator==' in '__first.std::_List_iterator<_Tp>::operator*<Symbol>() == __val' –
Here's my driver file and hash table.h file:
Driver.cpp:
#include <iostream>
#include <iomanip>
#include <cassert>
#include <fstream>
#include <string>
#include <vector>
#include <time.h>
#include <unistd.h>
#include <map>
#include <cstdlib>
#include <cmath>
#include "SeperateChaining.h"
//#include "hash_chn.h"
using namespace std;
int TABLE_SIZE; //I know it's a global, but it allows the Table Size to be taken in within main() and used in hash()
size_t hash(const string & key);
class Symbol
{
private:
int key;
int type;
string data;
public:
const string & getData() const
{
return data;
}
int getType()
{
return type;
}
int getKey()
{
return labs(key);
}
void setType(int Type)
{
type = Type;
}
void setData(string Data)
{
data = Data;
}
void setKey(int Key)
{
key = Key;
}
};
int main()
{
HashTable<Symbol> hashtable(TABLE_SIZE);
Symbol temp;
vector<Symbol> symbols;
string s;
int t;
int hash_key_array[TABLE_SIZE]; //array to hold hash key values
ifstream file;
file.open("symbols.txt");
if(!file)
{
cout << "System failed to open file.";
}
else
{
cout << "File successfully opened" << endl;
}
//for loop to read in the string name and the integer that follows the string name from symbols.txt
while(file >> s)
{
temp.setData(s);
file >> t;
temp.setType(t);
symbols.push_back(temp);
}
for(int i = 0; i < symbols.size(); i++)
{
cout << symbols[i].getData() << "\n";
cout << symbols[i].getType() << "\n";
}
cout << "What would you like the table size to be?" << endl;
cout << "Note: If the table size is greater than the number of objects" <<
" in the symbols.txt file, it will inevitably throw a segmentation fault" << endl;
cin >> TABLE_SIZE;
for(int j = 0; j < TABLE_SIZE; j++)
{
temp.setData(symbols[j].getData());
cout << temp.getData() << endl;
temp.setType(symbols[j].getType());
cout << temp.getType() << endl;
temp.setKey(::hash(symbols[j].getData()));
cout << "The key is: " << temp.getKey() << endl;
cout << endl;
hash_key_array[j] = temp.getKey();
for (int i = 0; i < TABLE_SIZE; i++)
{
if (i != j)
{
if (hash_key_array[i] == hash_key_array[j])
{
cout << endl;
cout << "Collision occurred at " << hash_key_array[i] << endl;
//rehash();
//cout << "The new key is: " << temp.getKey() << endl;
break;
}
}
}
hashtable.insert(&temp); //problem is here
}
}
size_t hash(const string & key)
{
size_t hashVal = 0;
for(char ch : key)
{
hashVal = 37 * hashVal + ch;
}
return labs(hashVal);
}
SeperateChaining.h:
#ifndef SEPARATE_CHAINING_H
#define SEPARATE_CHAINING_H
#include <vector>
#include <list>
#include <string>
#include <algorithm>
#include <functional>
//#include "Hash.h"
using namespace std;
// SeparateChaining Hash table class
//
// CONSTRUCTION: an approximate initial size or default of 101
//
// ******************PUBLIC OPERATIONS*********************
// bool insert( x ) --> Insert x
// bool remove( x ) --> Remove x
// bool contains( x ) --> Return true if x is present
// void makeEmpty( ) --> Remove all items
template <typename HashedObj>
class HashTable
{
public:
//Uses the whatever value table_size has
//Otherwise, it will make a hash table of size 101
explicit HashTable( int TABLE_SIZE )
{
currentSize = 0;
theLists.resize(TABLE_SIZE);
}
bool contains( const HashedObj & x ) const
{
//represents the correct list in the hash table vector to start looking through
auto & whichList = theLists[ myhash( x ) ];
//returns whatever you wanted to search for in the table provided it is there
return find( begin( whichList ), end( whichList ), x ) != end( whichList );
}
void makeEmpty( )
{
for( auto & thisList : theLists )
thisList.clear( );
}
bool insert(HashedObj & temp )
{
//represents the correct list in the hash table vector to start looking through
auto & whichList = theLists[myhash( temp )];
//goes through the beginning and end of the list, and if it
//doesn't get to the end, then it found the object you wanted to insert in the hash table already
//prevents duplicate insertions
if( find( begin( whichList ), end( whichList ), temp ) != end( whichList) )
return false;
//otherwise, it has gotten to the end of the list without finding a duplicate
//and puts what you want to insert in the list
whichList.push_back( temp );
// Rehash; see Section 5.5
if( ++currentSize > theLists.size( ) )
rehash( );
return true;
}
bool insert( HashedObj && x )
{
auto & whichList = theLists[ myhash( x ) ];
if( find( begin( whichList ), end( whichList ), x ) != end( whichList ) )
return false;
whichList.push_back( std::move( x ) );
// Rehash; see Section 5.5
if( ++currentSize > theLists.size( ) )
rehash( );
return true;
}
bool remove( const HashedObj & x )
{
//represents the correct list in the hash table vector to start looking through
auto & whichList = theLists[ myhash( x ) ];
//trying to find x within the list
//the iterator points to the slot in the list that contains x
auto itr = find( begin( whichList ), end( whichList ), x );
//if it gets to the end of the list without finding what you want to remove, then it returns false
if( itr == end( whichList ) )
{
return false;
}
//if it finds x, it removes it from the list
whichList.erase( itr );
--currentSize;
return true;
}
/*
void printTable()
{
for(int i=0; i < symbols.size(); i++)
{
cout << "The hash table contains: " << symbols[i] << endl;
}
}
*/
private:
vector<list<HashedObj>> theLists; // The array of Lists
int currentSize;
void rehash( )
{
vector<list<HashedObj>> oldLists = theLists;
// Creates new double-sized, empty table
theLists.resize( nextPrime( 2 * theLists.size( ) ) );
for( auto & thisList : theLists )
thisList.clear( );
// Copies the old table into the new table
currentSize = 0;
for( auto & thisList : oldLists )
for( auto & x : thisList )
insert( std::move( x ) );
}
size_t myhash( const HashedObj & x ) const
{
static hash<HashedObj> hf;
return hf( x ) % theLists.size( );
}
};
#endif
hashtable.insert(&temp)
You have to insert by value, not by pointer. Remove the & operator.
hashtable.insert(&temp);
^
You are trying to insert an address of temp. This is what this error says:
note: bool HashTable::insert(HashedObj&) [with HashedObj =
Symbol] note: no known conversion for argument 1 from 'Symbol*' to
'Symbol&'
There is a version of insert that takes a reference as its argument. So instead of pointer insert the object by value:
hashtable.insert(temp);
Look at the errors you are getting:
SeperateChaining.h:50:10: note: bool HashTable<HashedObj>::insert(HashedObj&) [with HashedObj = Symbol]
SeperateChaining.h:50:10: note: no known conversion for argument 1 from 'Symbol*' to 'Symbol&'
SeperateChaining.h:72:10: note: bool HashTable<HashedObj>::insert(HashedObj&&) [with HashedObj = Symbol]
SeperateChaining.h:72:10: note: no known conversion for argument 1 from 'Symbol*' to 'Symbol&&'
This is telling you that you are calling insert with a Symbol* and the function insert takes either a Symbol& or a Symbol&&.
So, let's look at the code where you call insert:
hashtable.insert(&temp); //problem is here
Sure enough, you are using & which is the address-of operator which will take the address of temp, which is of type Symbol, returning a pointer to it (which is, of course, of type Symbol*). So you're calling the function with Symbol*, which is not what the functions expect.
Sidenote: your implementation has a few other issues that you will need to sort through. Ask yourself what is temp and what does the HashTable class do with the l- and r-value references to Symbol that it accepts?
I'm using c++ to manipulate txt files.
I need to write some numbers with a certain precision so I'm doing:
ofstrem file;
file.open(filename, ios::app);
file.precision(6);
file.setf(ios::fixed, ios::floafield);
//writing number on the file.....
now I need to write other stuff, so I need to reset precision.
how can I do it?
Retrieve the stream's original precision value first with precision(), store it, change it, do your insertions, then change it back to the stored value.
int main() {
std::stringstream ss;
ss << 1.12345 << " ";
std::streamsize p = ss.precision();
ss.precision(2);
ss << 1.12345 << " ";
ss.precision(p);
ss << 1.12345;
cout << ss.str(); // 1.12345 1.1 1.12345
}
Live demo.
There are two possible solutions. If you're handling a large block of
output which uses the same formatting parameters, you can use something
like this:
class IOSave
{
std::ios& myStream;
std::ios::fmtflags myFlags;
std::streamsize myPrecision;
char myFill;
public:
IOSave( std::ios& userStream )
: myStream( userStream )
, myFlags( userStream.flags() )
, myPrecision( userStream.precision() )
, myFill( userStream.fill() )
{
}
~IOSave()
{
myStream.flags( myFlags );
myStream.precision( myPrecision );
myStream.fill( myFill );
}
};
Just define an instance of it at the top of the block doing the output.
Most of the time, however, I'll be defining my own manipulator, which
derives from something like:
class StateSavingManipulator
{
mutable std::ios* myStream;
mutable std::ios::fmtflags mySavedFlags;
mutable int mySavedPrec;
mutable char mySavedFill;
virtual void setState( std::ios& stream ) const = 0 ;
protected:
StateSavingManipulator();
public:
virtual ~StateSavingManipulator();
void operator()( std::ios& stream ) const ;
};
inline std::ostream& operator<<(
std::ostream& out,
StateSavingManip const& manip)
{
manip( out ) ;
return out ;
}
inline std::istream&
operator>>(
std::istream& in,
StateSavingManip const& manip )
{
manip( in ) ;
return in ;
}
The implementation is a bit tricky, since you have to take into account
that if several manipulators are used in the same expression, the
compiler can construct them (and thus destruct them) in any order it
pleases. So:
namespace {
int getXAlloc() ;
int ourXAlloc = getXAlloc() + 1 ;
int getXAlloc()
{
if ( ourXAlloc == 0 ) {
ourXAlloc = std::ios::xalloc() + 1 ;
assert( ourXAlloc != 0 ) ;
}
return ourXAlloc - 1 ;
}
}
StateSavingManipulator::StateSavingManipulator()
: myStream( NULL )
{
}
StateSavingManipulator::~StateSavingManipulator()
{
if ( myStream != NULL ) {
myStream->flags( mySavedFlags ) ;
myStream->precision( mySavedPrec ) ;
myStream->fill( mySavedFill ) ;
myStream->pword( getXAlloc() ) = NULL ;
}
}
void StateSavingManipulator::operator()(
std::ios& stream ) const
{
void*& backptr = stream.pword( getXAlloc() ) ;
if ( backptr == NULL ) {
backptr = const_cast< StateSavingManip* >( this ) ;
myStream = &stream ;
mySavedFlags = stream.flags() ;
mySavedPrec = stream.precision() ;
mySavedFill = stream.fill() ;
}
setState( stream ) ;
}
The derived manipulator then does whatever it has to in its implementation of setState. Given this, you can write things like:
std::cout << FFmt( 6, 2 ) << someValue << std::endl;
without having to worry about saving and restoring the formatting state.
One solution:
std::streamsize oldPres = file.precision(2);
file.setf(ios::fixed, ios::floafield);
… code continues …
file.precision(oldPres);
file.unsetf(std::ios::fixed);