Constructors and array of object in C++ - c++

I'm trying to create an application in C++. In the application I have the default constructor and another constructor with 3 arguments.
The user is providing from the keyboard an integer that it will be used to create an array of objects using the non default constructor.
Unfortunately I haven't been able to finish it till now, since I'm having issues with the creation of the array of objects that they will use the non default constructor.
Any suggestions or help?
#include<iostream>
#include<cstring>
#include<cstdlib>
#include <sstream>
using namespace std;
class Station{
public:
Station();
Station(int c, char *ad, float a[]);
~Station();
void setAddress(char * addr){
char* a;
a = (char *)(malloc(sizeof(addr+1)));
strcpy(a,addr);
this->address = a;
}
void setCode(int c){
code=c;
}
char getAddress(){
return *address;
}
int getCode(){
return code;
}
float getTotalAmount(){
float totalAmount=0;
for(int i=0;i<4;i++){
totalAmount+=amount[i];
}
return totalAmount;
}
void print(){
cout<<"Code:"<<code<<endl;
cout<<"Address:"<<address<<endl;
cout<<"Total Amount:"<<getTotalAmount()<<endl;
cout<<endl;
}
private:
int code;
char *address;
float amount[4];
};
Station::Station(){
code= 1;
setAddress("NO ADDRESS GIVEN");
amount[0]= 0.0;
amount[1]= 0.0;
amount[2]= 0.0;
amount[3]= 0.0;
}
Station::Station(int c, char *ad, float a[]){
if( (c>=1&& c<=10 ) ){
code=c;
address=ad;
for(int i=0;i<4;i++){
amount[i]=a[i];
}
}else{
code= 1;
setAddress("NO ADDRESS GIVEN");
amount[0]= 0.0;
amount[1]= 0.0;
amount[2]= 0.0;
amount[3]= 0.0;
}
}
Station::~Station(){
}
int main(){
int size,code;
char *addrr;
addrr = (char *)(malloc(sizeof(addrr+1)));
float mes[4];
do{
cout<<"size of array:";
cin>>size;
}while(size<=0 || size>=11);
// Station *stations= new Station[size];
// Station** stations = new Station*[size];
Station stations[size];
for(int i=0;i<size;i++){
cout<<"code:";
cin>>code;
cout<<"address:";
cin>>addrr;
double amo=0;
for(int k=0;k<4;k++){
cout<<"values"<<k+1<<":";
cin>>mes[k];
}
}
/*
for(int q=0;q<size;q++){
stations[q].print();
}
*/
return 0;
}
the values that I'll take from cin I want to assign them to the objects of the array!

You can either create the array default-initialized and then fill the array with the wanted object:
foo arr[10];
std::fill(arr, arr+10, foo(some, params));
Alternatively you could use std::vector and do just:
std::vector<foo> arr(10, foo(some, params));

In C++0x, you can use braced-init-list in new expression, which means you can do this:
#include <iostream>
class A
{
public:
A(int i, int j){std::cout<<i<<" "<<j<<'\n';}
};
int main(int argc, char ** argv)
{
int *n = new int[3]{1,2,3};
A *a = new A[3]{{1,2},{3,4},{5,6}};
delete[] a;
delete[] n;
return 0;
}
Compiled under g++ 4.5.2, using g++ -Wall -std=c++0x -pedantic

Since you say you can't use std::string, this is going to be much more difficult. The line addrr = (char *)(malloc(sizeof(addrr+1))); is not doing what you think it is. Instead of using malloc to allocate on the heap and since there is no free (which will lead to a memory leak), it will be much easier if we allocate on the stack with a predetermined buffer size: char addrr[BUFFER_LENGTH]. With BUFFER_LENGTH defined before Station's declaration as const int BUFFER_LENGTH = 20; or some other appropriate length.
To use the non-default constructor, adding stations[i] = Station(c, addrr, mes); at the end of the for loop will do the trick.
for(int i=0;i<size;i++){
cout<<"code:";
cin>>code;
cout<<"address:";
cin>>addrr; // do not read in strings longer than 20 characters or increase BUFFER_LENGTH’s size
double amo=0;
for(int k=0;k<4;k++){
cout<<"values"<<k+1<<":";
cin>>mes[k];
}
stations[i] = Station(c, addrr, mes);
}
But, this is not going to work properly since the constructor is copying the addrr pointer, not the data. I would recommend also changing the data member char *address to char address[BUFFER_LENGTH]. Then, in the constructor you can replace the line address=ad; with strcpy(address, ad);.
Note: setAddress and getAddress will now need to be updated.
Another line that is troubling is Station stations[size];. This is non-standard since size is not a known at compile time. Either use Station *stations= new Station[size]; and remember to delete or if you can use a std::vector, use std::vector<Station> stations(size);
If you do go the std::vector route, using push_back will work nicely:
std::vector<Station> stations;
for(int i=0;i<size;i++){
cout<<"code:";
cin>>code;
cout<<"address:";
cin>>addrr;
double amo=0;
for(int k=0;k<4;k++){
cout<<"values"<<k+1<<":";
cin>>mes[k];
}
stations.push_back( Station(c, addrr, mes) );
}

Related

how to assign an array to a pointer inside a structure without causing memory leakage

I am reading data from a file in a function and saving the data to a temporary array. Then I am passing the array to a pointer inside a structure. But when I check the output in the main function, the data that I am reading is compromised and there is memory leakage for some values.
I want to know how I can read the data in the main function without causing memory leakage.
#include <iostream>
#include <fstream>
#include <string>
#include <cstdlib>
#include <cstring>
using namespace std;
struct myWeather
{
wchar_t *cityName;
float *temperature, *pressure, *direction, *wind;
myWeather *next, *prev;
};
myWeather *readData();
int main()
{
myWeather *location, *currLoc;
location = readData();
currLoc = location;
for(int c=0; c<49; c++)
{
cout<< "temp value"<< c+1<<": "<< (*currLoc->temperature+c)<<endl;
}
for(int f=0; f<1441; f++)
{
cout<< "pressure value"<< f+1<<": "<< *(currLoc->pressure+f)<<endl;
}
for(int g=0; g<720; g++)
{
cout<< "Dir value"<< g+1<<": "<< *(currLoc->direction+g)<<endl;
}
for(int h=0; h<720; h++)
{
cout<< "Wind value"<< h+1<<": "<< *(currLoc->wind+h)<<endl;
}
return 0;
}
myWeather *readData()
{
myWeather *headPTR;
char cityText[80];
wchar_t cityNym[80];
string myCity;
float tmpData[49], prsData[1441], winData[720], dirData[720];
int len;
ifstream weatherFile ("Data.txt", ios::in);
headPTR = new myWeather;
getline(weatherFile, myCity);
len= myCity.length();
myCity.copy(cityText, len, 0);
cityText[len]='\0';
mbstowcs(cityNym, cityText, strlen(cityText)+1);
headPTR->cityName = new wchar_t;
headPTR->cityName= cityNym;
weatherFile>> cityText;
weatherFile>>len;
for(int a=0; a<49; a++)
{
weatherFile>>tmpData[a];
}
headPTR->temperature = new float;
headPTR->temperature = tmpData;
weatherFile>> cityText;
weatherFile>>len;
for(int b=0; b<1441;b++)
{
weatherFile>>prsData[b];
}
headPTR->pressure= new float;
headPTR->pressure= prsData;
weatherFile>> cityText;
weatherFile>>len;
for(int d=0; d<720; d++)
{
weatherFile>>dirData[d];
}
headPTR->wind= new float;
headPTR->wind= dirData;
weatherFile>> cityText;
weatherFile>>len;
for(int e=0; e<720; e++)
{
weatherFile>>winData[e];
}
headPTR->direction = new float;
headPTR->direction = winData;
weatherFile.close();
return headPTR;
}
First of all in your case instead using an array you should use old std::vector<float> and wstring (for cityName). This is exactly what you need.
In case of next and previous you can use std::unique_ptr for next and raw pointer for previous.
Basically it may look like this:
struct myWeather
{
std::wstring cityName;
std::vector<float> temperature, pressure, direction, wind;
std::unique_ptr<myWeather> next;
myWeather prev;
};
But on other hand it looks like you are implementing double linking list which is already provided, so IMO this aproach is better:
struct myWeather
{
std::wstring cityName;
std::vector<float> temperature, pressure, direction, wind;
};
using WeatherRecords = std::list<myWeather>;
So in fact you do not need any fancy pointers or use new delete operators.

Array Initialization problems: Unexpected behavior

The following program builds perfectly. However, during execution, no matter what value of degree I provide, the program takes only 2 array elements as input. I suppose there might be a problem with the redeclaration of the arrays f[] and fDash[]. In JAVA, arrays can be easily redeclared using the new keyword. Is that possible in c++ too? If not, what is the alternative?
P.S. I am using CodeBlocks 13.12 and compiler settings are standard.
#include <iostream>
#include <cmath>
using namespace std;
class Polynomial
{
public:
void input(void);
void expression(void);
void derivative(void);
double value(double var);
double der(double var);
private:
int f[];
int fDash[];
int degree;
};
void Polynomial::input()
{
cout<<"Enter degree of polynomial:\t";
cin>>degree;
f[degree+1];
fDash[degree];
for(int i=0;i<=degree;i++)
{
cout<<"Enter coefficient of x^"<<i<<":\t";
cin>>f[i];
}
for(int i=0;i<degree;i++)
{
fDash[i]=f[i+1]*(i+1);
}
}
void Polynomial::expression()
{
cout<<f[0];
for(int i=1;i<=degree;i++)
{
cout<<" + "<<f[i]<<"*x^"<<i;
}
}
void Polynomial::derivative()
{
cout<<fDash[0];
for(int i=1;i<degree;i++)
{
cout<<" + "<<fDash[i]<<"*x^"<<i;
}
}
double Polynomial::value(double var)
{
double val=0.0;
for(int i=0;i<=degree;i++)
{
val+=f[i]*pow(var,i);
}
return val;
}
double Polynomial::der(double var)
{
double val=0.0;
for(int i=0;i<degree;i++)
{
val+=fDash[i]*pow(var,i);
}
return val;
}
int main()
{
double lb,ub,step,var,accum=0.0,rms;
int counter=0;
Polynomial p;
p.input();
cout<<"\n\n\nPolynomial is:\nf(x) = ";
p.expression();
cout<<"\n\n\nDerivative is:\nf'(x) = ";
p.derivative();
cout<<"\n\n\nEnter x0,x1,Step:\t";
cin>>lb;
cin>>ub;
cin>>step;
cout<<"\n\n\n====================================";
cout<<"\n\nx\t|\tf\t|\tf'\n\n\n";
var=lb;
while(var<=ub)
{
cout<<var<<"\t|\t"<<p.value(var)<<"\t|\t"<<p.der(var)<<"\n";
accum+=pow(p.value(var),2.0);
var+=step;
counter++;
}
cout<<"\n====================================";
accum/=counter;
rms=sqrt(accum);
cout<<"\nRMS energy of f(x) = "<<rms;
return 0;
}
This does not compile on clang, it fails with "error: field has incomplete type 'int []' int f[];" and likewise for fDash.
Let's see how you declared these fields:
int f[];
int fDash[];
In C++, you can declare arrays with statically defined sizes like so:
int f[5];
int fDash[6];
If you want dynamic arrays, which you need in this case, you'd have to declare
int* f;
int* fDash;
and allocate memory for them with
f = new int[5];
You also must release that memory somewhere like so
delete [] f;
But beware - managing your own memory like this is error prone and should be avoided. You should just use std::vector instead, which is the equivalent of java.util.ArrayList:
std::vector<int> f;
std::vector<int> fDash;
And modify your input function like so:
void Polynomial::input()
{
cout<<"Enter degree of polynomial:\t";
cin>>degree;
int input;
for(int i=0;i<=degree;i++)
{
cout<<"Enter coefficient of x^"<<i<<":\t";
cin>>input;
f.push_back(input);
}
for(int i=0;i<degree;i++)
{
fDash.push_back(f[i+1]*(i+1));
}
}
You don't use arrays correctly. You need to allocate memory if you want to use array of variable length. How use arrays in c++ see this and this, or use std::vector

NFA simulator error C++

I have one big problem with my NFA simulator.
When I run the code sometimes everything goes nice, but sometimes I get this
Process terminated with status -1073741819(0xC0000005)
What do I miss out and what to do to get this work fine?
This is the code:
#include <iostream>
#include<fstream>
#include<map>
using namespace std;
ifstream fin("fisier.txt");
class NFA {
int initiala,finale,stari,tran,cuvinte;
int *f;
multimap <pair <int,int>,char>t;
public:
void stari_finale();
void tranzitii();
void rezolvare();
};
void NFA::stari_finale()
{
fin>>finale;
f=new int[finale];
for(int i=1;i<=finale;i++)
fin>>f[i];
}
void NFA::tranzitii()
{
fin>>tran;
for(int i=1;i<=tran;i++)
{
int x,y;
char c2;
fin>>x>>y>>c2;
t.insert(make_pair(make_pair(x,y),c2));
}
}
void NFA::rezolvare()
{
fin>>stari>>initiala;
fin>>cuvinte;
for(int i=1;i<=cuvinte;i++)
{
int l;
fin>>l;
char *cuv=new char[l+1];
fin.get();
fin.getline(cuv,l+1);
int *c=new int[stari],nr=1;
c[1]=initiala;
for(int j=0;j<l;j++)
{
int *c1=new int[stari];
int n=0;
for(int k=1;k<=nr;k++)
for(int z=0;z<=stari;z++)
if(t.find(make_pair(c[k],z))!=t.end())
if(t.find(make_pair(c[k],z))->second==cuv[j])
n++,c1[n]=z;
for(int k=1;k<=n;k++)
c[k]=c1[k];
nr=n;
delete c1;
}
for(int j=1;j<=nr;j++)
{for(int k=1;k<=finale;k++)
if(c[j]==f[k])
{
cout<<"Word "<<cuv<<" is accepted!\n";
nr=-1;
break;
}
if(nr==-1)
break;
}
if(nr!=-1)
cout<<"Word "<<cuv<<" isn't accepted!\n";
delete c;
delete cuv;
}
}
int main()
{
NFA test;
test.stari_finale();
test.tranzitii();
test.rezolvare();
return 0;
}
One major problem is you are not calling the right delete on your variables. If you call new you need to call delete. If you call new[] you need to use delete[]. Mixing new[] and delete calls will cause undefined behavior which is a symptom of what is happening.
Your calls to delete for c, c1 and cuv should all be delete [] variable_name
You are writing outside the array here:
void NFA::stari_finale()
{
fin>>finale;
f=new int[finale];
for(int i=1;i<=finale;i++)
fin>>f[i];
}
f has the size finale, but i will be equal to finale in the last iteration.
Use this instead:
void NFA::stari_finale()
{
fin>>finale;
f=new int[finale];
for(int i=0;i<finale;i++)
fin>>f[i];
}
or, if you really need to use the 1-based indexing:
void NFA::stari_finale()
{
fin>>finale;
f=new int[finale + 1];
for(int i=1;i<=finale;i++)
fin>>f[i];
}

I am getting a pointer being free but not allocated error when running make, make test in putty

I am very new to object oriented programming, pointer use and allocating memory in C++. I am working on an assignment for class and initially I had it pass the first three tests listed below by having an array, grade_array, that in the addScore function looked like grade_array[count -1] = grade. Then it would be used in the mean function.
I know this is not the correct way to go about this because I was getting seg faults, so I know I need to have an array, then create a new array (twice the size) that allocates more memory so that I can put the values of the first one into the new one, and then delete to not get memory leaks. The real problem I am having is I do not know if I am even close to correct on the way I am doing this. The error I am getting:
Running cxxtest tests (5 tests)testrunner(85436) malloc: *** error for object 0x107a87970: pointer being freed was not allocated
*** set a breakpoint in malloc_error_break to debug
make: *** [test] Abort trap: 6
I have seen a lot of people having similar problems and posting about them on this very site I just cannot seem to fix mine. I saw that it could be that I made a new pointer and tried to them have them point to the same thing so when one deletes the other has nothing to delete or that my initializer is wrong as it doesn't do much. Like I said, very new to the topic so sorry if I have a million questions and so many errors. I have spent a lot of time on this already and was hoping I could maybe get some advice before I waste more time, thanks in advance!
Gradebook.h
#ifndef GRADEBOOK_H
#define GRADEBOOK_H
#include <string>
using namespace std;
class Gradebook {
public:
Gradebook();
Gradebook(const string& filename);
Gradebook(const Gradebook& that);
virtual ~Gradebook();
void initCount();
void addScore(double grade);
double getScoreAt(int i);
int getCount(int i);
string getSourceFile();
double getMean(); // change back to double
double getMin();
double getMax();
double getMedian();
double getStdDev();
int scoresInRange(double low, double high);
private:
string filename;
int* grade_array;
int new_size;
int count;
int count_tracker;
int* grade_point;
};
#endif
Gradebook.cpp
void Gradebook::initCount(){
count = 0;
}
Gradebook::Gradebook() {
}
Gradebook::Gradebook(const string& filename) : filename(filename) {
//this->filename = filename; // i beleive that filename(filename) does this line
//grade_array = new int[this->getCount(0) +1];
}
Gradebook::Gradebook(const Gradebook& that) {
}
Gradebook::~Gradebook() {
for ( int i = 0; i < this->getCount(0); i ++){
delete &grade_array[i];
}
delete grade_array;
}
void Gradebook::addScore(double grade) {
int count_tracker = this->getCount(1); //number of elements in array currently
// grade_array = new int[count_tracker ];
// grade_array = new int[1]; // grade_array is just a *array
grade_array[count_tracker -1 ] = grade; // array[0] is first not array[1]
new_size = count_tracker * 2;
int* new_array = new int[new_size];
for (int i = 0; i < count_tracker ; i++) {
new_array[i] = grade_array[i];
}
delete[] grade_array;
grade_array = new_array;
count_tracker = new_size;
}
double Gradebook::getScoreAt(int i) {
return grade_array[i];
}
int Gradebook::getCount(int i) {
if (i == 1){
count = count + 1;
}
else{
//don't want to add to the actual count
}
return count;
}
string Gradebook::getSourceFile() {
//ifstream foo;
//foo.open(filename);
return filename;
}
double Gradebook::getMean() {
double mean = 0;
count_tracker = this->getCount(0);
for (int i = 0; i < count_tracker ; i++){
//mean = (*(&(grade_array[i])- (bit_count))) + mean;
mean = grade_array[i] + mean;
}
return (mean/count_tracker);
}
GradebookTest.h
#ifndef GRADEBOOK_TEST_H
#define GRADEBOOK_TEST_H
#include <Gradebook.h>
#include <cxxtest/TestSuite.h>
class GradebookTest : public CxxTest::TestSuite {
public:
void testDefaultConstructor(){
string filename = "data1.txt";
Gradebook a(filename);
TS_ASSERT_EQUALS("data1.txt" , a.getSourceFile());
}
void testAddOne() {
Gradebook gb;
gb.initCount();
gb.addScore(110);
TS_ASSERT_EQUALS(120, gb.getScoreAt(1));
TS_ASSERT_DELTA(110, gb.getMean(), 0.001);
TS_ASSERT_EQUALS(4, gb.getCount(0) );
}
void testAddMultiple() {
Gradebook gb;
gb.addScore(75);
TS_ASSERT_EQUALS(1, gb.getCount(0) );
gb.addScore(85);
TS_ASSERT_EQUALS(2, gb.getCount(0));
TS_ASSERT_DELTA(85, gb.getMean(), 0.001);
}
#endif
I think the following is wrong
for ( int i = 0; i < this->getCount(0); i ++){
delete &grade_array[i];
}
You don't need this for loop since you only allocate memory for grad_array. One delete grade_array; is enough.

c++ read 3 columns from a text file into a 2D array or 3 individual arrays

I have a text file looks like this:
173865.385 444879.102 0.299
173864.964 444879.137 0.467
173864.533 444879.177 0.612
173864.113 444879.211 0.798
173863.699 444879.244 1.002
173863.27 444879.282 0.926
173862.85 444879.317 0.974
....
....
....(around 200000 rows)
I'm trying to put each column into one array.
now I have these cripts:
int ReadDataFromFile(double * DataList[] ,int DataListCount,string &FileName)
{
ifstream DataFile;
int CurrentDataIndex = 0;;
DataFile.open(FileName.c_str(),ios::in);
if(DataFile.is_open()==true)
{
char buffer[200];
while(DataFile.getline(buffer,200))
{
string strdata;
stringstream ss(buffer);
for(int i =0;i<DataListCount;++i)
{
getline(ss,strdata,' ');
DataList[i][CurrentDataIndex] = strtod(strdata.c_str(),NULL);
}
++CurrentDataIndex;
}
}
return CurrentDataIndex;
}
int _tmain(int argc, _TCHAR* argv[])
{
double a[200000],b[200000],c[200000];
double* DataList[] = {a,b,c};
int DataCount = ReadDataFromFile(DataList,3,string("D:\\read\\k0_test.txt"));
for(int i=0;i<DataCount;++i)
{
cout<<setw(10)<<a[i]<<setw(10)<<b[i]<<setw(10)<<c[i]<<endl;
}
system("pause");
return 0;
}
But it always tell an error "overflow". Is there any other way to relize this problem?
double a[200000],b[200000],c[200000];
used out all your program's stack space, try to use std::vector (preferred) or use dynamic array, which allocates memory on the heap instead.
For example: (for a only)
vector<double> a;
a.reserve(200000);
Or
vector<double> a(200000);
if use dynamic array:
double* a = new double[200000];
Don't forget to release memory when you are done using them:
delete [] a;
See STL Vector for more information.
2 solutions:
Move double a[200000],b[200000],c[200000]; outside the _tmain so that they can be global variables.
Or,
Declare a,b,c as:
double *a = new double[200000];
double *b = new double[200000];
double *c = new double[200000];
and don't forget to free them by delete[]
Hope this helps :)