I am unable to read an input from a file. Every time my code reaches strncpy, my code breaks and I am unable to figure out why. The code seems to break at the set name function.
fstream& AmaProduct::load(std::fstream& file){
char s[7];
char* n;
n = new char[7];
double p;
bool t;
int q;
int nn;
file.open("amaPrd.txt");
if (file.is_open()){
file.ignore(2);
file.getline(s,',');
cout << s;
sku(s);
file.ignore();
file.getline(n,',');
name(n);
file.ignore();
file >> p;
price(p);
file.ignore();
file >> t;
taxed(t);
file.ignore();
file >> q;
file.ignore();
quantity(q);
file.getline(unit_, ',');
file.ignore();
file >> nn;
qtyNeeded(nn);
}
file.close();
return file;
}
This is set here:
void Product::sku(char* sku){
strncpy(sku_,sku,7);
sku_[7]=0;
}
void Product::price(double price){
price_=price;
}
void Product::name(char* name){
delete[] name_;
name_= new char[strlen(name)+1];
strcpy(name_,name);
}
void Product::taxed(bool tax){
taxed_=tax;
}
void Product::quantity(int q){
quantity_=q;
}
void Product::qtyNeeded(int n){
qtyNeeded_=n;
sku being declared
char sku_[8]
I have been working on this for hours but have yet to find a solution.
Sorry for my previous answer that clearly wasn't correct.
A segmentation fault means your program is trying to access a memory location that doesn't belong to it. In other words, you're writing or reading a pointer that hasn't been (properly) initialized or is out of scope (plus a couple of other options that are less likely here).
You wrote that it crashes at strncpy, and its only reference is in the sku function. You have no "set name" function, but you have a strcpy call in the "name" function. Notice the difference between strncpy and strcpy.
Your function Product::sku(..) copies to sku_ using strncpy, but it is unclear where you are declaring it and whether it is in scope or has been initialized when Product::sku(..) runs. The main function is in a AmaProduct namespace (or class), while the others are in Product. Is that on purpose? In which namespace is sku_ declared?
The Product::name(char* name) function calls strcpy, which assumes that name is a zero-terminated string. Are you sure that it is zero-terminated? If not, it will continue to write and throw a segfault. It is probably also wise to add a maximum number of characters for file.getline() to read. The max number should correspond to the size of the destination buffer.
Also, it is considered unwise to name a function the same as a variable. Having clear and meaningful names makes it easier to see and debug the logic of your code.
Finally, see http://www.cprogramming.com/debugging/segfaults.html for more help on debugging.
Related
so basically I was trying to save a class inside a .dat file but in my code but it says this error No matching member function for call to 'open' but I put fstream header. I don't know if I'm writing something wrong. I use Xcode 10.
class memberinformation
{
string name; //name
long int phonenumber; // phone number
int memberid; // member id
public :
memberinformation()
{ name="not assigned" ;
phonenumber=0;
memberid=0;
}
int option3();
int option2();
int option1();
int option4();
};
void wrt_file() //file function
{
memberinformation k;
fstream f;
f.open ("information.dat",ios::app,ios::binary) //this is where I get the error.
f.write((char*)&k,sizeof(k));
}
You are lucky to have been stopped by a simple error. #Alex44 has already shown how to get rid of the error:
f.open ("information.dat",ios::app|ios::binary); //this is where I get the error.
But the following line is even worse:
f.write((char*)&k,sizeof(k));
because the compiler will not show any error, while the content of the string will not be saved in the file. std::string is not trivially copiable and because of that, the memberinformation class is not either. So you should not try to write it to a file as raw bytes.
You should instead write a serialization function that writes to a binary stream (just a possible serialization way):
phonenumber as a long int (no problem there)
memberid as an int (no problem there)
name.size as a size_t
name.data as name.size bytes
The other two answers have answered:
Why its not compiling.
Why its a bad idea to write binary objects.
I would suggest that you serialize the object via the standard C++ technique of using the stream operators. This makes writting/reading the objects trivial and usually makes debugging problems easy.
Using the format suggested by #serge-ballesta in his post:
class memberinformation
{
string name; //name
long int phonenumber; // phone number
int memberid; // member id
public :
// OLD STUFF GOES HERE
void swap(memberinformation& other) noexcept
{
using std::swap;
swap(name, other.name);
swap(phonenumber, other.phonenumber);
swap(memberid, other.memberid);
}
friend std::ostream& operator<<(std::ostream& str, memberinformation const& data)
{
return str << data.phonenumber << " "
<< data.memberid << " "
<< data.name.size() << " "
<< data.name << " ";
}
friend std::istream& operator<<(std::istream& str, memberinformation& data)
{
memberinformation tmp;
std::size_t nameSize
if (str >> tmp.phonenumber >> tmp.memberid >> nameSize) {
// All sizes were read correctly.
tmp.name.resize(nameSize);
if (str.ignore(1).read(&tmp.name[0], nameSize)) {
// ignored the space and read the name correctly.
// So now we update the "data" object
tmp.swap(data);
}
}
return str;
}
};
Now in your code:
int main()
{
memberinformation object;
std::cout << object;
std::cin >> object;
std::ofstream file("Data.dat");
file << object;
}
You miss a semicolon and you need to "bitwise or" your flags:
void wrt_file() //file function
{
memberinformation k;
fstream f;
f.open ("information.dat",ios::app|ios::binary); //this is where I get the error.
...
}
The answers above address your initial problem. I'm going to talk about two more.
First, you probably should f.close() at the end of your method. It may be perfectly fine to let it drop out of scope and clean up from there, but I personally think that's ugly, and I wouldn't count on it.
Second, I wouldn't store the data in binary unless there's a really good reason to do it. It won't be portable. Serge above suggests a serialization method. I'd consider an alternate approach. I'd write to the file in a human readable form such as JSON. Yes, it's a little more work, but...
-If you change your class, your old files will still be readable
-They are portable across environments
-You can actually look at them and readily understand what they contain
So Serge's suggestions above aren't horrible, but I'd pick a more modern serialization / deserialization style.
Note that your f.write won't work because your object contains other objects, you don't know how they work under the hood. That string, for instance, almost certainly can't be dumped the way you're trying to do it. Plus you aren't only dumping your data.
Also, you should printf the sizeof(k). You might find it interesting information. Try to account for every byte. You could printf the sizeof(k.name) to help you work some of it out.
I'm almost positive the information doing so would surprise you, but I haven't actually done it myself, because I would never try to raw memory copy C++ objects, and that's in effect what you're trying to do.
I am trying to reading and write objects to a file in C++, writing the object works fine, reading gives segmentation core dump. I have commented the code for writing objects to file, while writing we can uncomment that part and comment the reading part.
#include<iostream>
#include<fstream>
#include<string>
using namespace std;
class RelianceMart{
string name;
double trolley_number;
public:
RelianceMart(){
name = "NA";
trolley_number = 0;
}
RelianceMart(string name, double trolley_number){
this->name = name;
this->trolley_number = trolley_number;
}
void setname(string name){
this->name = name;
}
string getname(){
return name;
}
void settrolleynumber(double trolley_number){
this->trolley_number = trolley_number;
}
double gettrolleynumber(){
return trolley_number;
}
};
int main(){
string name;
double trl_num;
RelianceMart mart[3];
RelianceMart obj;
// ofstream fout("PersistentStorage.txt");
/*
for(int i=0;i<3;i++){
cin>>name;
cin>>trl_num;
mart[i] = RelianceMart(name, trl_num);
fout.write((char *) & mart[i], sizeof(mart[i]));
}
fout.close();
*/
ifstream fin("PersistentStorage.txt");
while(!fin.eof()){
fin.read((char *) & obj,sizeof(obj));
cout<< obj.getname();
}
fin.close();
return 0;
}
The members of std::string is really nothing more than a member variable for the length, and a member variable being a pointer to the actual string contents.
Pointers are private and unique to a specific process in all modern protected multi-tasking operating systems, no other process (not even one started from the same program) can reuse the same pointer.
When you write the RelianceMart objects, you write the pointer of the name string object to the file. As mentioned above no other process can use this pointer, and therefore can't read the file.
Furthermore when you attempt to read the raw objects, you read raw data overwriting the existing data in the constructed object, and the object won't be properly constructed anymore.
You also don't open the file in binary mode, which is wrong since you write and read raw binary data, not text.
The common solution is to use serialization, and the most common way to do it is simply to overload the "output" and "input" operators << and >>.
In the overloaded functions you simply write and read each object as text, again using the formatted << and >> operators.
Lastly, please read Why is iostream::eof inside a loop condition considered wrong?
I would use a serialization framework, you could use Google's Protocol Buffers(https://developers.google.com/protocol-buffers/).
If you consider a fullblown framework overkill, you can always write your own serialization framework, I've done that, I did use the JSON-format to encode the object.
I am trying to create class that reading and writing to the same file in c++ using template function and I'm trying to realize the function read() that reading a char or int and returns it and when i tried to run it i got number like -998324343 please help :)
#include<iostream>
#include<fstream>
using namespace std;
template <class T>
class myFile
{
ifstream in;
ofstream out;
public:
myFile(char* fileName)
{
in.open(fileName);
if (!in.is_open())
throw"couldnt open file to reading";
out.open(fileName);
if (!out.is_open())
throw"couldnt open file to writing";
cout << read();
}
T read() {
T x;
in >> x;
return x;
}
};
int main()
{
try {
myFile<int> a("read.txt");
}
catch (char* msg) {
cout << msg << endl;
}
}
Your out and in refer to the same file. So when this happens:
in.open(fileName);
if (!in.is_open())
throw"couldnt open file to reading";
out.open(fileName);
Assuming fileName exists as a file, out will truncate the file, so it becomes empty. The subsequent in >> x; will fail (because the file is empty) and depending on the C++ standard you're compiling against, either x will get zeroed out (since C++11) or remain unmodified (until C++11). I'm assuming you're compiling pre-C++11, in which case what you see is whatever indeterminate value x was initialized with.
Not sure what you need out for, but you either want it to refer to a different file or open it in append mode.
Regardless of whether or not out is truncating the file, the >> operation can fail. If it fails, you will get garbage data (or 0). So you need to check the result of that operation.
Note: Everywhere you are using char* you should be using const char*. The conversion from string literal to char* is deprecated (if you compiled with warnings enabled, you would see this).
as the title suggests, I am having a problem with not being able to read from an input file after passing the ifstream object to a class function. Basically I'm trying to sort a list of numbers using a heap ADT implemented with an array.
int main() {
ifstream infile("input.txt");
HeapSort* heap = new HeapSort(20); // creates a heap (array) with size 20
heap->buildHeap(&infile);
return 0;
}
void HeapSort::buildHeap(ifstream* infile) {
int data;
while (infile >> data) {cout << data << endl;}
infile->close();
}
the error occurs in the conditional of the while loop inside buildHeap. The compiler can't recognize the operator ">>" between an 'int' and an 'ifstream' object. However, strangely enough, if I write that same while loop inside main(), it'll work just fine. Also of note is that if I remove the while loop, the compiler returns no errors. Meaning, simply the act of passing the ifstream object from main to buildHeap is OK.
Please avoid suggesting alternative ways of achieving this. I was asked to not use any special fstream functions like eof(). I can only use the ">>" operator to read from the desired file.
You're passing a pointer to a stream, so you need to dereference it:
while (*infile >> data)
If you want your code to look like what you say you did in main, then you pass a reference:
heap->buildHeap(infile);
//...
void HeapSort::buildHeap(ifstream& infile)
{
int data;
while (infile >> data) { ... }
infile.close();
}
I've written a class that reads in a map. But I need the map to be editable outside of the class. So my question is how can I return a map.
class ReadMap
{
string fileName;
public:
//constructors and destructor
ReadMap(){fileName="blank.txt";}
ReadMap(string name){fileName=name;}
~ReadMap(){}
//Function to print out visible list
void show()
{
LineDatabase Entry;
int LineNumber=100;
string buffer;
ifstream myfile (fileName.c_str() );
while (myfile.good())
{
myfile >> LineNumber >> ws;
getline (myfile, buffer);
Entry.insert(pair<int, string>(LineNumber, buffer));
cout <<buffer << endl;
}
//return Entry;
}
};
You may be better off by having the caller of show() pass in a reference to the map to be filled, as returning a map tends to have high overhead. Something like this:
void show(LineDatabase& Entry) {
// do your map readin logic
return;
}
You return a map just like you return anything else—using the return keyword. If you're wondering why your commented out return doesn't work, it's because you declare show() as returning void. Change void show() to LineDatabase show().
Also, try to keep variable and type names lower-case. Typical convention is to use capitalized names for template parameters, so it is a bit confusing to read.
There are 4 options.
The simplest option is to change the return type of show and uncomment your return, however this will be returning the map by value which will involve a copy and could (depending upon size) be very inefficient (possibly dangerous, depending upon LineDatabase's copy operator).
LineDatabase show()
{
LineDatabase Entry;
// .... ommited
return Entry;
}
The 2nd option is to do as was suggested by user258808 and create a new object then return it by pointer, the issue with this approach is that your client would have to know to call delete on this pointer when finished otherwise you would be creating a leak.
The 3rd option is to have Entry as a field of ReadMap and then return a reference. This is my personal preference as it imposes the least burden on the client, however it may also require you to 'reset' the Entry before each new run.
Something like this
class ReadMap
{
string fileName;
LineDatabase Entry;
public:
//constructors and destructor
ReadMap(){fileName="blank.txt";}
ReadMap(string name){fileName=name;}
~ReadMap(){}
//Function to print out visible list
LineDatabase& show()
{
int LineNumber=100;
string buffer;
ifstream myfile (fileName.c_str() );
while (myfile.good())
{
myfile >> LineNumber >> ws;
getline (myfile, buffer);
Entry.insert(pair<int, string>(LineNumber, buffer));
cout <<buffer << endl;
}
return Entry;
}
};
The issue with this is that it exposes your internal state to modification, it is possible to return a const reference but then the client cannot modify the Map.
Finally, you could do as was suggested by bodes. However this requires that the client passes in a Map for you to work on.
Your choice will depend on how much work you would like to require your client to do as well as what kind of constraints you need and/or do not need to place on the data structure.