C++ send object trough socket - c++

I'm trying to build a client-server application. To accomplish it, I use socket.h and try to send my object. I know that it exist librairies which do the job for me but I would like to do it from my hand. I know that the problem are string because of the "ramdom" size. When the server receive my object, it create a seg fault when I'm trying to output/delete the object
#ifndef MESSAGE_HPP
#define MESSAGE_HPP
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <string.h>
#include <unistd.h>
#include <vector>
#include <fstream>
class Message
{
int _from = -1; // id socket client
int _to = -1; //id socket friend
std::string _format = "txt";
std::string _message ="some message to send";
public:
Message(int from, int to, std::string format, std::string message);
Message() noexcept = default;
~Message(){}
//OPERATOR
friend std::ofstream& operator<<(std::ofstream& os, const Message& obj);
friend std::ifstream& operator>>(std::ifstream& is, Message& obj);
};
//here start my cpp
Message::Message(int from, int to, std::string format, std::string message){
_from = from;
_to = to;
_format = format;
_message = message;
}
std::ofstream& operator<<(std::ofstream& os, const Message& obj)
{
os << obj._from << " ";
os << obj._to << " ";
//os << obj._format.length();
os << "\0"<< obj._format << " ";//my tries D;
//os << obj._message.length();
os << "\0" << obj._message;
return os;
}
std::ifstream& operator>>(std::ifstream& is, Message& obj)
{
char* tmp;
size_t sizeOfString;
is >> obj._from;
is >> obj._to;
is >> obj._format;
is >> obj._message;
is >> sizeOfString;
/*tmp = new char[sizeOfString];
is.get(tmp, sizeOfString+1);
obj._format = tmp;
delete[] tmp;
tmp = NULL;
is >> sizeOfString;
tmp = new char[sizeOfString];
is.get(tmp, sizeOfString+1);
obj._message = tmp;
delete[] tmp;
tmp = NULL;*/
return is;
}
#endif
As you can see. I already tried a lot of things found on internet. Send size of string and build with char[size], add a '\n', reinterpret_cast, etc.
The client do
std::string buffer;
while (buffer != "END"){
buffer.clear();
std::cout << "You: ";
std::getline( std::cin,buffer) ;
Message mess = Message(1,2,"txt",buffer);
//char* tmp = reinterpret_cast<char*>(&mess); // when I tried reinterpret_cast
write(_connection_to_server_socket, &mess , sizeof(Message));
and server:
mes = new Message();
char buf[sizeof(Message)];//the try with reinterpret_cast
if ((valread = recv( sd , mes, sizeof(Message),0)) == 0) {
//some code to manage client disconnection
}
else{
std::cout << mes << std::endl; // seg fault
//some code using the object
}
delete mes; //if segfault here if the std::cout is comment
Is it possible to show me a concrete example with number and std::string(with conversion to char*) using operator(or not if it impossible with operator<< and operator>>).
Thank you to the persons that will help me !
See you !

Related

creating a class vector that does not delete it's content

I am a beginner , so i wanted to ask , can we create a class object vector/array , that does not delete it's content when i close the program like , so like I want a customer record , but whenever if we try to restart the program we need to enter the customer details again and again ...
how to prevent that from happening
#include <iostream>
#include <vector>
using namespace std;
class customer{
public:
int balance;
string name;
int password;
};
int main(){
vector <customer> cus;
...
if(choice == 1){
cout << cus[i].balance
}
return 0;
}
As a complement to Adam's answer, it is possible to encapsulate the serialization in the container class itself. Here is an simplified example:
The header file defining a persistent_vector class that saves its content to a file:
#include <iostream>
#include <string>
#include <vector>
#include <fstream>
#include <initializer_list>
namespace {
// Utility functions able to store one element of a trivially copyable type
template <class T>
std::ostream& store1(std::ostream& out, const T& val) {
out.write(reinterpret_cast<const char*>(&val), sizeof(val));
return out;
}
template <class T>
std::istream& load1(std::istream& in, T& val) {
in.read(reinterpret_cast<char*>(&val), sizeof(val));
return in;
}
// Specialization for the std::string type
template <>
std::ostream& store1<std::string>(std::ostream& out, const std::string& val) {
store1<size_t>(out, val.size());
if (out) out.write(val.data(), val.size());
return out;
}
template <>
std::istream& load1<std::string>(std::istream& in, std::string& val) {
size_t len;
load1<size_t>(in, len);
if (in) {
char* data = new char[len];
in.read(data, len);
if (in) val.assign(data, len);
delete[] data;
}
return in;
}
}
template <class T>
class persistent_vector {
const std::string path;
std::vector<T> vec;
// load the vector from a file
void load() {
std::ifstream in(path);
if (in) {
for (;;) {
T elt;
load1(in, elt);
if (!in) break;
vec.push_back(elt);
}
if (!in.eof()) {
throw std::istream::failure("Read error");
}
in.close();
}
}
// store the vector to a file
void store() {
std::ofstream out(path);
size_t n = 0;
if (out) {
for (const T& elt : vec) {
store1(out, elt);
if (!out) break;
++n;
}
}
if (!out) {
std::cerr << "Write error after " << n << " elements on " << vec.size() << '\n';
}
}
public:
// a bunch of constructors, first ones load data from the file
persistent_vector(const std::string& path) : path(path) {
load();
}
persistent_vector(const std::string& path, size_t sz) :
path(path), vec(sz) {
load();
};
// last 2 constructors ignore the file because they do receive data
persistent_vector(const std::string& path, size_t sz, const T& val) :
path(path), vec(sz, val) {
};
persistent_vector(const std::string& path, std::initializer_list<T> ini) :
path(path), vec(ini) {
}
// destructor strores the data to the file before actually destroying it
~persistent_vector() {
store();
}
// direct access to the vector (const and non const versions)
std::vector<T>& data() {
return vec;
}
const std::vector<T>& data() const {
return vec;
}
};
It can, out of the box, handle any trivially copyable type and std::string. User has to provide specializations of store1 and load1 for custom types.
Here is a trivial program using it:
#include <iostream>
#include <string>
#include "persistent_vector.h"
int main() {
std::cout << "Create new vector (0) or read an existing one (1): ";
int cr;
std::cin >> cr;
if (!std::cin || (cr != 0 && cr != 1)) {
std::cout << "Incorrect input\n";
return 1;
}
if (cr == 0) {
persistent_vector<std::string> v("foo.data", 0, "");
// skip to the end of line...
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
for (;;) {
std::string line;
std::cout << "Enter a string to add to the vector (empty string to end program)\n";
std::getline(std::cin, line);
if (line.empty()) break;
v.data().push_back(line);
}
}
else {
persistent_vector<std::string> v("foo.data");
for (const std::string& i : v.data()) {
std::cout << i << '\n';
}
}
return 0;
}
When a programmer creates a vector class, he must ensure that the resources acquired for that vector are released when they are no longer needed. (See RAII)
C++ Reference : https://en.cppreference.com/w/cpp/language/raii
Wikipedia : https://en.wikipedia.org/wiki/Resource_acquisition_is_initialization
Stack Overflow : What is meant by Resource Acquisition is Initialization (RAII)?
Microsoft : https://learn.microsoft.com/en-us/cpp/cpp/object-lifetime-and-resource-management-modern-cpp?view=msvc-170
Before the program closes, all resources must be released.
(No leaking resources, memory included)
It is not possible to create a vector class that does not delete its contents after closing a program. Secure operating systems will release program resources when the program is closed.
If you want the program not to lose customer information after closing, you need to save the information in persistent (non-volatile) storage device, such as a disk.
As CinCout, 김선달, Serge Ballesta say, you have to save the customer information to a file, and write the program so that you can read that file during the start of the program.
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
struct customer {
std::string name;
int balance;
int password;
};
int main() {
std::vector <customer> customers;
std::ifstream ifs("info.txt");
{
customer customer{};
while (ifs >> customer.name >> customer.balance >> customer.password)
customers.push_back(customer);
}
for (const auto& [name, balance, password] : customers) {
std::cout <<
"\nName : " << name <<
"\nBalance : " << balance <<
"\nPassword : " << password <<
'\n';
}
std::cout << "\n\nWelcome\n\n";
std::ofstream ofs("info.txt", std::ios_base::app);
char cont{};
do {
customer customer{};
std::cout << "Name : ";
std::cin >> customer.name;
std::cout << "Balance : ";
std::cin >> customer.balance;
std::cout << "Password : ";
std::cin >> customer.password;
ofs << customer.name << ' ' << customer.balance << ' ' << customer.password << '\n';
std::cout << "Add another customer? (Y/N) : ";
std::cin >> cont;
} while (cont == 'Y');
for (const auto& [name, balance, password] : customers) {
std::cout <<
"\nName : " << name <<
"\nBalance : " << balance <<
"\nPassword : " << password <<
'\n';
}
}
CPlusPlus : https://www.cplusplus.com/doc/tutorial/files/
LearnCpp : https://www.learncpp.com/cpp-tutorial/basic-file-io/
(About File I/O)
This program is a prototype, I left some things incomplete (like check readings, user-defined I/O operators, duplicate code, formatting, reallocations of customers, ifs is not required after range-for + structured binding,...).
I suggest you read the book "Programming: Principles and Practice Using C+", I’m reading it and it helped me a lot.
(I’m also a beginner)
Edit: I also suggest you use "using namespace std;" only for small projects, examples or simple exercises.
Do not use "using namespace std;" for real projects, large projects or projects that may include other dependencies because the use of "using namespace std;" could lead to a possible naming collisions between names within std and the names of other codes and libraries.
It’s not good practice to use it all the time.

How to swap strings?

I am trying to swap strings. For one of my functions of my class, I am passing in two strings and I also created a temp variable. I have been trying to compile my code, but it says "no suitable function for conversion from std::string to const char* exists.
void CdLib::swap(string *s1, string *s2)
{
string temp;
strcpy(temp, *s1);
strcpy(*s1, *s2);
strcpy(*s1, temp);
}
class CdLib
{
public:
int n;
char Cd[N_MAX];
string artist;
string title;
int year;
string genre;
string fan;
string imageURL;
CdLib();
void setFromFile(string fileName);
void print(string label);
void sortByYear();
void sortByArtist();
void sortByTitle(string genres[]);
private:
void swap(int *a, int *b);
void swapStrings(string *s1, string *s2);
};
I'm confused why it is trying to convert between string and char when they should all be string. Thank you.
strcpy() takes char* pointers, not string* pointers. It you are not allocating any memory for strcpy() to copy into.
Rather than using strcpy() at all, a better solution is to use std::string::operator= instead:
void CdLib::swap(string *s1, string *s2)
{
string temp = *s1;
*s1 = *s2;
*s1 = temp;
}
Or better, std::swap():
void CdLib::swap(string *s1, string *s2)
{
std::swap(*s1, *s2);
}
I am trying to swap strings
Why would you need to? Sorting can be accomplished via std::sort and you don't have to worry about how the strings get swapped - that's the beauty of C++, such basic operations are all implemented in the standard library.
std::swap supports pretty much everything, so use that.
Don't pass strings as arguments by value. Pass them by const reference. Return them by value. If a function is intended to modify a string in place, then it should take it by non-const reference (i.e. "just" a reference).
Don't write using namespace std - it's bad practice.
I guess that the CdLib class is some sort of a CD library, but you haven't told us what else your program should do.
If I were to write a sketch of this, I'd start with a structure representing the CD information, comparison functions for the CD that can be used in sorting, a function to print out the CD information, and a way to stream the CD information to/from an ostream/istream:
#include <algorithm>
#include <fstream>
#include <iostream>
#include <string>
#include <vector>
struct CDInfo
{
std::string artist;
std::string title;
std::string genre;
std::string fan;
std::string imageUrl;
int year;
friend void swap(CDInfo& a, CDInfo& b)
{
// see https://stackoverflow.com/a/2684544/1329652 for rationale
using std::swap; // bring in swap for built-in types
swap(a.artist, b.artist);
swap(a.title, b.title);
swap(a.genre, b.genre);
swap(a.fan, b.fan);
swap(a.imageUrl, b.imageUrl);
swap(a.year, b.year);
}
};
bool lessByYear(const CDInfo &l, const CDInfo &r) {
return l.year < r.year;
}
bool lessByArtist(const CDInfo &l, const CDInfo &r) {
return l.artist < r.artist;
}
void print(std::ostream &os, const CDInfo &cd) {
os << "Artist: " << cd.artist
<< "\n Title: " << cd.title
<< "\n Genre: " << cd.genre
<< "\n Fan: " << cd.fan
<< "\n Image: " << cd.imageUrl
<< "\n Year: " << cd.year << "\n";
}
std::istream &operator>>(std::istream &is, CDInfo &cd)
{
std::string year;
std::getline(is, cd.artist);
std::getline(is, cd.title);
std::getline(is, cd.genre);
std::getline(is, cd.fan);
std::getline(is, cd.imageUrl);
if (std::getline(is, year)) cd.year = std::stoi(year);
return is;
}
std::ostream &operator<<(std::ostream &os, const CDInfo &cd)
{
os << cd.artist << '\n' << cd.title << '\n'
<< cd.genre << '\n' << cd.fan << '\n'
<< cd.imageUrl << '\n' << cd.year << '\n';
return os;
}
Then I'd write a class representing the CD library, with methods to access the individual CDs, iterators to access the entire collection, methods using the std::sort algorithm and the comparison functions to sort the library, and methods to load/save it from/to file, and to print the entire library (by default to stdout):
class CDLibrary
{
std::vector<CDInfo> m_CDs;
public:
CDLibrary() = default;
int count() const { return m_CDs.size(); }
void resize(int newCount) { m_CDs.resize(newCount); }
CDInfo &getCD(int index) { return m_CDs[index]; }
const CDInfo &getCD(int index) const { return m_CDs[index]; }
auto begin() { return m_CDs.begin(); }
auto end() { return m_CDs.end(); }
auto begin() const { return m_CDs.begin(); }
auto end() const { return m_CDs.end(); }
auto cbegin() const { return m_CDs.begin(); }
auto cend() const { return m_CDs.end(); }
void sortByYear() {
std::sort(begin(), end(), lessByYear);
}
void sortByArtist() {
std::sort(begin(), end(), lessByArtist);
}
void addCD(const CDInfo &cd) {
m_CDs.push_back(cd);
}
void removeCD(int index) {
m_CDs.erase(m_CDs.begin() + index);
}
bool load(const std::string &filename);
bool save(const std::string &filename) const;
void printAll(std::ostream &os = std::cout) const {
int n = 1;
for (auto &cd : *this) {
os << "--- CD #" << n << '\n';
print(os, cd);
}
}
};
Of course I'd also implement the streaming operators for the entire library, just as we did for the individual CDInfo:
std::istream &operator>>(std::istream &is, CDLibrary &lib) {
std::string count;
if (std::getline(is, count)) {
lib.resize(std::stoi(count));
for (auto &cd : lib)
if (!(is >> cd)) break;
}
return is;
}
std::ostream &operator<<(std::ostream &os, const CDLibrary &lib) {
if (!(os << lib.count() << '\n')) return os;
for (auto &cd : lib)
if (!(os << cd)) break;
return os;
}
Then, the load and save convenience methods can be expressed n terms of those streaming operators:
bool CDLibrary::load(const std::string &filename) {
std::ifstream ifs(filename);
try {
return ifs.good() && ifs >> *this;
} catch (...) {}
return false;
}
bool CDLibrary::save(const std::string &filename) const {
std::ofstream ofs(filename);
return ofs.good() && ofs << *this;
}
Hopefully this gives you some idea how such code might look. I'm not quite sure what you expected to achieve with void sortByTitle(string genres[]), so I didn't implement it. Feel free to comment under this answer to explain, as well as edit the question to make it clear what is the functionality you need.
#include <iostream>
#include<bits/stdc++.h>
using namespace std;
int main() {
string str1 = "Hello";
string str2 = "World";
swap(str1,str2);
cout<<str1<<" ";
cout<<str2;
}
o/p:
Success #stdin #stdout 0s 4492KB
World Hello

fread is reading garbage in file

I am working on my assignment and faced a problem with fread() in C++. When I modify the name in my file it modifies it perfectly as I want but the problem occurs when I try to read the file after that, it reads the whole file but it does not stop after that it's running total 146 times whereas there are only 3 names.
My code:-
#include <bits/stdc++.h>
using namespace std;
struct person{
int id;
string fname;
}s;
void write(){
FILE *outfile;
struct person input;
int num,ident;
string sname[] = {"a","b","c"};
outfile = fopen ("C:\\Users\\Amritesh\\Desktop\\students.txt","wb");
if (outfile == NULL)
{
fprintf(stderr, "\nError opend file\n");
exit (1);
}
scanf("%d",&num);
for(int i=0;i<num;i++){
s.fname = sname[i];
cin >> s.id;
fwrite (&s, sizeof(s), 1, outfile);
}
fclose(outfile);
}
void read(){
FILE *file1;
int i=0;
file1 = fopen ("C:\\Users\\Amritesh\\Desktop\\students.txt","r");
while(fread(&s, sizeof(s), 1, file1) == 1) {
cout << "ID " << s.id << " Name " <<s.fname << endl;
}
fclose (file1);
}
void modify(){
FILE *file;
file = fopen ("C:\\Users\\Amritesh\\Desktop\\students.txt","r+");
while(fread(&s, sizeof(s), 1, file)) {
if(s.fname == "a"){
s.fname = "d";
fseek(file,-sizeof(s),SEEK_CUR);
fwrite (&s, sizeof(s), 1,file);
}
}
fclose (file);
}
int main(){
write();
modify();
read();
}
Edited code:-
#include <iostream>
#include <string>
#include <fstream>
using namespace std;
struct person
{
int id;
string fname;
}s,temp;
void read()
{
int num;
ifstream fin;
fin.open("C:\\Users\\Amritesh\\Desktop\\student.txt",ios::in);
fin.seekg(0,ios::beg);
//scanf("%d",&num);
while(fin){
cout << s.fname << s.id << endl;
}
fin.close();
}
void write(){
int i=0;
ofstream fout;
fout.open("C:\\Users\\Amritesh\\Desktop\\student.txt");
while(i!=2) {
cin >> s.id >> s.fname;
fout << "ID " << s.id << " Name " <<s.fname << endl;
i++;
}
fout.close();
}
void modify(){
fstream mod;
mod.open ("C:\\Users\\Amritesh\\Desktop\\student.txt");
while(mod) {
if(s.fname == "a"){
s.fname = "d";
mod.seekg(-sizeof(s),ios::cur);
mod << s.fname;
}
}
mod.close();
}
int main(){
write();
read();
modify();
}
Thanks for any answer!
Here are three ideas based on our discussion. I'll start with free functions for reading and writing a person object since it looks like you're at that stage right now. I'll move on to adding member functions in your person class and end with adding stream operators for convenience.
An example of free (non-member) read and write functions:
#include <iostream>
#include <string>
#include <fstream>
struct person {
int id;
std::string fname;
};
std::ostream& write(std::ostream& os, const person& p) {
os << p.id << ',' << p.fname << '\n'; // stream out the properties of a person
return os; // look at the next example for an alternative doing the same thing
}
std::istream& read(std::istream& is, person& p) {
// extract "id" and if it succeeds, check if the next char is a , char
if(is >> p.id && is.peek() == ',') {
is.ignore(); // step over the , char
std::getline(is, p.fname); // read the rest of the line into p.fname
} else {
// we didn't get id or the , char, so set the stream in a failed state
is.setstate(is.failbit);
}
return is;
}
int main() {
// write to file
{
std::ofstream file("C:\\Users\\Amritesh\\Desktop\\student.txt");
person test1{10, "Foo Bar"};
person test2{20, "Apa Bepa"};
write(file, test1);
write(file, test2);
}
// read from file
{
std::ifstream file("C:\\Users\\Amritesh\\Desktop\\student.txt");
person test;
while(read(file, test)) {
std::cout << test.fname << '\n';
}
}
}
An example of making read and write member functions in person:
#include <iostream>
#include <string>
#include <fstream>
struct person {
int id;
std::string fname;
std::ostream& write(std::ostream& os) const {
// this does the same thing as in the first example
return os << id << ',' << fname << '\n';
}
std::istream& read(std::istream& is) {
if(is >> id && is.peek() == ',') {
is.ignore(); // step over the , char
std::getline(is, fname);
} else {
is.setstate(is.failbit); // we didn't get id or the , char
}
return is;
}
};
int main() {
// write to file
{
std::ofstream file("C:\\Users\\Amritesh\\Desktop\\student.txt");
person test1{10, "Foo Bar"};
person test2{20, "Apa Bepa"};
test1.write(file);
test2.write(file);
}
// read from file
{
std::ifstream file("C:\\Users\\Amritesh\\Desktop\\student.txt");
person test;
while(test.read(file)) {
std::cout << test.fname << '\n';
}
}
}
Member functions supported by stream operators:
#include <iostream>
#include <string>
#include <fstream>
struct person {
int id;
std::string fname;
std::ostream& write(std::ostream& os) const {
return os << id << ',' << fname << '\n';
}
std::istream& read(std::istream& is) {
if(is >> id && is.peek() == ',') {
is.ignore(); // step over the , char
std::getline(is, fname);
} else {
is.setstate(is.failbit); // we didn't get id or the , char
}
return is;
}
};
// stream operators calling member functions
std::ostream& operator<<(std::ostream& os, const person& p) { return p.write(os); }
std::istream& operator>>(std::istream& is, person& p) { return p.read(is); }
int main() {
// write to file
{
std::ofstream file("C:\\Users\\Amritesh\\Desktop\\student.txt");
person test1{10, "Foo Bar"};
person test2{20, "Apa Bepa"};
file << test1 << test2; // calling operator<< for each person object
}
// read from file
{
std::ifstream file("C:\\Users\\Amritesh\\Desktop\\student.txt");
person test;
while(file >> test) { // extract one person at a time using operator>>
std::cout << test.fname << '\n';
}
}
}

How can I overload the << operator so I can write the data of an object to a file?

I have an object of type piggyBank and I need to write data of this object into a file and then read it. I am aware of how to write/read to a text file but how can I overload the << operator so I can write data about the object into a file?
My code for the class here:
piggyBank.h
#include <string>
#ifndef PIGGYBANK_H
#define PIGGYBANK_H
class PiggyBank
{
private:
std::string owner;
int balance;
bool broken;
int id;
static int nrOfObjects;
public:
PiggyBank(void);
PiggyBank(std::string name);
std::string getOwnerName() const;
void setOwnerName(std::string name);
bool isBroken() ;
int getBalance(int & amount) ;
};
#endif /* PIGGYBANK_H */
piggyBank.cpp
#include "PiggyBank.h"
#include "readWrite.h"
#include <string>
#include <iostream>
using namespace std;
int PiggyBank::nrOfObjects = 0; // outside constructor
PiggyBank::getNrOfObjects(){
return nrOfObjects;
}
PiggyBank::PiggyBank(void){
{this->owner="";this->balance=0;this->broken=false;}
id = ++nrOfObjects;
}
PiggyBank::PiggyBank(std::string name, int startBalance){
{this->owner=name;this->balance=startBalance;this->broken=false;}
id = ++nrOfObjects;
}
string PiggyBank::getOwnerName() const{
return this->owner;
}
void PiggyBank::setOwnerName(string name){
this->owner = name;
}
bool PiggyBank::isBroken() {
return this->broken;
}
int PiggyBank::getBalance(int & amount) {
if(!broken){
amount = balance;
return 0;
}else{
return -1;
}
}
You want the << operator to be a friend to the class and to return ostream&.
Here is a simple example to get an idea about how it works.
friend ostream& operator << (ostream& os, const PiggyBank& obj)
{
// For example something like this
os << "Information that you want to output to the file:\n";
os << "Owner: " << obj.owner << "\n";
return os;
}
And then you can use it like this:
PiggyBack obj;
ofstream fout("file.txt");
// also check to see if the file opened correctly
if(fout.fail())
{
cout << "File failed to open\n";
return 0;
}
fout << obj;
// now you have written the owner information onto the file as well as the message before it
// inside the operator<< overload
// close the resource at the end
fout.close();
The cool part is that you can use it to print to the console too by changing fout to be cout.
For example:
cout << obj; // will print to the console
Very simple. Overload the inserter operator. Write this into your class:
friend std::ostream& operator << (std::ostream& os, const PiggyBank& pb) {
return os << pb.owner << . . . // Whatever you want
Then you can use the inserter operator as for any other data type:
int main() {
PiggyBank pb;
if (std::ofstream os("FileName"); os) {
os << pb << "\n";
}
return 0;
}

unable to write to a file char pointer

i am writing a character pointer to a file, but my program always crashes at name when i do it and i am unable to figure out why
#include <iostream>
#include <iomanip>
#include <string>
#include "AmaProduct.h"
using namespace std;
namespace sict{
AmaProduct::AmaProduct(char file){
fileTag_ = file;
}
const char* AmaProduct::unit()const{
return unit_;
}
void AmaProduct::unit(const char* value){
for (int i = 0; i != 9; i++){
unit_[i] = value[i];
}
unit_[11] = 0;
}
fstream& AmaProduct::store(fstream& file, bool addNewLine)const{
file.open("file.txt");
if (file.is_open()){
file << fileTag_ << "," << sku() << ",";
file<< name() << ",";//here
file<< price() << "," << taxed() << "," << quantity() << "," << unit_ << "," << qtyNeeded();
if (addNewLine){
file << endl;
}
}
file.close();
return file;
}
header file
#ifndef SICT_AMAPRODUCT_H__
#define SICT_AMAPRODUCT_H__
#include "Streamable.h"
#include "Product.h"
#include "Date.h"
#include "ErrorMessage.h"
#include "general.h"
#include <iostream>
#include <fstream>
namespace sict{
class AmaProduct : public Product{
private:
char fileTag_;
char unit_[11];
protected:
ErrorMessage err_;
public:
AmaProduct(char file='N');
const char* unit()const;
void unit(const char* value);
fstream& store(fstream& file, bool addNewLine = true)const;
fstream& load(std::fstream& file);
ostream& write(ostream& os, bool linear)const;
istream& read(istream& is);
};
}
name()
const char* Product::name()const{
return name_;
}
char* name_;
void Product::name(char* name){
delete[] name_;
name_= new char[strlen(name)+1];
strcpy(name_,name);
}
if anyone is interested in the other files i will upload them too
There are several possibilities, but if cout<<name() causes a segmentation fault, the most probable cases are:
name_ is still nullptr
name_ is an invalid pointer (for example if you copied your structure, which doesn't respect the rule of 3)
To make your code more reliable, you could change all char*, their tedious memory allocations and the c-style string operations with string.
If you don't, make sure to respect the rule of 3 to avoid shallow copy and pointer issues when copying or copy constructing your struct, and make sure that when you use a fixed size char array, you're sure not to overflow the buffer
Note also that doing this, might overflow the buffer:
file.getline(n, ',');
name(n);
because istream::getline(), when it has two arguments, takes as second argument the size (here 44, the ascii value of the comma). file.getline(n, 7, ',') would be the correct form.