I am writing to perform and test a binary search. The aim is to get the maximum x when y<=0 for the function y=x-1, and the search range is [-2,2),obviously the answer should be 1.
for test part, I should test if the invocations of function f is less than the calculated max_invoke
a segmentation fault appeared, and when I valgrind it, the error is:
==126667== Use of uninitialised value of size 8
==126667== at 0x400C8A: binarySearchForZero(Function<int, int>*, int,
int) (in /home/jw562/ece551/092_tests_binsrch/test)
==126667== by 0x400DD5: check(Function<int, int>*, int, int, int,
char const*) (in /home/jw562/ece551/092_tests_binsrch/test)
==126667== by 0x400E81: main (in
/home/jw562/ece551/092_tests_binsrch/test)
==126667== Uninitialised value was created by a stack allocation
==126667== at 0x400E41: main (in
/home/jw562/ece551/092_tests_binsrch/test)
below is my code:
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cmath>
using namespace std;
template<typename R, typename A>
class Function {
public:
virtual R invoke(A arg) = 0;
virtual ~Function() {}
};
class CountedIntFn : public Function<int,int>{
protected:
unsigned remaining;
Function<int,int> * f;
const char * mesg;
public:
CountedIntFn(unsigned n, Function<int,int> * fn, const char * m):
remaining(n),f(fn),mesg(m) {}
virtual int invoke(int arg) {
if (remaining == 0) {
fprintf(stderr,"Too many function invocations in %s\n", mesg);
exit(EXIT_FAILURE);
}
remaining--;
return f->invoke(arg);
}
class linearFunction : public Function<int, int> {
public:
virtual int invoke(int arg) {
int ans = arg-1;
return ans;
}
virtual ~linearFunction(){}
};
int binarySearchForZero(Function<int, int> * f, int low, int high){
if (high <= low){
cout << "high less or equal than low" << endl;
return EXIT_FAILURE;
}
int low_ans = f->invoke(low);
int high_ans = f->invoke(high);
int mid = (high-low)/2+low;
int mid_ans = f->invoke(mid);
if (low_ans > 0){
return low;//all positive
}
if (high_ans < 0){
return high-1;//all negtive
}
if (low_ans = high_ans){
return low;//all zero
}
if (mid_ans <= 0){
low = mid;
}
if (mid_ans >= 0){
high = mid;
}
return binarySearchForZero(f,low,high);
}
void check(Function<int,int> * f,int low,int high,int
expected_ans,const char * mesg){
int max_invoke = 0;//the maximum number of invocations allowed
if (high > low){
max_invoke = (int)(log2(high-low))+1;
}
else {
max_invoke = 1;
}
CountedIntFn count(max_invoke,f,mesg);
int ans = binarySearchForZero(f,low,high);
if (ans != expected_ans){
cout << "wrong answer" <<endl;
}
}
int main(void){
linearFunction *fl;
const char * message = "linearFunction";
int low = -2;
int high = 2;
int expected_ans = 1;
check(fl,low,high,expected_ans,message);
return EXIT_SUCCESS;
}
This is because variable fl of type linearFunction* is uninitialized.
You can change it to a non-pointer, and invoke with address-of operator:
linearFunction fl;
...
check(&fl, low, high, expected_ans, message);
Related
I'm trying to run a code that its's meant to change the value of object variables after it creates the object, and it isn't changing, then the variable is returning values like -815470397 and not changing. And when I use breakpoints it's like it jumps the inside part of the setter.
Pessoa.h
#pragma once
using namespace std;
class Pessoa
{
protected:
int dia;
int mes;
int ano;
int idade;
public:
Pessoa();
Pessoa(int, int, int, int);
int GetDia();
void SetDia(int);
int GetMes();
void SetMes(int);
int GetAno();
void SetAno(int);
int GetIdade();
void SetIdade(int);
};
Pessoa.cpp
#include "Pessoa.h"
Pessoa::Pessoa() {
}
Pessoa::Pessoa(int dia, int mes, int ano, int idade) {
this->dia = dia;
this->mes = mes;
this->ano = ano;
this->idade = idade;
}
int Pessoa::GetDia() {
return this->dia;
}
int Pessoa::GetMes() {
return this->mes;
}
int Pessoa::GetAno() {
return this->ano;
}
int Pessoa::GetIdade() {
return this->idade;
}
void Pessoa::SetDia(int dia) {
this->dia == dia;
}
void Pessoa::SetMes(int mes) {
this->mes == mes;
}
void Pessoa::SetAno(int ano) {
this->ano == ano;
}
void Pessoa::SetIdade(int idade) {
this->idade == idade;
}
Exame_especial.cpp
#include <iostream>
#include <string>
#include "Pessoa.h"
using namespace std;
string ImprimeIdade(Pessoa*);
int Calc_Idade(Pessoa*, int, int, int);
int main()
{
Pessoa* Einstein = new Pessoa();
Pessoa* Newton = new Pessoa();
Einstein->SetDia(14);
Einstein->SetMes(3);
Einstein->SetAno(1879);
Newton->SetDia(4);
Newton->SetMes(1);
Newton->SetAno(1643);
cout << ImprimeIdade(Newton) << endl;
cout << ImprimeIdade(Einstein) << endl;
}
string ImprimeIdade(Pessoa* nome) {
nome->SetIdade(Calc_Idade(nome, 29, 6, 2021));
return "A idade de Einstein seria " + to_string(nome->GetIdade()) + "\n";
}
int Calc_Idade(Pessoa* nome, int dia, int mes, int ano) {
int idade = ano - nome->GetAno();
if (nome->GetMes() > mes) {
idade = idade - 1;
}
else {
if (nome->GetMes() == mes) {
if (nome->GetDia() > dia) {
idade = idade - 1;
}
}
}
return idade;
}
You get these strange values due to the fact that your data members are of built-in type and they remain uninitialized when you use them. They remain uninitialized because your setters aren't setting anything. What they actually do is a comparison (the ==).
Pay attention to the difference in these two:
void Pessoa::SetDia(int dia) {
this->dia == dia; // Equal? Returns bool value which is lost
}
Vs
void Pessoa::SetDia(int new_dia) {
this->dia = new_dia; // Assigns a new value
}
This goes for all setters in your code.
Also, note that inside the body of a member function, you can refer to the data members directly, without the need to dereference them via this:
void Pessoa::SetDia(int new_dia) {
// Assigns new value to the dia data member of this
dia = new_dia;
}
Okay so am trying to make a data structure that maintains a heap of data in order to solve within the compile-time limit. https://open.kattis.com/problems/annoyedcoworkers
I might be in over my head since I just started coding in the last year or so and I just learned about sorting and vectors last week and heap data structures yesterday. But I am really interested in solving this problem.
Anyway here goes I first started to solve this problem with selection sort... needless to say it took way too long.
Then I started looking into making a heap data structure that yields values sorted order,
which brought me to priority_queue
After about 9 hours of trying different methods, this is the closest I've gotten to solving the problem.
does anyone have any suggestions as to why after 25/27 test cases my code returns a wrong answer?
Here is my code :
// C++ program to use priority_queue to implement Min Heap
// for user defined class
#include <algorithm>
#include <iostream>
#include <queue>
#include <vector>
using namespace std;
// User defined class, coworker
class CoworkerT
{
private:
int a;
int d;
public:
CoworkerT(int _a, int _d)
{
a = _a;
d = _d;
}
int SimAddAD() const
{
int aD;
aD = a + d;
return aD;
}
int AddAD()
{
a = a + d;
return a;
}
int getA() const {
return a;
}
int getD() const {
return d;
}
};
// To compare two coworkers possible a value
class Min
{
public:
int operator() (const CoworkerT& p1, const CoworkerT& p2)
{
return p1.SimAddAD() > p2.SimAddAD();
}
};
//compare two a values between coworkers
class Max
{
public:
int operator() (const CoworkerT& p1, const CoworkerT& p2)
{
return p1.getA() < p2.getA();
}
};
int AskForA() {
int a;
cin >> a;
return a;
}
int AskForD() {
int d;
cin >> d;
return d;
}
priority_queue <CoworkerT, vector<CoworkerT>, Max >
PopulateMax(priority_queue <CoworkerT, vector<CoworkerT>, Max > max,
priority_queue <CoworkerT, vector<CoworkerT>, Min > min) {
while (min.empty() == false)
{
CoworkerT e = min.top();
max.push(CoworkerT(e.getA(), e.getD()));
min.pop();
}
return max;
}
// Driver code
int main()
{
int h, c, i, a, d;
cin >> h >> c;
// Creates a Min heap of points (order by possible a +d combination )
priority_queue <CoworkerT, vector<CoworkerT>, Min > pq;
// Creates a Max heap of points (order by actual a value )
priority_queue <CoworkerT, vector<CoworkerT>, Max > max;
// Insert points into the min heap
for (int i = 0; i < c; i++) {
a = AskForA();
d = AskForD();
pq.push(CoworkerT(a, d));
}
i = 0;
while (i < h) {
CoworkerT e = pq.top();
a = e.AddAD();
d = e.getD();
pq.pop();
pq.push(CoworkerT(a, d));
i++;
}
max = PopulateMax(max, pq);
CoworkerT eMax = max.top();
cout << eMax.getA() << endl;
return 0;
}
I just want to say that I ended up using something similar to my original algorithm using the heap. The problem was my use of int I switched to an unsigned long long int ~(though that might have been overkill?) and it worked like a charm.
// C++ program to use priority_queue to implement Min Heap
// for user defined class
#include <algorithm>
#include <iostream>
#include <vector>
#include <cmath>
using namespace std;
// User defined class, coworker
class CoworkerT {
private:
unsigned long long int a;
unsigned long long int d;
public:
CoworkerT(unsigned long long int _a, unsigned long long int _d){
a = _a;
d = _d;
}
unsigned long long int SimAddAD() const{
return a + d;
}
unsigned long long int AddAD(){
return a + d;;
}
unsigned long long int getA() const {
return a;
}
unsigned long long int getD() const {
return d;
}
};
//compare two coworkers possible a + d values
struct MinSort {
bool operator()(const CoworkerT& p1, const CoworkerT& p2) const {
return p1.SimAddAD() < p2.SimAddAD();
}
};
//compare two coworkers possible a + d values ~for some reason heap lesser than or greater need to be reverse of operator for sort???
struct Min {
bool operator()(const CoworkerT& p1, const CoworkerT& p2) const {
return p1.SimAddAD() > p2.SimAddAD();
}
};
//compare two a values between coworkers
struct MaxSort {
bool operator()(const CoworkerT& p1, const CoworkerT& p2) const {
return p1.getA() > p2.getA();
}
};
void FindAndPrintMax(vector<CoworkerT>& max) {
sort(max.begin(), max.end(), MaxSort());
CoworkerT minMax = max.front();
cout << minMax.getA();
}
void InputCoworkersAD(vector<CoworkerT>& min, unsigned long long int& h, unsigned long long int& c) {
int a, d, i;
cin >> h >> c;
// Insert a and d into the vector
if (h <= 100000 && h >= 1 && c <= 100000 && c >= 1) {
for (i = 0; i < c; i++) {
cin >> a >> d;
min.push_back(CoworkerT(a, d));
}
}
make_heap(min.begin(), min.end(), Min());
}
void AskForHelp(vector<CoworkerT>& min, unsigned long long int h) {
int i = 0;
while (i < h) {
push_heap(min.begin(), min.end(), Min());
CoworkerT e = min.front();
pop_heap(min.begin(), min.end(), Min());
min.pop_back();
min.push_back(CoworkerT(e.AddAD(), e.getD()));
i++;
}
}
// Driver code
int main()
{
unsigned long long int h, c;
vector<CoworkerT> min;
InputCoworkersAD(min, h, c);
AskForHelp(min, h);
FindAndPrintMax(min);
return 0;
}
Hi: please further down find my code.
I compiled using mingw with parameters -Wmain;-pedantic;-std=c++11;-Wall.
Codelite set the semicola between the compiler options
Here I tried to learn how to use thread and mutex: https://en.cppreference.com/w/cpp/thread/mutex
The main module contains the global variable std::mutex mtx after the include section
The thread functions are declared and joined in the main() function; the function definitions for friend class SL can be found here as well. Class and method definitions are spread over the next two modules.
These are the error messages, which I cannot handle:
Message 1
C:/Program Files/CodeBlocks/MinGW/lib/gcc/x86_64-w64-mingw32/8.1.0/include/c++/thread:240:2: error: no matching function for call to 'std::thread::_Invoker<std::tuple<void (*)(int, int, SL&), int, int, SL> >::_M_invoke(std::thread::_Invoker<std::tuple<void (*)(int, int, SL&), int, int, SL> >::_Indices)'
operator()()
^~~~~~~~
Message 2
C:/Program Files/CodeBlocks/MinGW/lib/gcc/x86_64-w64-mingw32/8.1.0/include/c++/thread:233:29: error: no matching function for call to '__invoke(std::__tuple_element_t<0, std::tuple<void (*)(int, int, SL&), int, int, SL> >, std::__tuple_element_t<1, std::tuple<void (*)(int, int, SL&), int, int, SL> >, std::__tuple_element_t<2, std::tuple<void (*)(int, int, SL&), int, int, SL> >, std::__tuple_element_t<3, std::tuple<void (*)(int, int, SL&), int, int, SL> >)'
-> decltype(std::__invoke(_S_declval<_Ind>()...))
__invoke(_Callable&& __fn, _Args&&... __args)
^~~~~~~~
*Message 2 seems to make reference to some type of move constructor ...
I had the idea that the friend function is cause of the dilemma, but was not able to verify
Please help with this.
main module
#include <mutex>
#include <thread>
#include "sl.h"
std::mutex mtx;
void play(int die1, int die2, SL& p){
std::this_thread::sleep_for(std::chrono::seconds(1));
mtx.lock();
if (p.dice.size() > 0) {
p.dice.resize(0);
}
p.set_dice(die1, die2);
rollDice(p);
mtx.unlock();
}
void rollDice(SL& p) {
int iFound = -1;
int iAdd = p.dice[0] + p.dice[1];
p.addPosition(iAdd);
p.bounceBack();
if (p.position == 100) {
printResult(p, iFound);
std::cout << "Game over" << std::endl;
return;
}
if ((iFound = p.check(SL::ladders, p.position)) != -1) {
p.setPosition(SL::ladders[iFound].second);
iFound += 100;
}
else if ((iFound = p.check(SL::snakes, p.position)) != -1) {
p.setPosition(SL::snakes[iFound].second);
}// snakes, position + iAdd
printResult(p, iFound);
if (p.dice[0] == p.dice[1]) {
mtx.unlock();
play(rand() %6 + 1, rand() % 6 + 1, p);
}
}
void printResult(SL& p, int iFound) {
std::cout << ++p.iTimes << ") "
<< p.get_name() << "<<<< "
<< p.dice[0] << "|"
<< p.dice[1] << " position: "
<< p.position;
if (iFound != -1) {
if (iFound > 100) { // this is a ladder field
iFound -= 100;
std::cout << " LADDER from "
<< SL::ladders[iFound].first << "|"
<< SL::ladders[iFound].second;
}
else {
std::cout << " SNAKE from "
<< SL::snakes[iFound].first << "|"
<< SL::snakes[iFound].second;
}
}
std::cout << std::endl;
}
int main()
{
srand(time(NULL));
SL one("Player 1"),
two("Player 2");
std::thread t1 (play, rand() %6 + 1, rand() %6 + 1, one);
std::thread t2 (play, rand() %6 + 1, rand() %6 + 1, two);
while((one.get_position() != 100) && (two.get_position() != 100)) {
t1.join();
t2.join();
}
return 0;
}
// Class Declaration
#pragma once
#include <iostream>
#include <string>
#include <vector>
#include <utility>
#include <ctime>
#include <iomanip>
class SL {
public:
SL(const std::string& strName) : player(strName), position(0), iTimes(0) {}
~SL() = default;
private:
friend void play(int die1, int die2, SL& p);
friend void rollDice(SL&);
friend void printResult(SL&, int);
static const std::pair<int, int> snakes[];
static const std::pair<int, int> ladders[];
std::string player;
int position;
int iTimes;
std::vector<int> dice;
protected:
int check(const std::pair<int, int> field[], const int iField);
public:
void addPosition(const int iPosition);
void setPosition(const int iPosition);
void bounceBack();
void set_dice(int die1, int die2);
const int get_position() const;
const std::string& get_name() const;
const std::vector<int> get_dice() const;
};
// friend function
void play(int die1, int die2, SL& p);
void rollDice(SL&);
void printResult(SL&, int =-1);
// Class methods - static variables
#include <mutex>
#include <thread>
#include "sl.h"
inline void SL::addPosition(const int iPosition) {
position += iPosition;
}
inline void SL::setPosition(const int iPosition) {
position = iPosition;
}
inline void SL::bounceBack() {
if (position > 100) {
int iBounceBack = position - 100;
position -= iBounceBack;
}
}
inline void SL::set_dice(int die1, int die2){
if (dice.size() > 0) {
dice.erase(dice.begin(), dice.end());
}
dice.push_back(die1);
dice.push_back(die2);
}
const int SL::get_position() const {return position;}
const std::string& SL::get_name() const {return player;}
const std::vector<int> SL::get_dice() const {return dice;}
int SL::check(const std::pair<int, int> field[], const int iField) {
const int end = 10;
int result = -1;
for ( size_t idx = 0; idx < end; idx++) {
if (field[idx].first == iField){
result = idx;
break;
}
else if (iField > field[idx].first)
break;
}
return result;
}
const std::pair<int, int> SL::ladders[] {
std::make_pair( 2, 38),
std::make_pair( 7, 14),
std::make_pair( 8, 31),
std::make_pair(15, 26),
std::make_pair(28, 84),
std::make_pair(36, 44),
std::make_pair(51, 67),
std::make_pair(71, 91),
std::make_pair(78, 98),
std::make_pair(87, 94)
};
const std::pair<int, int> SL::snakes[] {
std::make_pair(16, 6),
std::make_pair(46, 25),
std::make_pair(49, 11),
std::make_pair(62, 19),
std::make_pair(64, 60),
std::make_pair(74, 53),
std::make_pair(89, 68),
std::make_pair(92, 88),
std::make_pair(95, 75),
std::make_pair(99, 80)
};
I tried to go along with G.M.s suggestion and truly I was not able to make it.
For multi threading beginners this is a good stop:
https://hackernoon.com/learn-c-multi-threading-in-5-minutes-8b881c92941f
After reading through all of this I decided for the std::lock guard as so using the mutex mtx global variable from the main module:
void play(int die1, int die2, SL& p){
std::lock_guard<std::mutex> guard(mtx);
if (p.dice.size() > 0) {
p.dice.resize(0);
}
p.setDice(die1, die2);
int iGameOver = 0;
rollDice(p, iGameOver);
if (iGameOver)
return;
}
In the rollDice function I used to have a recursive call to the rollDice function via play. This configuratin caused a dead lock and I got rid of that logic and replaced the recursion into two loops inside main.
int main()
{
srand(time(NULL));
SL one("Player 1"),
two("Player 2");
while((one.getPosition() != 100) && (two.getPosition() != 100)) {
int die1 = 0,
die2 = 0;
if (!two.gameOver()) {
do {
die1 = rand() % 6 + 1;
die2 = rand() % 6 + 1;
play(die1, die2, one);
}while(die1 == die2);
std::cout << "-----------------" << std::endl;
}
if (!one.gameOver()) {
do {
die1 = rand() % 6 + 1;
die2 = rand() % 6 + 1;
play(die1, die2, two);
}while(die1 == die2);
std::cout << "-----------------" << std::endl;
}
}
return 0;
}
The respective logic making another call to rollDice() via play from rollDice was taken off the rollDice function, which now looks like this.
void rollDice(SL& p, int& gameOver) {
int iFound = -1;
int iAdd = p.getAdded();
p.addPosition(iAdd);
p.bounceBack();
if (p.getPosition() == 100)
p.setGameOver();
if (p.gameOver()) {
printResult(p, iFound);
std::cout << "Game over" << std::endl;
return;
}
if ((iFound = p.check(SL::ladders, p.getPosition())) != -1) {
p.setPosition(SL::ladders[iFound].second);
iFound += 100;
}
else if ((iFound = p.check(SL::snakes, p.getPosition())) != -1) {
p.setPosition(SL::snakes[iFound].second);
}// snakes, position + iAdd
printResult(p, iFound);
}
I am not really sure, where I went wrong with my original approach, but my first multi threaded test code is successfully implemented and without me posting and getting G.M.s suggestion, it just would not have taken place. Thank you.
After a bit of bug searching, I've found that my code leaves with exit code 11 at a certain point, and this is because an EXC_BAD_ACCESS error with code 1. After some googling, I see this must be due to some memory mismanagement, but I'm new to C++ and nothing seems obvious to me.
The code is exiting at the line
fieldFuncts[field](string, equal, validOps, length, difficulty, rng, opGen);
in the file (last function)
//
// Created by Anthony Monterrosa on 4/17/18.
//
#include "MathExpr.h"
#include <list>
#include <iostream>
#include <random>
std::vector<std::function<void(std::vector<MathExpr::CharType> &, MathExpr::NumType &, std::vector<MathExpr::NumType> &)>> MathExpr::layerFuncts;
std::vector<std::function<void(std::vector<MathExpr::CharType> &, MathExpr::NumType &, std::vector<MathExpr::Op> &, unsigned char, unsigned char, std::mt19937 &, std::uniform_int_distribution<MathExpr::OpType> &)>> MathExpr::fieldFuncts;
void MathExpr::init() {
initLayerFuncts();
initFieldFuncts();
}
void MathExpr::initLayerFuncts() {
layerFuncts.resize(Op::EOOE);
layerFuncts[static_cast<unsigned long>(Op::addition)] = [](std::vector<MathExpr::CharType> &string, NumType &equal, std::vector<NumType> & otherArgs) -> void {
string.insert(string.end(), {' ', opToChar(Op::addition), ' '});
equal += otherArgs[0];
std::vector<MathExpr::CharType> digits = intToDigit(otherArgs[0]);
for(int i = 0; i < digits.size(); i++ ) {
string.push_back(digits[i]);
}
};
layerFuncts[static_cast<unsigned long>(Op::subtraction)] = [](std::vector<MathExpr::CharType> &string, MathExpr::NumType &equal, std::vector<NumType> & otherArgs) -> void {
string.insert(string.end(), {' ', opToChar(Op::subtraction), ' '});
equal -= otherArgs[0];
std::vector<MathExpr::CharType> digits = intToDigit(otherArgs[0]);
for(int i = 0; i < digits.size(); i++ ) {
string.push_back(digits[i]);
}
};
}
void MathExpr::initFieldFuncts() {
fieldFuncts.resize(Field::EOFE);
fieldFuncts[static_cast<unsigned long>(Field::integers)] = [](std::vector<MathExpr::CharType> &string, NumType &equal, std::vector<MathExpr::Op> &validOps, unsigned char length, unsigned char difficulty, std::mt19937 &rng, std::uniform_int_distribution<MathExpr::OpType> &opGen) -> void {
std::uniform_int_distribution<MathExpr::NumType> numGen(1, static_cast<MathExpr::NumType>(pow(10, difficulty)));
equal = numGen(rng);
std::vector<MathExpr::CharType> digits = intToDigit(equal);
for(int i = 0; i < digits.size(); i++ ) {
string.push_back(digits[i]);
}
for (int i = 0; i < length - 1; i++) {
MathExpr::Op op = validOps[opGen(rng)];
int count = otherArgsCount(op);
std::vector<MathExpr::NumType> otherArgs(count);
for(int j = 0; j < count; j++) {
otherArgs[j] = (numGen(rng));
}
layer(string, equal, op, otherArgs);
}
};
}
char MathExpr::opToChar(OpType ordinal) {
return opToChar(static_cast<Op>(ordinal));
}
char MathExpr::opToChar(Op op) {
switch(op) {
case Op::addition : return '+';
case Op::subtraction : return '-';
default : return '_';
}
}
MathExpr::NumType MathExpr::otherArgsCount(MathExpr::Op op) {
switch(op) {
case Op::addition : return 1;
case Op::subtraction : return 1;
default : return 0;
}
}
std::vector<MathExpr::CharType> MathExpr::intToDigit(MathExpr::NumType num) {
std::vector<MathExpr::CharType> digits;
while(num >= 10) {
digits.insert(digits.begin(),'0' + static_cast<MathExpr::CharType>(num % 10));
num /= 10;
} digits.insert(digits.begin(), '0' + static_cast<MathExpr::CharType>(num));
return digits;
}
bool MathExpr::initBool = false;
MathExpr::MathExpr(std::vector<CharType> exp, MathExpr::NumType equal) {
if(!initBool) init();
this->string = std::vector<CharType>(exp);
this->equal = equal;
}
void MathExpr::print(MathExpr &exp) {
for(int i = 0; i < exp.string.size(); i++) {
std::cout << exp.string[i];
}
}
void MathExpr::layer(std::vector<MathExpr::CharType> &string, MathExpr::NumType &equal, MathExpr::Op op, std::vector<MathExpr::NumType> &otherArgs) {
layerFuncts[op](string, equal, otherArgs);
}
MathExpr MathExpr::generate(std::vector<MathExpr::Op> &validOps, MathExpr::Field field, unsigned char length, unsigned char difficulty) {
std::vector<MathExpr::CharType> string;
std::random_device rd;
std::mt19937 rng(rd());
std::uniform_int_distribution<MathExpr::OpType> opGen(0, static_cast<MathExpr::OpType>(validOps.size() - 1));
MathExpr::NumType equal;
fieldFuncts[field](string, equal, validOps, length, difficulty, rng, opGen);
return MathExpr::MathExpr(string, equal);
}
here is the corresponding .h file
//
// Created by Anthony Monterrosa on 4/17/18.
//
// EO_E -> "end of _ enum".
#ifndef MATHTESTGENERATOR_MATHEXPR_H
#define MATHTESTGENERATOR_MATHEXPR_H
#include <functional>
#include <random>
#include <vector>
class MathExpr {
public:
using FieldType = unsigned char;
using OpType = unsigned char;
using NumType = short int;
using CharType = char;
enum Field : FieldType {
integers,
EOFE // rational, real, complex.
};
enum Op : OpType {
addition,
subtraction,
EOOE // multiplication, division, absolute value, radical
};
explicit MathExpr(std::vector<CharType>, NumType);
std::vector<CharType> string;
NumType equal;
static void print(MathExpr &);
static MathExpr generate(std::vector<Op> &, Field = Field::integers, unsigned char length = 2, unsigned char difficulty = 1);
//protected:
static void init();
static bool initBool;
static void layer(std::vector<MathExpr::CharType> &, NumType &, Op, std::vector<NumType> &);
static NumType otherArgsCount(Op);
static std::vector<CharType> intToDigit(NumType);
static char opToChar(OpType);
static char opToChar(Op);
static std::vector<std::function<void(std::vector<MathExpr::CharType> &, NumType &, std::vector<NumType> &)>> layerFuncts;
static void initLayerFuncts();
static std::vector<std::function<void(std::vector<MathExpr::CharType> &, NumType &, std::vector<MathExpr::Op> &, unsigned char, unsigned char, std::mt19937 &, std::uniform_int_distribution<MathExpr::OpType> &)>> fieldFuncts;
static void initFieldFuncts();
};
#endif //MATHTESTGENERATOR_MATHEXPR_H
My gut says the error has to do with the "string" vector, but I'm unsure of how to tell. I would appreciate insight into the problem.
i have this code which uses a function pointer to point 3 functions sum, subtract, mul. it works well. but now the problem is that i have functions with different no.of parameters and different data types. how to implement this.
int add(int a, int b)
{
cout<<a+b;
}
int subtract(int a, int b)
{
cout<<a-b;
}
int mul(int a, int b)
{
cout<<a*b;
}
int main()
{
int (*fun_ptr_arr[])(int, int) = {add, subtract, mul};
unsigned int ch, a = 15, b = 10,c=9;
ch=2;
if (ch > 4) return 0;
(*fun_ptr_arr[ch])(a, b);
return 0;
}
The simple answer is that technically you can't do this. You could do some manipulations using an array as input for all these functions, but you will still have to know exactly what to pass to each function. From a software engineering perspective, you should not do this - I suggest you take a look at the nice answers here: C++ Function pointers with unknown number of arguments
A slightly different approach using objects to implement the required behavior. In order to have a truly generic kind of solution, we need to use Interfaces.
Dismantle the data and operation i.e keep them separately.
//Interface which describes any kind of data.
struct IData
{
virtual ~IData()
{
}
};
//Interface which desribes any kind of operation
struct IOperation
{
//actual operation which will be performed
virtual IData* Execute(IData *_pData) = 0;
virtual ~IOperation()
{
}
};
Now, every operation knows the kind of data it work on and will expect that kind of data only.
struct Operation_Add : public IOperation
{
//data for operation addition.
struct Data : public IData
{
int a;
int b;
int result;
};
IData* Execute(IData *_pData)
{
//expected data is "Operation_Add::Data_Add"
Operation_Add::Data *pData = dynamic_cast<Operation_Add::Data*>(_pData);
if(pData == NULL)
{
return NULL;
}
pData->result = pData->a + pData->b;
return pData;
}
};
struct Operation_Avg : public IOperation
{
//data for operation average of numbers.
struct Data : public IData
{
int a[5];
int total_numbers;
float result;
};
IData* Execute(IData *_pData)
{
//expected data is "Operation_Avg::Data_Avg"
Operation_Avg::Data *pData = dynamic_cast<Operation_Avg::Data*>(_pData);
if(pData == NULL)
{
return NULL;
}
pData->result = 0.0f;
for(int i = 0; i < pData->total_numbers; ++i)
{
pData->result += pData->a[i];
}
pData->result /= pData->total_numbers;
return pData;
}
};
Here, is the operation processor, the CPU.
struct CPU
{
enum OPERATION
{
ADDITION = 0,
AVERAGE
};
Operation_Add m_stAdditionOperation;
Operation_Avg m_stAverageOperation;
map<CPU::OPERATION, IOperation*> Operation;
CPU()
{
Operation[CPU::ADDITION] = &m_stAdditionOperation;
Operation[CPU::AVERAGE] = &m_stAverageOperation;
}
};
Sample:
CPU g_oCPU;
Operation_Add::Data stAdditionData;
stAdditionData.a = 10;
stAdditionData.b = 20;
Operation_Avg::Data stAverageData;
stAverageData.total_numbers = 5;
for(int i = 0; i < stAverageData.total_numbers; ++i)
{
stAverageData.a[i] = i*10;
}
Operation_Add::Data *pResultAdd = dynamic_cast<Operation_Add::Data*>(g_oCPU.Operation[CPU::ADDITION]->Execute(&stAdditionData));
if(pResultAdd != NULL)
{
printf("add = %d\n", pResultAdd->result);
}
Operation_Avg::Data *pResultAvg = dynamic_cast<Operation_Avg::Data*>(g_oCPU.Operation[CPU::AVERAGE]->Execute(&stAverageData));
if(pResultAvg != NULL)
{
printf("avg = %f\n", pResultAvg->result);
}
If you have the following functions
int f1(int i);
int f2(int i, int j);
You can define a generic function type like this
typedef int (*generic_fp)(void);
And then initialize your function array
generic_fp func_arr[2] = {
(generic_fp) f1,
(generic_fp) f2
};
But you will have to cast the functions back
int result_f1 = ((f1) func_arr[0]) (2);
int result_f2 = ((f2) func_arr[1]) (1, 2);
Obviously, it does not look like a good way to build a program
To make code look a little bit better you can define macros
#define F1(f, p1) ((f1)(f))(p1)
#define F2(f, p1, p2) ((f2)(f))(p1, p2)
int result_f1 = F1(func_arr[0], 2);
int result_f2 = F2(func_arr[1], 1, 2);
EDIT
Forgot to mention, you also have to define a type for every type of function
typedef int (*fi)(int); // type for function of one int param
typedef int (*fii)(int, int); // type for function of two int params
And to then cast stored pointers to those types
int result_f1 = ((fi) func_arr[0]) (2);
int result_f2 = ((fii) func_arr[1]) (1, 2);
Here is a complete example
#include <iostream>
typedef int (*generic_fp)(void);
typedef int (*fi)(int); // type for function of one int param
typedef int (*fii)(int, int); // type for function of two int params
#define F1(f, p1) ((fi)(f))(p1)
#define F2(f, p1, p2) ((fii)(f))(p1, p2)
int f1(int i);
int f2(int i, int j);
int main()
{
generic_fp func_arr[2] = {
(generic_fp) f1,
(generic_fp) f2
};
int result_f1_no_macro = ((fi) func_arr[0]) (2);
int result_f2_no_macro = ((fii) func_arr[1]) (1, 2);
int result_f1_macro = F1(func_arr[0], 2);
int result_f2_macro = F2(func_arr[1], 1, 2);
std::cout << result_f1_no_macro << ", " << result_f2_no_macro << std::endl;
std::cout << result_f1_macro << ", " << result_f2_macro << std::endl;
return 0;
}
int f1(int i)
{
return i * 2;
}
int f2(int i, int j)
{
return i + j;
}
The code above produces the following output
4, 3
4, 3