I have the following problem:
I have main executable program called algatorc. In this program, I have class called TestCase, AbsAlgorithm and TestSetIterator. End user must create new algatorc program and then inherits these three classes.
Let's say that end user creates project Sorting. He would end up with three classes called SortingTestCase, SortingTestSetIterator and SortingAbsAlgorithm.
So here is the thing. End user has a method SortingTestSetIterator::get_current and return type of this function is TestCase*. In this method, he creates instance of SortingTestCase and return this instance. So he actually returned child of TestCase. In my main program I save this pointer to TestCase *t (and no, I can't save it as SortingTestCase, because before runtime, I don't know the name of the project) and then I send this pointer to method SortingAbsAlgorithm::init(TestCase* test_case). In this particulary method, end user will probably cast this object to his (SortingTestCase), and this is done like this:
sorting_test_case = dynamic_cast<SortingTestCase*>(test);
This SortingTestCase is derived from TestCase and has all members from parent class and two variables of his own: array and size. So when in init method I say
for (int i = 0; i<sorting_test_case->size; i++)
{
std::cout << sorting_test_case[i] << std::endl;
}
then I get nothing. It seems like array is empty.
Any idea what am I doing wrong?
Edit:
class SortingAbsAlgorithm : public AbsAlgorithm
{
private:
SortingTestCase *sorting_test_case;
public:
bool init (TestCase *test)
{
sorting_test_case = dynamic_cast<SortingTestCase*>(test);
std::cout << "INIT ARRAY" << std::endl;
for (int i = 0; i<sorting_test_case->size; i++)
{
std::cout << sorting_test_case->array_to_sort[i] << " ";
}
}
};
class SortingTestCase : public TestCase
{
public:
int size;
int *array_to_sort;
void init_array(int tab[], int size)
{
array_to_sort = new int[size];
for (int i = 0; i<size; i++)
{
array_to_sort[i] = tab[i];
}
}
};
class SortingTestSetIterator : public TestSetIterator
{
private:
std::string file_path;
std::string test_file_name;
public:
TestCase *get_current()
{
if (current_input_line.empty())
{
return nullptr;
}
std::vector<std::string> fields;
std::string token;
std::stringstream str(current_input_line);
while ( getline(str, token, ':') )
{
fields.push_back(token);
}
str.clear();
if (fields.size() < 3)
{
report_invalid_data_format("to few fields");
return nullptr;
}
std::string test_name = fields.at(0);
int prob_size;
try
{
prob_size = std::atoi(fields.at(1).c_str());
} catch (...)
{
report_invalid_data_format("'n' is ot a number");
}
std::string group = fields.at(2);
std::string test_id = "Test-" + std::to_string(line_number);
EParameter *test_id_par = new EParameter("TestID", "Test identificator", test_id);
EParameter *parameter1 = new EParameter("Test", "Test name", test_name);
EParameter *parameter2 = new EParameter("N", "Number of elements", std::to_string(prob_size));
EParameter *parameter3 = new EParameter("Group", "A name of a group of tests", group);
SortingTestCase *t_case = new SortingTestCase();
t_case->addParameter(*test_id_par);
t_case->addParameter(*parameter1);
t_case->addParameter(*parameter2);
t_case->addParameter(*parameter3);
int arr[prob_size];
int i = 0;
if (group == "INLINE")
{
if (fields.size() < 4)
{
report_invalid_data_format("to few fields");
return nullptr;
}
std::vector<std::string> data;
std::stringstream ss(fields.at(3));
while (getline(ss, token, ' ') )
{
data.push_back(token);
}
if (data.size() != prob_size)
{
report_invalid_data_format("invalid number of inline data");
return nullptr;
}
try
{
for (i = 0; i<prob_size; i++)
{
arr[i] = std::atoi(data.at(i).c_str());
}
} catch (...)
{
report_invalid_data_format("invalid type of inline data - data " + std::to_string((i+1)));
return nullptr;
}
}
else if (group == "RND")
{
srand(time(NULL));
for (i = 0; i<prob_size; i++)
{
arr[i] = rand() % prob_size + 1000;
}
}
else if (group == "SORTED")
{
for (i = 0; i<prob_size; i++)
{
arr[i] = i;
}
}
else if (group == "INVERSED")
{
for (i = 0; i<prob_size; i++)
{
arr[i] = prob_size - i;
}
}
t_case->init_array(arr, prob_size);
return t_case;
}
};
This are end users classes. I create library out of this classes and I load them in my program via dlopen and dlsym. I get instance of classes like this:
#ifdef __cplusplus
extern "C" {
#endif
TestSetIterator * create_iterator_object() {
return new SortingTestSetIterator;
}
void destroy_iterator_object(TestSetIterator* object) {
delete object;
}
#ifdef __cplusplus
}
and then in my main program I load symbol create_iterator_object
create_it = (TestSetIterator* (*)())dlsym(handle, "create_iterator_object");
and then I say this:
TestSetIterator *it = (TestSetIterator*)create_it();
I can call it->get_current() which loads line from file to variable curent_input_line. So I do this:
TestCase *t_case = it->get_current();
and then I say
a->init(t_case)
a is here actually SortingAbsAlgorithm loaded exactly the same as TestSetIterator (ofcourse, different symbol) and is "saved" into AbsAlgorithm a*.
So when a->init(t_case) is called, then in this init end-user cast t_case this is type of TestCase to SortingTestCase. And when I want to print elements in array, array is empty.
Related
How to send an array of structs into a function as a parameter?
The employee variable is a struct.
My function:
void arraySort(struct Employee *employee[])
{
bool flag = false;
for (int i = 0; i < 5000; i++)
{
int empID1 = employee[i]->empID;
int empID2 = employee[i + 1]->empID;
flag = Employee().compareEmpID(empID1, empID2);
if (flag == true)
{
Employee swap;
swap = *employee[i + 1];
*employee[i] = *employee[i + 1];
*employee[i + 1] = swap;
}
}
}
Which calls this function:
bool Employee::compareEmpID(int empID1, int empID2)
{
if (empID1 >= empID2)
return true;
return false;
}
I am trying to invoke a call to the arraySorts function from main by using the employee array struct as a pointer:
arraySort(*employee);
The function compareEmpID have to be a static method in struct employee and invoked by calling as Employee::compareEmpID.
There are some issues in for your arraySort method.
You hard code the number 5000, that means your array need to have 5000 elements or more, otherwise you will get error about illegal memory access.
The variable swap should be a pointer and declared outside of the for loop.
Your swap logic is wrong.
I rewrite the program base on your code and tested it.
#include<iostream>
using namespace std;
struct Employee {
int empID;
static bool compareEmpID(int empID1, int empID2) {
return empID1 > empID2;
}
};
void arraySort(Employee *employees[], int size) {
bool flag = false;
Employee *swap;
for(int i=0; i<size-1; i++) {
int empID1 = employees[i]->empID;
int empID2 = employees[i+1]->empID;
flag = Employee::compareEmpID(empID1,empID2);
if(flag) {
swap = employees[i+1];
employees[i+1] = employees[i];
employees[i] = swap;
}
}
}
int main(int argc, char* args[]) {
Employee** employee;
employee = new Employee*[2];
employee[0] = new Employee;
employee[0]->empID = 5;
employee[1] = new Employee;
employee[1]->empID = 1;
arraySort(employee, 2);
cout << "emp[0]: " << employee[0]->empID << endl;
cout << "emp[1]: " << employee[1]->empID << endl;
delete employee[0];
delete employee[1];
delete[] employee;
return 0;
}
Hope this helps you boots your learning progress.
I am working on a sample test in the site: https://www.testdome.com/for-developers/solve-question/9808
I added two destructors for base class and derived class respectively to release the memory allocated by constructors. The first two requirements of this question are solve successfully, but the result give a fail as: Using timed multiple choice test as multiple choice test: Memory limit exceeded
My modified code as given below, I will appreciate if you can help to fix the fail...
#include <iostream>
#include <string>
class MultipleChoiceTest
{
public:
MultipleChoiceTest(int questionsCount)
{
this->questionsCount = questionsCount;
answers = new int[questionsCount];
for (int i = 0; i < questionsCount; i++)
{
answers[i] = -1;
}
}
void setAnswer(int questionIndex, int answer)
{
answers[questionIndex] = answer;
}
int getAnswer(int questionIndex) const
{
return answers[questionIndex];
}
~MultipleChoiceTest()
{
delete answers; // release memory
}
protected:
int questionsCount;
private:
int* answers;
};
class TimedMultipleChoiceTest : public MultipleChoiceTest
{
public:
TimedMultipleChoiceTest(int questionsCount)
: MultipleChoiceTest(questionsCount)
{
times = new int[questionsCount];
for (int i = 0; i < questionsCount; i++)
{
times[i] = 0;
}
}
void setTime(int questionIndex, int time)
{
times[questionIndex] = time;
}
int getTime(int questionIndex) const
{
return times[questionIndex];
}
~TimedMultipleChoiceTest()
{
delete times; // release memory
}
private:
int* times;
};
#ifndef RunTests
void executeTest()
{
MultipleChoiceTest test(5);
for (int i = 0; i < 5; i++)
{
test.setAnswer(i, i);
}
for (int i = 0; i < 5; i++)
{
std::cout << "Question " << i + 1 << ", correct answer: " << test.getAnswer(i) << "\n";
}
}
int main()
{
for (int i = 0; i < 3; i++)
{
std::cout << "Test: " << i + 1 << "\n";
executeTest();
}
}
#endif
you should use delete [] instead of delete to deallocate dynamic arrays.
Also, you don't seem to use the derived class but, nevertheless, the destructor in MultipleChoiceTest should be virtual
When I use the object function set_and_make_variable I send it a name and value which both work correctly. However then when I go to use show current_variables it acts like I never set the values for both integers, and integers_names. I thought you could modify the variables arrays from the functions associated with the class without references or pointers.
Am I not correct?
void reset_name(string *variable_names)
{
for (int i = 0; i < 100; i++)
{
variable_names[i] = "";
}
}
void reset_int_value(int *variable_value)
{
for (int i = 0; i < 100; i++)
{
variable_value[i] = 0;
}
}
int find_next(string variable_names[100])
{
for (int i = 0; i < 100; i++)
{
if (variable_names[i] == "")
{
return i;
}
}
}
//*****************************************************************
class variables_integers
{
public:
string integer_names[100];
int integers[100];
variables_integers(void);
void set_and_make_variable(string, int);
void show_current_variables(void);
};
variables_integers::variables_integers(void)
{
reset_int_value(integers);
reset_name(integer_names);
}
void variables_integers::show_current_variables(void)
{
cout << "INTEGERS:" << endl;
for (int i = 0; i < (find_next(integer_names)); i++)
{
cout << integer_names[i] << " = " << integers[i] << endl;
}
}
void variables_integers::set_and_make_variable(string name, int value)
{
cout << name << " " << value << endl;
cout << find_next(integer_names) << endl;
integers[find_next(integer_names)] = value;
integer_names[find_next(integer_names)] = name;
}
//*** added code ******
bool operations_and_declerations(string parsed_input[3000], variables variable)
{
if (parsed_input[0] == "int")
{
if (parsed_input[2] == "=")
{
variable.integers.set_and_make_variable(parsed_input[1], atoi(parsed_input[3].c_str()));
}
return true;
}
else if (parsed_input[0] == "string")
{
return true;
}
//else if (parsed_input[0] ==)
else
{
return false;
}
}
In operations_and_declerations(), you sent your variables parameter by value. Hence, the function created a local copy, and only modified that local copy.
You can fix the problem by sending it the parameter by reference. Just modify the function name to:
bool operations_and_declerations(string parsed_input[3000], variables & variable)
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 8 years ago.
Improve this question
So I'm making a program for class and I have a header file called "Item" and I have a class inside my main file called "Room" and I'm trying to make a method that returns type Item and Cygwin is giving me pages and pages of errors!
Here's my code so far:
Item Header File:
class Item
{
std::string description;
public: Item (std::string newDescription)
{
description = newDescription;
}
public: std::string getDescription()
{
return description;
}
};
Here's the main Class:
#include <iostream>
#include <string>
#include "Item.h"
class Room
{
std::string description;
int exits[2][4];
std::string items[10];
Room(std::string description)
{
this -> description = description;
}
void setExit (int direction, int neighbor) //Direction - 1=N, 2=E, 3=S, 4-W
{
for (int i = 0; i < 4; i++)
{
if (exits[0][i] == NULL)
{
exits[0][i] = neighbor;
exits[1][i] = direction;
break;
}
}
}
std::string getShortDescription()
{
return description;
}
std::string getLongDescription()
{
return "You are " + description + ".\n" + getExitString();
}
std::string getExitString()
{
std::string returnString = "Exits:";
for (int i = 0; i < 4; i++)
{
if (exits[1][i] != NULL)
{
std::string tempDirection;
switch(exits[1][i])
{
case 1: tempDirection = "North";
break;
case 2: tempDirection = "East";
break;
case 3: tempDirection = "South";
break;
case 4: tempDirection = "West";
break;
}
returnString += " " + tempDirection;
}
else
{
break;
}
}
returnString += "\nItems in the room:\n";
//returnString += getRoomItems();
return returnString;
}
/*Item getItem(std::string itemName)
{
int size = 0;
for (int i = 0; i < 10; i++)
{
if (items[i] == NULL)
{
break;
}
else
{
size++;
}
}
for (int i = 0; i < size; i++)
{
if (items[i] == itemName)
{
return items[i];
}
}
}*/
int getExit(int direction)
{
for (int i = 0; i < 4; i++)
{
if (exits[1][i] == direction)
{
return exits[0][i];
}
}
}
};
using namespace std;
int main()
{
}
Putting the error on here will take forever so I'm going to skip it sorry!
Any help would be super helpful!
There are several problems with your proposed implementation of this method:
Item getItem(std::string itemName)
{
int size = 0;
for (int i = 0; i < 10; i++)
{
// items[i] is of type std::string, which is a value type, not a pointer. It
// makes no sense to compare it to null, because it can't even be null.
if (items[i] == NULL)
{
break;
}
else
{
size++;
}
}
for (int i = 0; i < size; i++)
{
if (items[i] == itemName)
{
// Here you return an std::string, not an Item -- however, Item contains
// a one-argument constructor accepting std::string and is not marked
// "explicit", so this line is equivalent to "return Item(items[i]);".
// This may or may not be what you intended, but would not cause a
// compile-time error.
return items[i];
}
}
// You do not return anything if program flow makes it to this point. This
// causes an undefined value to be returned, and you don't want that. You need
// to return something here -- but it can't be null, because Item is a value
// type!
}
Consider instead using std::vector<std::string> as the type of items. A vector is a variable-length container that can grow automatically. (Think Java's List<>.) Or, perhaps you want to map item names to Item instances, in which case you might use std::map<std::string, Item>.
I have an array of objects that have a vector as a class member (actually it is a struct). The struct is:
struct Cell {
vector<int> borderNodes;
vector<int> helperNodes;
int minNodePointer;
int maxNodePointer;
Cell() {
minNodePointer = -1;
maxNodePointer = -1;
}
Cell(int _minNodePointer, int _maxNodePointer) {
minNodePointer = _minNodePointer;
maxNodePointer = _maxNodePointer;
}
vector<int>& getHelperNodes() {
return helperNodes;
}
vector<int>& getBorderNodes() {
return borderNodes;
}
void setHelperNodesArray() {
sort(helperNodes.begin(), helperNodes.end());
}
void setBorderNodesArray() {
sort(borderNodes.begin(), borderNodes.end());
}
};
I have built an array of those objects as a global variable with :
Cell* cells = new Cell[maxNumberOfCells];
and I want to add some integers to the vectors inside the objects.
I tried this (inside a function):
cells[cellId].borderNodes.push_back(node_id);
or
cells[cellId].getBorderNodes().push_back(node_id);
and they compile fine, but nothing is added to the vector. How is the correct way to do this? Here is the function that reads from a db, and adds the integers. The query and reading from db is correct, so no mistakes there.
void loadBorderNodesPerCellBnOnly(bool shouldRearrangeNodes, int subtractor, int maxNumberOfCells, int** cellBorderNodes) {
cellBorderNodes = new int*[maxNumberOfCells];
try {
work W(Conn);
for (int rownum = 0; rownum < r.size(); ++rownum) {
const result::tuple row = r[rownum];
vector<string> s = split(row[1].as<string > (), ' ');
const int mySize = s.size();
int cellId = row[0].as<int> ();
cellBorderNodes[cellId] = new int[mySize];
for (int k = 0; k < mySize; k++) {
int node_id = atoi(s[k].c_str());
cellBorderNodes[cellId][k] = node_id;
(cells[cellId].getBorderNodes()).push_back(node_id);
try {
nodes[node_id - subtractor].cellId = cellId;
} catch (const std::exception &e) {
std::cerr << e.what() << std::endl;
}
nodes[node_id - subtractor].isBorderNode = true;
}
s.clear();
}
} catch (const std::exception &e) {
std::cerr << e.what() << std::endl;
}
for (int k = 0; k < maxNumberOfCells; k++) {
cout << k << ": " << cells[k].borderNodes.size() << endl;
cells[k].setBorderNodesArray();
if (maxBorderNodesPerCell < cells[k].borderNodes.size()) {
maxBorderNodesPerCell = cells[k].borderNodes.size();
}
}
}
void loadBorderNodesPerCellBnOnly([...], int** cellBorderNodes) {
cellBorderNodes = new int*[maxNumberOfCells];
The function above takes an int** by value. The copy is called cellBorderNodes inside the function. In the next line you change the value of the copy and continue updating that. None of those changes will be visible outside of the function. (And you will leak the acquired memory)
If you want to pass an int** and modify it inside the function, consider passing it by reference as in int**&. But you might be better off using higher level constructs (pass a vector<vector<int>>&, create a type that represents the data and pass it by value...)