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

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.

Related

Array and pointers to structures

So I have this structure
struct Data {
int id;
string message;
};
I am trying to create an array of struct pointers and fill it with values using this
Data *stack[10];
for(int i=0; i<10; i++){
stack[i] = (struct Data*) malloc(sizeof(struct Data));
stack[i]->id = i;
stack[i]->message = "message" + i;
}
however, I keep getting an error (segmentation fault when debugging) from stack[i]->message = "message" + i;
Can anyone please help understand what's causing the error and how to solve it?
Below is the working example. You can use smart pointers for automatic memory management, that is the destructor will be called automatically when reference count goes to zero.
#include <iostream>
#include <memory>
using namespace std;
struct Data {
int id;
string message;
Data()
{
std::cout<<"default consructor"<<std::endl;
}
~Data()
{
std::cout<<"destructor "<<std::endl;
}
};
int main()
{
std::cout << "Hello World" << std::endl;
std::shared_ptr<Data> stack[10];
for(int i=0; i<10; i++){
stack[i] = std::make_shared<Data>();
stack[i]->id = i;
stack[i]->message = "message" + std::to_string(i);//make sure to convert the integer to std::string
}
//check the value of id for first element in stack
std::cout<<stack[1]->id<<std::endl;
return 0;
}
You can also use new instead of malloc but then you will have to call delete explicitly. Note the use of std::to_string() to convert the integer i to string.

c++ segmentation fault for dynamic arrays

I want to add a theater object into a boxoffice object in a C++ code. When I try to add it in main code, first one is added successfully. But a segmentation fault occurs for second and obvioulsy other theater objects. Here is the add function;
#include <iostream>
#include <string>
#include "BoxOffice.h"
using namespace std;
BoxOffice::BoxOffice()
{
sizeReserv = 0;
sizeTheater = 0;
theaters = new Theater[sizeTheater];
reserv = new Reservation[sizeReserv];
}
BoxOffice::~BoxOffice(){}
void BoxOffice::addTheater(int theaterId, string movieName, int numRows, int numSeatsPerRow){
bool theaterExist = false;
for(int i=0; i<sizeTheater; i++)
{
if(theaters[i].id == theaterId)
{
theaterExist=true;
}
}
if(theaterExist)
cout<<"Theater "<<theaterId<<"("<<movieName<<") already exists"<< endl;
else
{
++sizeTheater;
Theater *tempTheater = new Theater[sizeTheater];
if((sizeTheater > 1)){
tempTheater = theaters;
}
tempTheater[sizeTheater-1] = Theater(theaterId,movieName,numRows,numSeatsPerRow);
delete[] theaters;
theaters = tempTheater;
cout<<"Theater "<<theaterId<<"("<<movieName<<") has been added"<< endl;
cout<<endl;
delete[] tempTheater;
}
}
And I get segmentation fault on this line;
tempTheater[sizeTheater-1] = Theater(theaterId,movieName,numRows,numSeatsPerRow);
This is Theater cpp;
#include "Theater.h"
using namespace std;
Theater::Theater(){
id=0;
movieName="";
numRows=0;
numSeatsPerRow=0;
}
Theater::Theater(int TheaterId, string TheaterMovieName, int TheaterNumOfRows, int TheaterNumSeatsPerRow)
{
id = TheaterId;
movieName = TheaterMovieName;
numRows = TheaterNumOfRows;
numSeatsPerRow = TheaterNumSeatsPerRow;
theaterArray = new int*[TheaterNumOfRows];
for(int i=0;i<TheaterNumOfRows;i++)
theaterArray[i]= new int[TheaterNumSeatsPerRow];
for(int i=0; i<TheaterNumOfRows;i++){
for(int j=0;j<TheaterNumSeatsPerRow;j++){
theaterArray[i][j]=0;
}
}
}
This is header file of Theater;
#include <iostream>
#include <string>
using namespace std;
class Theater{
public:
int id;
string movieName;
int numRows;
int numSeatsPerRow;
int **theaterArray;
Theater();
Theater(int TheaterId, string TheaterMovieName, int TheaterNumOfRows, int TheaterNumSeatsPerRow);
};
And this is how i call add functions;
BoxOffice R;
R.addTheater(10425, "Ted", 4, 3);
R.addTheater(8234, "Cloud Atlas", 8, 3);
R.addTheater(9176, "Hope Springs",6,2);
The problematic lines are these:
if((sizeTheater > 1)){
tempTheater = theaters;
}
First you allocate memory and assign it to tempTheater, but here you overwrite that pointer so it will point to the old memory. It does not copy the memory. Since the code is for a homework assignment, I'll leave it up to you how to copy the data, but I do hope you follow the rule of three for the Theater class (as for the BoxOffice class) which will make it very simple.
Also, there's no need to allocate a zero-size "array", just make the pointers be nullptr (or 0).

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];
}

dynamically allocate memory to struct array c++

let me start by saying I know this is a funky way to program, but my teacher is requiring us to go about it this way.
also:
I CANT use std::string, classes, constructors for this project.
I am required to use this archaic method of c-style strings with dynamic memory allocation occuring outside the struct.. i know its not the best way to go about this, but theres nothign i can go. :(
Im stuck with the structs, I cant figure out whats wrong..
I have a struct
#include <iostream>
#include <fstream>
#include <ctime>
#include <stdlib.h>
#include <string>
using namespace std;
//global constant(s)
const int maxCards = 52;
//Structs
struct card
{
char *suit;
char *rank;
int cvalue;
char location;
};
//Function List
void readPlayers(player *peoplePointer);
void shuffleCards(card *unshuffled, card* shuffled);
//program
int main()
{
//create pointer and set initial value
card * deckPointer = new card[52];
card *deckHome = &deckPointer[0];
for(int i=0;i<maxCards;i++)
{
(*deckPointer).suit=new char[8];
(*deckPointer).rank = new char[7];
deckPointer++;
}
deckPointer = deckHome;
cardInit(deckPointer);
readDeck(deckPointer);
//sets default values for the card arrays
for(int i=0;i<52;i++)
{
strcopy((*deckPointer).suit,"suit");
strcopy((*deckPointer).rank,"rank");
(*deckPointer).cvalue = 0;
deckPointer++;
}
deckPointer = deckHome;
return 0;
}
//Functions
void cardInit(card *deckPointer)
{
card * deckHome = NULL;
deckHome = &deckPointer[0];
//set up card file to be read in
ifstream fin;
char *finName = new char[13];
//get file name from user
cout << "Enter file name...(cardFile.txt)" << endl;;
cin >> *finName;
//open the file
fin.open(finName);
//check if cardFile.txt opens correctly
if(!fin.good())
{
cout << "Error with card file" << endl;
}
else
{
deckPointer = deckHome;
while(fin.good())
{
for(int i=0;i<50;i++)
{
fin >> (*deckPointer).suit;
fin >> (*deckPointer).rank;
fin >> (*deckPointer).cvalue;
deckPointer++;
}
}
}
delete [] finName;
}
//Its a pretty simple program..and my dynamic memory works for
//the file name, but I cant figure out why it doesnt work for structs?
For your code to work, you will need a typename card.
to this end you will need to setup the following:
struct cardstruct {
char *suit;
char *rank;
int cvalue;
};
typedef struct cardstruct card;
otherwise, when you declare the pointers, you would need to use the "struct" keword first. E.G.:
struct card *deckPtr = new struct card[52];

Constructors and array of object in 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) );
}