Initializing a dynamic memory array in a class - c++

I am new to c++ programming, and this is probably a trivial problem, but I need to construct a variable sized array in a class and transfer text file data into it, see below. Here HISTORYFile >> ClusterCoord[i]; seems to take in the information fine, however when I try to get access to the info in the main program via,
cout << CoordClassExample.ClusterCoord[1] << "\n";
I get a bus error. Please help if you can!
class CoordClass{
public:
int Entries;
double * ClusterCoord;
void set_valuesCoord(ifstream &HISTORYFile,int MolAtomNum, int MolNum);
};
void CoordClass::set_valuesCoord(ifstream& HISTORYFile,int MolAtomNum, int MolNum) {
Entries=MolAtomNum*MolNum;
double *ClusterCoord = new double [Entries];
for (int i=0;i<Entries;i++) {
HISTORYFile.ignore(1000,'\n');
HISTORYFile >> ClusterCoord[i];
cout << ClusterCoord[i] << "\n";
HISTORYFile.ignore(1000,'\n');
}
}

You have a leak in the set_valuesCoord() function if you call the function twice, unless you somewhere release the resources. That's not the problem but it's a problem. Use a std::vector<>.
class CoordClass {
// ...
std::vector<double> ClusterCoord; // instead of double *ClusterCoord
// ...
};
What might be the problem is that you don't check whether the double parsed properly. If it didn't then you're accessing uninitialized memory, and that leads to undefined behaviour.
void CoordClass::set_valuesCoord(...)
{
// ...
double cluster_coord = 0;
if( HISTORYFile >> cluster_coord )
ClusterCoord.push_back(cluster_coord);
else
std::cerr << "Error parsing cluster coord.\n";
// ...
}

As an exercise showing the vector way that won't leak among other things:
Further changes would be to remove Entries and use ClusterCoord.size().
class CoordClass{
public:
int Entries;
std::vector<double> ClusterCoord;
void set_valuesCoord(ifstream &HISTORYFile,int MolAtomNum, int MolNum);
};
void CoordClass::set_valuesCoord(ifstream& HISTORYFile,int MolAtomNum, int MolNum) {
Entries=MolAtomNum*MolNum;
ClusterCoord.resize(Entries);
for (int i=0;i<Entries;i++) {
HISTORYFile.ignore(1000,'\n');
HISTORYFile >> ClusterCoord[i];
cout << ClusterCoord[i] << "\n";
HISTORYFile.ignore(1000,'\n');
}
}

Related

C++ Segmentation fault while dereferencing a void pointer to a vector

#include <iostream>
#include <vector>
#include <mutex>
struct STRU_Msg
{
std::string name;
void *vpData;
};
class CMSG
{
public:
template <typename T>
int miRegister(std::string name)
{
STRU_Msg msg;
msg.name = name;
msg.vpData = malloc(sizeof(T));
msgtable.push_back(msg);
std::cout << "registeratio ok\n";
return 0;
}
template <typename T>
int miPublish(std::string name, T tData)
{
for (int i = 0; i < msgtable.size(); i++)
{
if (!name.compare(msgtable[i].name))
{
(*(T *)msgtable[i].vpData) = tData;
std::cout << "SUccess!\n";
return 0;
}
else
{
std::cout << "cannot find\n";
return 0;
}
}
}
private:
std::vector<STRU_Msg> msgtable;
};
int main()
{
CMSG message;
std::string fancyname = "xxx";
std::vector<float> v;
// message.miRegister< std::vector<float> >(fancyname);
// for (int i = 0; i < 1000; i++)
// {
// v.push_back(i);
// }
// std::cout << "v[0]: " << v[0] << ", v[-1]: " << v[v.size()-1] << '\n';
// message.miPublish< std::vector<float> >(fancyname, v);
for (int i = 0; i < 1000; i++)
{
v.push_back(i);
}
std::cout << "v[0]: " << v[0] << ", v[-1]: " << v[v.size()-1] << '\n';
message.miRegister< std::vector<float> >(fancyname);
message.miPublish< std::vector<float> >(fancyname, v);
return 0;
}
What I want to achieve is to write a simple publish/subscribe (like ROS) system, I use void pointer so that it works for all data type. This is the simplified code.
If I publish an int, it works fine, but what really confuse me are:
If I pass a long vector (like this code), it gave me the
"segmentation fault (core dump)" error.
If I define the vector between "register" and "publish" (i.e. like
the commented part), this error goes away.
If I use a shorter vector, like size of 10, no matter where I define
it, my code run smoothly.
I use g++ in Linux.
Please help me fix my code and explain why above behaviors will happen, thanks in ahead!
You cannot copy std::vector or any other non-trivial type like that. Before you do anything (even assignment-to) with such an object, you need to construct it using a constructor and placement new.
A way to do this would be
new(msgtable[i].vpData) T;
Do this in the register function.
Then you can assign a value as you do.
Still better, do not use malloc at all, allocate your object with (normal, non-placement) new.
I however strongly suggest ditching void* and moving to a template based implementation of STRU_Msg. If you don't feel like reinventing the wheel, just use std::any.

Through what to call the method, if I already created constructor with initialization of array of structures?

I'm trying to call the method displayChoices, member of the class MachineManager through the object of the class. But I already have a constructor with initializing of the array of structures. How I understood when we create an object of the class compiler implicitly create a default constructor of the class.
Question: How to call method displayChoices?
#include "MachineManager.h"
using namespace std;
int main()
{
MachineManager mjp;
mjp.displayChoices();
return 0;
}
struct BrewInfo {
string* DrinkName;
double* Cost;
int* Number;
};
class MachineManager {
static const int Num_Drinks = 3; /// why it works only with static?!!!
BrewInfo* BrewArr[Num_Drinks];
public:
MachineManager()
{
*BrewArr[0]->Cost = 1.25;
*BrewArr[0]->Number = 20;
*BrewArr[1]->DrinkName = "pepsi";
*BrewArr[1]->Cost = 1.15;
*BrewArr[1]->Number = 17;
*BrewArr[2]->DrinkName = "Aloe";
*BrewArr[2]->Cost = 2.00;
*BrewArr[2]->Number = 15;
};
int displayChoices();
}
int MachineManager::displayChoices() // (which displays a menu of drink names and prices)
{
cout << 1;
int choice;
cout << "|1." << *BrewArr[0]->DrinkName << " |2." << *BrewArr[1]->DrinkName << " |3." << *BrewArr[2]->DrinkName << " |" << endl;
cin >> choice;
if (!choice || choice == 0) {
system("slc");
displayChoices();
}
else
return choice;
}
displayChoices has to print a menu in console.
You have a majo bug in your source code. You do not yet understand, how pointer work.
You are defining an array of pointer with BrewInfo* BrewArr[Num_Drinks];.
But these pointers are not initialized. They point to somewhere. Then you are dereferencing those pointers (pointing to somewhere) and assigning a value to somewhere in the memory.
This is a major bug.
The array dimensions for C-Sytle arrays must be a compile time constant.
You cannot write
int x=3;
unt array[x];
This is C99 code (called VLA, Variable length array), but not C++.
Solution for you problem:
Do never use C-Style arrays, like int array[5]. Use STL container like std::vector instead.
Do not use pointers.
This is your major problem. Define your array with BrewInfo BrewArr[Num_Drinks];. Please remove also the pointer from
struct BrewInfo {
string* DrinkName;
double* Cost;
int* Number;
};

How to save values to pointers in function and use the returned pointer to print out values stored in pointer

I am a beginner in programming, I am trying to solve the problem I encountered in my assignment.
Here I want to read a file and save each word as an element in a pointer pointing array.
I declared pointer in Array class and reading the file in ReadAcc class. I am trying to process it outside these two classes.
class ReadAcc {
private:
double*_customerBalanceArray;
double read1;
ifstream f;
int counter = 0;
public:
ReadAcc() {
_customerBalanceArray = new double[100];
}
int GetCounter() {
return counter;
}
void Reading(string path)
{
f.open(path);
while (!f.eof())
{
f >> read1;
_customerBalanceArray[counter] = read1;
counter++;
}
f.close();
}
double* GetPointer() {
return _customerBalanceArray;
}
void DeletePointer() {
delete[] _customerBalanceArray;
}
};
int main()
{
ReadAcc read;
read.Reading("acc.txt");
for (int i = 0; i < read.GetCounter(); i=i+2)
{
//cout << "Acc# " << *(a.getCustomerBlanceArray) << " Balance: " << *(a.getCustomerBlanceArray) << endl;
}
read.DeletePointer();
}
When it compiles, the error says Exception thrown: read access violation.
Access violation writing location 0x013CE000. The pointer _customerBalanceArray value is now 0x013CE000. I do not know where it went wrong. Please help me. Thanks a million!!!

Run time error for dynamic memory allocation in C++

I am a newbie for OOP concepts and while trying to solve Project Euler Problem 7, to find 10001th prime number, I tried to do it using a class but encountered 2 major errors.
instantiating the class prime_n
initializing its argument
I have posted the code here for reference:
#include<iostream>
#include<cstdio>
using namespace std;
class prime_n
{
int j,k;
int n;
int *store;
public:
prime_n(int num)
{
n=num;
store[n];
}
static int isPrime(int j)
{
for(int i=2;i*i<=j;i++)
{
if(j%i==0) return 0;
}
return 1;
}
void find_n()
{
for(int i=0;i<n;i++)
{
store[i]=0;
}
store[0]=2;
j=3;
k=1;
while(store[n-1]==0)
{
if(isPrime(j)) store[k++]=j;
j+=2;
}
}
int get_num()
{
int value=store[n-1];
return value;
}
};
int main()
{
int num, req_num;
printf("Enter the position at which prime number is to be found ");
scanf("%d",&num);
printf("\nnumber = %d",num);
prime_n p = new prime_n(num);
req_num = p.get_num();
printf("The required prime number is %d\n",req_num);
return 0;
}
It would be a great help if someone could help me figure out where I am actually going wrong. Thanks a lot in advance!
Use
prime_n p(num);
or (not recommended in this particular case)
prime_n * p = new prime_n(num);
// some other code
req_num = p->get_num(); // note the -> operator replacing . in case of pointers
delete p;
The first case declares p on stack and it is automatically deallocated when the program leaves the scope (main function in this case)
The second one allocates space on heap and p is the pointer to it. You have to deallocate the memory manually.
As for your second question, the C++ way would be
#include <iostream>
...
int num;
std::cout << "Enter the position at which prime number is to be found "
std::cin >> num;
std::cout << std::endl << "Number = " << num << std::endl;
You provide a constructor:
prime_n(int num)
{
n=num;
store[n];
}
I think you are under the impression that store[n] creates an array with n elements, but that is not so; it attempts to access the (n+1)th element of an an array. Since store does not point anywhere (we are in the constructor, after all), the program crashes.
You probably want to write store = new int[num] instead.
And then I cannot see any call to find_n() originating from get_num() which is called in main(), so that your program would for now just return a random value.

Segmentation Fault when trying to push a string to the back of a list

I am trying to write a logger class for my C++ calculator, but I'm experiencing a problem while trying to push a string into a list.
I have tried researching this issue and have found some information on this, but nothing that seems to help with my problem. I am using a rather basic C++ compiler, with little debugging utilities and I've not used C++ in quite some time (even then it was only a small amount).
My code:
#ifndef _LOGGER_H_
#define _LOGGER_H_
#include <iostream>
#include <list>
#include <string>
using std::cout;
using std::cin;
using std::endl;
using std::list;
using std::string;
class Logger
{
private:
list<string> mEntries;
public:
Logger() {}
~Logger() {}
// Public Methods
void WriteEntry(const string& entry)
{
mEntries.push_back(entry);
}
void DisplayEntries()
{
cout << endl << "**********************" << endl
<< "* Logger Entries *" << endl
<< "**********************" << endl
<< endl;
for(list<string>::iterator it = mEntries.begin();
it != mEntries.end(); it++)
{
// *** BELOW LINE IS MARKED WITH THE ERROR ***
cout << *it << endl;
}
}
};
#endif
I am calling the WriteEntry method by simply passing in a string, like so:
mLogger->WriteEntry("Testing");
Any advice on this would be greatly appreciated.
* CODE ABOVE HAS BEEN ALTERED TO HOW IT IS NOW *
Now, the line:
cout << *it << endl;
causes the same error. I'm assuming this has something to do with how I am trying to get the string value from the iterator.
The code I am using to call it is in my main.cpp file:
#include <iostream>
#include <string>
#include <sstream>
#include "CommandParser.h"
#include "CommandManager.h"
#include "Exceptions.h"
#include "Logger.h"
using std::string;
using std::stringstream;
using std::cout;
using std::cin;
using std::endl;
#define MSG_QUIT 2384321
#define SHOW_LOGGER true
void RegisterCommands(void);
void UnregisterCommands(void);
int ApplicationLoop(void);
void CheckForLoggingOutput(void);
void ShowDebugLog(void);
// Operations
double Operation_Add(double* params);
double Operation_Subtract(double* params);
double Operation_Multiply(double* params);
double Operation_Divide(double* params);
// Variable
CommandManager *mCommandManager;
CommandParser *mCommandParser;
Logger *mLogger;
int main(int argc, const char **argv)
{
mLogger->WriteEntry("Registering commands...\0");
// Make sure we register all commands first
RegisterCommands();
mLogger->WriteEntry("Command registration complete.\0");
// Check the input to see if we're using the program standalone,
// or not
if(argc == 0)
{
mLogger->WriteEntry("Starting application message pump...\0");
// Full version
int result;
do
{
result = ApplicationLoop();
} while(result != MSG_QUIT);
}
else
{
mLogger->WriteEntry("Starting standalone application...\0");
// Standalone - single use
// Join the args into a string
stringstream joinedStrings(argv[0]);
for(int i = 1; i < argc; i++)
{
joinedStrings << argv[i];
}
mLogger->WriteEntry("Parsing argument '" + joinedStrings.str() + "'...\0");
// Parse the string
mCommandParser->Parse(joinedStrings.str());
// Get the command names from the parser
list<string> commandNames = mCommandParser->GetCommandNames();
// Check that all of the commands have been registered
for(list<string>::iterator it = commandNames.begin();
it != commandNames.end(); it++)
{
mLogger->WriteEntry("Checking command '" + *it + "' is registered...\0");
if(!mCommandManager->IsCommandRegistered(*it))
{
// TODO: Throw exception
mLogger->WriteEntry("Command '" + *it + "' has not been registered.\0");
}
}
// Get each command from the parser and use it's values
// to invoke the relevant command from the manager
double results[commandNames.size()];
int currentResultIndex = 0;
for(list<string>::iterator name_iterator = commandNames.begin();
name_iterator != commandNames.end(); name_iterator++)
{
string paramString = mCommandParser->GetCommandValue(*name_iterator);
list<string> paramStringArray = StringHelper::Split(paramString, ' ');
double params[paramStringArray.size()];
int index = 0;
for(list<string>::iterator param_iterator = paramStringArray.begin();
param_iterator != paramStringArray.end(); param_iterator++)
{
// Parse the current string to a double value
params[index++] = atof(param_iterator->c_str());
}
mLogger->WriteEntry("Invoking command '" + *name_iterator + "'...\0");
results[currentResultIndex++] =
mCommandManager->InvokeCommand(*name_iterator, params);
}
// Output all results
for(int i = 0; i < commandNames.size(); i++)
{
cout << "Result[" << i << "]: " << results[i] << endl;
}
}
mLogger->WriteEntry("Unregistering commands...\0");
// Make sure we clear up our resources
UnregisterCommands();
mLogger->WriteEntry("Command unregistration complete.\0");
if(SHOW_LOGGER)
{
CheckForLoggingOutput();
}
system("PAUSE");
return 0;
}
void RegisterCommands()
{
mCommandManager = new CommandManager();
mCommandParser = new CommandParser();
mLogger = new Logger();
// Known commands
mCommandManager->RegisterCommand("add", &Operation_Add);
mCommandManager->RegisterCommand("sub", &Operation_Subtract);
mCommandManager->RegisterCommand("mul", &Operation_Multiply);
mCommandManager->RegisterCommand("div", &Operation_Divide);
}
void UnregisterCommands()
{
// Unregister each command
mCommandManager->UnregisterCommand("add");
mCommandManager->UnregisterCommand("sub");
mCommandManager->UnregisterCommand("mul");
mCommandManager->UnregisterCommand("div");
// Delete the logger pointer
delete mLogger;
// Delete the command manager pointer
delete mCommandManager;
// Delete the command parser pointer
delete mCommandParser;
}
int ApplicationLoop()
{
return MSG_QUIT;
}
void CheckForLoggingOutput()
{
char answer = 'n';
cout << endl << "Do you wish to view the debug log? [y/n]: ";
cin >> answer;
switch(answer)
{
case 'y':
ShowDebugLog();
break;
}
}
void ShowDebugLog()
{
mLogger->DisplayEntries();
}
// Operation Definitions
double Operation_Add(double* values)
{
double accumulator = 0.0;
// Iterate over all values and accumulate them
for(int i = 0; i < (sizeof values) - 1; i++)
{
accumulator += values[i];
}
// Return the result of the calculation
return accumulator;
}
double Operation_Subtract(double* values)
{
double accumulator = 0.0;
// Iterate over all values and negativel accumulate them
for(int i = 0; i < (sizeof values) - 1; i++)
{
accumulator -= values[i];
}
// Return the result of the calculation
return accumulator;
}
double Operation_Multiply(double* values)
{
double accumulator = 0.0;
for(int i = 0; i < (sizeof values) - 1; i++)
{
accumulator *= values[i];
}
// Return the value of the calculation
return accumulator;
}
double Operation_Divide(double* values)
{
double accumulator = 0.0;
for(int i = 0; i < (sizeof values) - 1; i++)
{
accumulator /= values[i];
}
// Return the result of the calculation
return accumulator;
}
Did you remember to call mLogger = new Logger at some point? Did you accidantally delete mLogger before writing to it?
Try running your program in valgrind to see whether it finds any memory errors.
After your edit, the solution seem clear:
Your first line in main() is :
mLogger->WriteEntry("Registering commands...\0");
Here mLogger is a pointer that has never been initialized. This is "undefined behaviour", meaning anything can appen, often bad things.
To fix this you can either make it a "normal" variable, not a pointer or create a Logger instance using new (either at the declaration or as the first line in main).
I suggest you to not use a pointer to be sure the logger is always there and is automatically destroyed.
By the way, it seems like you want to create every instance of objects on the heap using pointers. It's not recommanded if it's not necessary. You should use pointers ONLY if you want to explicitely state the creation (using new) and destruction (using delete) of the instance object. If you just need it in a specific scope, don't use a pointer. You might come from another language like Java or C# where all objects are referenced. If so, you should start learning C++ like a different language to avoid such kind of problem. You should learn about RAII and other C++ scpecific paradigm that you cannot learn in those languages. If you come from C you should too take it as a different language. That might help you avoid complex problems like the one you showed here. May I suggest you read some C++ pointer, references and RAII related questions on stackoverflow.
First, you don't need to create the std::list on the heap. You should just use it as a normal member of the class.
class Logger
{
private:
list<string> mEntries; // no need to use a pointer
public:
Logger() // initialization is automatic, no need to do anything
{
}
~Logger() // clearing and destruction is automatic too, no need to do anything
{
}
//...
};
Next, entryData don't exist in this code so I guess you wanted to use entry. If it's not a typo then you're not providing the definition of entryData that is certainly the source of your problem.
In fact I would have written your class that way instead:
class Logger
{
private:
list<string> mEntries;
public:
// no need for constructor and destructor, use the default ones
// Public Methods
void WriteEntry(const string& entry) // use a const reference to avoid unnecessary copy (even with optimization like NRVO)
{
mEntries.push_back( entry ); // here the list will create a node with a string inside, so this is exactly like calling the copy constructor
}
void DisplayEntries()
{
cout << endl << "**********************" << endl
<< "* Logger Entries *" << endl
<< "**********************" << endl
<< endl;
for(list<string>::iterator it = mEntries.begin();
it != mEntries.end(); ++it) // if you want to avoid unnecessary copies, use ++it instead of it++
{
cout << *it << endl;
}
}
};
What's certain is that your segfault is from usage outside of this class.
Is an instance of Logger being copied anywhere (either through a copy constructor or operator=)? Since you have mEntries as a pointer to a list, if you copy an instance of Logger, they will share the value of the pointer, and when one is destructed, it deletes the list. The original then has a dangling pointer. A quick check is to make the copy constructor and operator= private and not implemented:
private:
void operator=(const Logger &); // not implemented
Logger(const Logger &); // not implemented
When you recompile, the compiler will flag any copies of any Logger instances.
If you need to copy instances of Logger, the fix is to follow the Rule of 3:
http://en.wikipedia.org/wiki/Rule_of_three_%28C%2B%2B_programming%29
You can do this by eliminating the need for the destructor (by not using a pointer: list<string> mEntries), or by adding the needed code to the copy constructor and operator= to make a deep copy of the list.
You only need to do
list<string> entries;
entries.push_back();
You do not need to create a pointer to entries.
Nothing too obvious, though you typed
mEntries->push_back(string(entryData));
and I htink you meant entry instead of entryData. You also don't need the string conversion on that line, and your function should take entry by const reference.
However, none of these things would cause your program to segfault. What compiler are you using?
You're missing the copy constructor. If the Logger object is copied and the original deleted, you'll be dereferencing memory that was previously deleted.
A simplified example of the problem
Logger a;
{
Logger b;
a=b;
}
a.WriteEntry("Testing");
Add a copy constructor.
Logger(const Logger& item)
{
mEntries = new list<string>();
std::copy(item.mEntries->begin(), item.mEntries->end(), std::back_inserter(*mEntries));
}