I have a matrix of values (stored as an array of values) and a vector with the matrix dimensions( dims[d0, d1, d2]).
I need to build a string like that:
"matA(j, k, l) = x;"
where j, k, l are the indices of the matrix and x the value of the element. I need to write this for each value of the matrix and for matrices with 2 to n dimensions.
I have a problem isolating the base case and replicating it in a useful way. I did a version in a switch case with a case for each dimension and a number of for cycles equal to the number of dimensions:
for (unsigned int k=1; k<=(dims[2]); k++)
{
for (unsigned int j=1; j<=(dims[1]); j++)
{
for (unsigned int i=1; i<=(dims[0]); i++)
{
strs << matName << "(" << i << "," << j << ","<< k << ")="<< tmp[t]<< "; ";
....
but is not what I wanted.. Any idea for a more general case with a variable number of dimensions?
You need a separate worker function to recursively generate the series of indices and main function which operates on it.
For example something like
void worker(stringstream& strs, int[] dims, int dims_size, int step) {
if (step < dims_size) {
... // Add dims[step] to stringstream. Another if may be necessary for
... // whether include `,` or not
worker(strs, dims, dims_size, step + 1);
} else {
... // Add cell value to stringstream.
}
}
string create_matrix_string(int[] dims, int dims_size, int* matrix) {
... // Create stringstream, etc.
strs << ... // Add matrix name etc.
worker(strs, dims, dims_size, 0);
strs << ... // Add ending `;` etc.
}
The main problem here is the value, since the dimension is not known during compilation. You can avoid that by encoding matrix in single-dimensional table (well, that's what C++ is doing anyway for static multidimensional tables) and call it using manually computed index, eg. i + i * j (for two-dimensional table). You can do it, again, by passing an accumulated value recursively and using it in final step (which I omitted in example above). And you probably have to pass two of them (running sum of polynomial components, and the i * j * k * ... * x product for indices from steps done so far.
So, the code above is far from completion (and cleanliness), but I hope the idea is clear.
You can solve this, by doing i, j and k in a container of the size of dim[] - sample:
#include <iostream>
#include <vector>
template< typename Itr >
bool increment( std::vector< int >& ijk, Itr idim, int start )
{
for( auto i = begin(ijk); i != end(ijk); ++i, ++idim )
{
if( ++*i <= *idim )
return true;
*i = start;
}
return false;
}
int main()
{
using namespace std;
int dim[] = { 5, 7, 2, 3 };
const int start = 1;
vector< int > ijk( sizeof(dim)/sizeof(*dim), start );
for( bool inc_done = true; inc_done
; inc_done = increment( ijk, begin(dim), start ) )
{
// .. here make what you want to make with ijk
cout << "(";
bool first = true;
for( auto j = begin(ijk); j != end(ijk); ++j )
{
if( !first )
cout << ",";
else
first = false;
cout << *j;
}
cout << ")= tmp[t] " << endl;
}
return 0;
}
Related
I have created a simple mode calculator and I am displaying random list - something like this:
12 14 11 10 15 13 16 13 14 14 11 13 16 15 15 15 10 14 13 14 12 13 14 12
The mode value is 6
The mode is 14
. But my problem is I can't get the pair list to show instead of showing the list way - I want to display it this as a item-count pair list :
{2,3}, {4,3}, {5,2}, {3,2}, {1,2}
and the modes are clearly 2 and 4.
can anyone help me solve this issue? thanks for the help.
Here is an image for more details: https://imgur.com/a/FYNcxkv
here is my code:
#include <ctime>
#include <iomanip>
#include <iostream>
#include <string>
#include <random>
using namespace std;
default_random_engine e(static_cast<unsigned>(time(NULL)));
void fill(int a[], int size, int value)
{
for(int i = 0; i < size; i++)
a[i] = value;
}
void randomFill(int a[], int size, int lb, int up)
{
uniform_int_distribution<int> u(lb, up);
for(int i = 0; i < size; i++)
a[i] = u(e);
}
void show(int a1d[], int size)
{
for(int i = 0; i < size; i++)
cout << setw(2) << a1d[i] << ' ';
cout << endl;
}
int count(int a1d[], int size, int value)
{
int vcount = 0;
for(int i = 0; i < size; i++)
if(a1d[i] == value) vcount++;
return vcount;
}
int findLargest(int a1d[], int size)
{
int largest = a1d[0];
for(int i = 1; i < size; i++)
if(a1d[i] > largest) largest = a1d[i];
return largest;
}
/*
the mode of a set of things is that thing that appears the greater number of times in the set
a set may have several modes
*/
int computemodes(int source[], int size, int modes[], int& msize)
{
/*
1. fill the modes array with zeroes
*/
fill(modes, size, 0);
/*
2. store the number of times each source element appears in the modes array.
if an element appears more than once in the source array then its counts appears
more than once the modes array.
source and modes form a parallel array structure
*/
for(int i = 0; i < size; i++)
modes[i] = count(source, size, source[i]);
/*
3. calculate the largest number in the modes array. this number is the number of
times the mode or modes appears in the source array
*/
int modevalue = findLargest(modes, size);
/*
4. assign -1 to the mode array elements that are less than the mode value
now only mode values in the modes array are not equal to -1.
the corresponding elements in the source array are the modes.
*/
for(int i = 0; i < size; i++)
if(modes[i] != modevalue) modes[i] = -1;
/*
5. we use the modes array to identify the source elements that are modes:
any element in the modes array that is not -1 corresponds to a mode in the
source array. if the mode is 1 then every source element is a mode
and no element in the modes array is -1; if the mode is greater than 1 then
a. many modes array entries are -1
b. the number of times a mode appears in the source equals its corresponding modes value
c. the number of modes array entries that are not -1 are the number of times the modes
appear in the source array
the following nested for loop transforms the modes array into an array in which
the first appearance of a mode in the source corresponds to a modes array entry
that is not -1 and subsequent appearances of this mode in the source correspond to
modes array entries that are -1.
*/
for(int i = 0; i < size; i++)
if(modes[i] != -1) //first appearance of the mode in the source
for(int j = i + 1; j < size; j++)
if(source[i] == source[j]) modes[j] = -1;
//subsequent appearances
/*
at this point the usage of the modes array changes.
heretofore, an entry that is not -1 in the modes array is the number of times
a mode appears in the source array. now an entry in the modes array is a mode.
the loop adds modes from the source array to the modes array.
msize serves 2 purposes:
a. it is number of modes copied so far.
b. it is the next free modes array position.
*/
msize = 0;
for (int i = 0; i < size; i++)
if (modes[i] != -1) //first occurrence of a mode in the source
{
modes[msize] = source[i];
msize++;
}
return modevalue;
}
int main()
{
const int size = 24;
int a[size];
int m[size];
randomFill(a, size, 10, 16);
show(a, size);
int msize = 0;
int modevalue = computemodes(a, size, m, msize);
cout << "The mode value is " << modevalue << endl;
if (msize == 1)
cout << "The mode is ";
else
cout << "The modes are ";
show(m, msize);
system("pause");
return 0;
}
You can create your map count with:
template <typename T>
std::map<T, std::size_t> map_count(const std::vector<T>& v)
{
std::map<T, std::size_t> res;
for (const auto& e: v) { res[e]++; }
return res;
}
and from that:
template <typename T>
std::pair<const T, std::size_t> find_mode(const std::map<T, std::size_t>& m)
{
if (m.empty()) {throw std::runtime_error("empty map");}
return *std::max_element(m.begin(),
m.end(),
[](const auto& lhs, const auto& rhs){ return lhs.second < rhs.second; }
);
}
Demo
I would design your code problem something like this:
#include <iostream>
#include <string>
#include <random>
#include <vector>
#include <map>
#include <algorithm> // could be used in your calculate function - algorithm
#include <numeric> // same as above.
class ModeCaclulator {
private:
std::vector<int> generatedNumbers_;
int highestModeCount_;
int highestModeValue;
typedef std::map<int,int> Modes;
Modes allModeCounts_;
public:
ModeCalculator() = default; // default constructor
template<typename T = int> // variadic constructor
ModeCalculator( T&&... t ) : generatedNumbers_{ t... } {
calculateModes();
}
std::vector<int>& getAllNumbers() const { return generatedNumbers_; }
int getHighestModeCount() const { return getHighestModeCount_; }
int getHighestModeValue() const { return getHighestModeValue_; }
Modes getAllModes() const { return allModeCounts_; }
void generateNumbers(int count, int lower, int upper) {
std::random_device rd;
std::mt19937 gen( rd() );
std::uniform_int_distribution<> dis( lower, upper );
for ( int i = 0; i < count; i++ )
generateNumbers_.push_back( dis( gen ) );
}
void calculateModes() {
// This is where you would perform your algorithm
// After doing the proper calculations this is where you would
// save the highestModeValue_ & highestModeCount_ as well as
// populating the vector of maps member.
// In this function you can use local lambdas to find the highest mode count and value.
}
void displayModeInformation() const {
std::cout << Random Values: << '\n';
for ( auto& v : generatedNumbers )
std::cout << v << " ";
std::cout << '\n'
std::cout << "Highest Mode Count: " << highestModeCount_ << '\n';
std::cout << "Highest Mode Value: " << highestModeValue_ << '\n';
std::cout << "\n"
std::cout << "All Mode Count & Value Pairs:\n";
for ( auto& p : allModeCounts_ ) {
std::cout << "{" << p.first << "," << p.second << "}" << " "
}
std::cout << '\n';
}
};
int main() {
ModeCalculator mc;
mc.generateNumbers( 15, 1, 16 );
mc.calculateModes();
mc.displayModeInformation();
// If using variadic constructor
ModeCalculate mc2( 12, 15, 14, 19, 18, 12, 15, 19, 21, 12, 18, 19, 21, 14 );
// no need to call calculateModes() this constructor does that for u
mc2.displayModeInformation();
return 0;
}
This makes the code much more readable, and look how clean main is, and all of the functionality is encapsulated into a single class instead of a handful of floating functions... Internal data is protected or hidden and can only be retrieved through accessor functions. The use of stl containers provides a clean interface instead of the use of C style arrays and also helps to prevent the use of raw pointers, and dynamic memory - via new & delete or new[] & delete[]. It also allows the code to be easier to manage and to debug, and provides a user with a generic reusability.
I am new to c++ programming and am taking a computational physics class where we are analyzing the problem of percolation on a square lattice using a single-cluster algorithm. My professor has given us some base code, and asked us to modify it as well as write some additional code and scripts within and without this specific program. I have written the majority of the code and scripts necessary to solve and plot this problem, but I am having an issue with my main data output program, specifically that of an infinite loop when I set an input parameter to any value other than 0.
Three main function comprise this program, namely LATTICE::LATTICE, CLUSTER::grow, and CUSTER::print, and also uses a standard Mersenne Twister header file. The heavily modified, commented, and toyed with c++ program is as follows:
#include <fstream>
#include <iostream>
#include <math.h>
#include <string>
#include <sstream>
#include <iomanip>
#include <vector>
#include <cstdlib>
#include "MersenneTwister.h"
using namespace std;
class PARAMS
{
public:
int Nlin; // linear size of lattice
double pr; // probability for a site
double Nclust; // number of clusters in a bin
double Nbin; // number of bins of data to output
int SEED; // seed for mersenne twister
string latt_; // which lattice
PARAMS();//constructor
};
class LATTICE
{
public:
LATTICE(const PARAMS&);//constructor
int Nsite;// number of lattice sites
int Lx,Ly;
vector<vector<int> > nrnbrs;
void print ();
};
class CLUSTER
{
public:
CLUSTER(const PARAMS&, const LATTICE&);//constructor
void grow(const PARAMS&, const LATTICE&, MTRand&);
void meas_clear(const LATTICE&);
void meas(const LATTICE&);
void binwrite(const PARAMS&, const LATTICE&);
//void print(const LATTICE& latt, int index);
void print(const PARAMS& p, const LATTICE& latt);
~CLUSTER();// destructor
//private:
int size;
vector <int> conf;
vector <int> stack;
double pr;
//int stck_pnt,stck_end;
double avg_size;
ofstream dfout;
vector <int> stck_pnt;
vector <int> stck_end;
int z, pnt, prob, val, row, column;
vector< vector< vector <int> > > imax;
};
int main(void)
{
PARAMS p;
LATTICE latt(p);
CLUSTER cluster(p,latt);
MTRand ran(p.SEED);
latt.print();
/*for (int bin=0;bin<p.Nbin;bin++)
{
cluster.meas_clear(latt);
for(int clust=0;clust<p.Nclust;clust++)
{
cluster.grow(p,latt,ran);
cluster.meas(latt);
}
cluster.binwrite(p,latt);
}
*/
cluster.grow(p, latt, ran);
cluster.print(p,latt);
}
PARAMS::PARAMS(){
//initializes commonly used parameters from a file
ifstream pfin;
pfin.open("param.dat");
if (pfin.is_open()) {
pfin >> Nlin;
pfin >> pr;
pfin >> Nclust;
pfin >> Nbin;
pfin >> SEED;
pfin >> latt_;
}
else
{cout << "No input file to read ... exiting!"<<endl;exit(1);}
pfin.close();
// print out all parameters for record
cout << "--- Parameters at input for percolation problem ---"<<endl;
cout <<"Nlin = "<<Nlin<<"; prob. of site = "<<pr<<endl;
cout <<"Number of clusters in a bin = "<<Nclust<<"; Number of bins = "<<Nbin<<endl;
cout <<"RNG will be given SEED of = "<<SEED<<endl;
cout <<"Percolation problem on lattice --> "<<latt_<<endl;
};//constructor
LATTICE::LATTICE (const PARAMS& p)
{
string latt_=p.latt_;
if(p.latt_=="sqlatt_PBC")
{
Lx=p.Nlin;Ly=p.Nlin;
Nsite=Lx*Ly;
int i;
nrnbrs = vector<vector<int> >(Nsite, vector<int>(4));
for (i=0; i<Nsite; i++){
if((i+1) % p.Nlin != 0) nrnbrs[i][0] = i+1;
else nrnbrs[i][0] = i - p.Nlin + 1 ;
if(i + p.Nlin < Nsite ) nrnbrs[i][1] = i+p.Nlin;
else nrnbrs[i][1] = i - (Nsite-p.Nlin);
if(i % p.Nlin > 0) nrnbrs[i][2] = i-1;
else nrnbrs[i][2] = i-1+p.Nlin;
if(i - p.Nlin >= 0) nrnbrs[i][3] = i-p.Nlin;
else nrnbrs[i][3] = i + (Nsite-p.Nlin);
}
}
else if(p.latt_=="sqlatt_OBC")
{
Lx=p.Nlin;Ly=p.Nlin;
Nsite=Lx*Ly;
nrnbrs = vector<vector<int> >(Nsite, vector<int>(0));
for (int i=0; i<Nsite; i++){
if((i+1) % p.Nlin != 0){
nrnbrs[i].push_back(i+1);
}
if(i + p.Nlin < Nsite ){
nrnbrs[i].push_back(i+p.Nlin);
}
if(i % p.Nlin > 0){
nrnbrs[i].push_back(i-1);
}
if(i - p.Nlin >= 0){
nrnbrs[i].push_back(i-p.Nlin);
}
}
}
else
{cout <<"Dont know your option for lattice in param.dat .. exiting"<<endl;exit(1);}
}
void LATTICE::print()
{
//THIS FUNCTIONS MAY BE CALLED DURING DEBUGGING TO MAKE SURE LATTICE HAS BEEN DEFINED CORRECTLY
cout <<"---printing out properties of lattice ---"<<endl;
cout<<"size is "<<Lx<<"x"<<Ly<<endl;
cout <<"neighbors are"<<endl;
for (int site=0;site<Nsite;site++)
{
cout <<site<<" : ";
for (size_t nn=0;nn<nrnbrs.at(site).size();nn++)
cout<<nrnbrs.at(site).at(nn)<<" ";
cout <<endl;
}
cout << endl;
}
CLUSTER::CLUSTER(const PARAMS& p, const LATTICE& latt)
{
conf.resize(latt.Nsite);
stack.resize(latt.Nsite);
pr=p.pr;// store prob in a private member of cluster
dfout.open("data.out");
}
CLUSTER::~CLUSTER()
{
dfout.close();
}
void CLUSTER::grow(const PARAMS& p, const LATTICE& latt, MTRand& ran)
{
conf.resize(latt.Nsite); // Initalize Nsite elements of lattice to 0 in conf
// 0 = Not Asked; 1 = Asked, Joined; 2 = Asked, Refused
for (int i = 0; i < p.Nclust; ++i) { // Iterate for Nclust values
z = ran.randInt(latt.Nsite - 1); // Random integer between 0 and Nsite; Selects first lattice element in the cluster algorithm per Nclus
stck_pnt.resize(0); // Set stck_pnt and stck_end vectors to size 0; Will be filled when iterating through each Nclust
stck_end.resize(0); //-----------------------------------------------------------------------------------------------
//while (conf[z] != 0) { z = ran.randInt(latt.Nsite - 1); } // Iterate through lattice elements until we select one that has not been asked to join
conf[z] = 1; // Set element z in conf to have been asked to join and accepted
stck_pnt.push_back(z); // Add z to both stck_pnt and stck_end
stck_end.push_back(z);
for (int j = 0; j = 3; ++j) { // Add z's nearest neighbors to stck_end; Ignore if already been asked
if (conf[latt.nrnbrs[z][j] == 0]) {
stck_end.push_back(latt.nrnbrs[z][j]);
}
}
pnt = 1; // Initialize pnt for trasnferral of stack_end values to stck_pnt
while (stck_pnt.size() < stck_end.size()) {
stck_pnt.push_back(stck_end[pnt]); // Add pnt element of stck_end to stck_pnt
double prob = ran.rand(); // Get probability value for testing if cluster grows
if (prob <= pr) {
conf[stck_pnt[pnt]] = 1; // Set the current stck_pnt element to joined in conf
for (int j = 0; j = 3; ++j) { // Add z's nearest neighbors to stck_end; Ignore if already been asked
if (find(stck_end.begin(), stck_end.end(), latt.nrnbrs[stck_pnt[pnt]][j]) != stck_end.end()) {
// The given value already exists in stck_end, don't add it again
}
else { // The given value is not contained in stck_end, add it to stck_end
stck_end.push_back(latt.nrnbrs[z][j]);
}
}
}
else {
conf[stck_pnt[pnt]] = 2; // Set the given value to haven been asked and refused in conf
}
++pnt; // Increment pnt; ++p is more efficient then p++ due to lack of copying value
}
}
}
/*
void CLUSTER::print(const LATTICE& latt, int index)
{
stringstream ss;
string file_name;
ss << index << ".clust";
file_name = ss.str();
ofstream clout;
clout.open(file_name.c_str());
clout << "#" << latt.Lx << " x " << latt.Ly << endl;
for (int y = 0; y < latt.Ly; y++)
{
for (int x = 0; x < latt.Lx; x++)
clout << conf[x + y*latt.Lx] << " ";
clout << endl;
}
clout.close();
}
*/
void CLUSTER::print(const PARAMS& p, const LATTICE& latt)
{
//vector< vector< vector<int> > > imax(latt.Lx, vector< vector<int>>(latt.Ly, vector<int>(1)));
// Resize and allocate memeory for imax
//-------------- Row = y-position = i/Lx --------------- Column = x-position = i%Lx ---------------- val = conf[i]
ofstream myFile;
myFile.open("imax.out");
cout << "THe following output was calculated for the input parameters; Recorded to 'imax.out'" << endl;
cout <<"[index]" << "\t" << "[x-position]" << "\t" << "[y-position]" << "\t" << "[conf val]" << endl << endl;
for (int i = 0; i < latt.Nsite; ++i) {
val = conf[i]; // Find color value
row = i / latt.Lx; // Find row number
column = i%latt.Lx; // Find column number
cout << i << "\t" << column << "\t" << row << "\t" << val << endl;
myFile << i << "\t" << column << "\t" << row << "\t" << val << endl;
}
myFile.close();
double size = 0.0; // Initialize size
for (int i = 0; i < latt.Nsite; ++i) {
if (conf[i] == 1) {
size += 1;
}
}
double avg_size = size / p.Nclust; // Find avg_size
}
void CLUSTER::meas(const LATTICE& latt)
{
avg_size+=(double)size;
}
void CLUSTER::meas_clear(const LATTICE& latt)
{
avg_size=0.;
}
void CLUSTER::binwrite(const PARAMS& p, const LATTICE& latt)
{
dfout << avg_size/((double)p.Nclust)<<endl;
}
When I set Nclust=0 in the input file, the code runs as expected and gives the proper output in the file and console. However, when I set Nclust equal to any other value, I get the proper lattice console output but the program hangs for the cluster algorithm. I at first assumed that my computer and algorithm were slow and inefficient and that the program was working in some non-linear time. However, after leaving the program running for around 30 minutes for a 4x4 lattice (only 16 elements in the conf[] vector), no progress had been made and I assumed that the program was stuck in a loop.
After spending several hours going over the CLUSTER::grow() method line-by-line and experimenting with changing various bits of code, I have been unable to resolve where this loop error originates from. I would assume it is somewhere in the while loop that compares the size of stck_pnt and stck_end, but I cannot figure out why or where this is. Any help with this would be very greatly appreciated.
Tl;dr: For Nclust !=0, CLUSTER:grow gets stuck in an infinite loop
You have infinite loop here:
stck_end.push_back(z);
for (int j = 0; j = 3; ++j) { // <======== HERE
and here:
conf[stck_pnt[pnt]] = 1; // Set the current stck_pnt element to joined in conf
for (int j = 0; j = 3; ++j) { // <======== HERE
I want to read Graph from file and start function to get max flow but i get some error when i pass this graph as function argument. What am I doing wrong?
int main() {
fstream file;
file.open( "macierz.txt", ios::in );
int n = 7;
int graph[n][n];
int v;
for(int i = 0; i < n; i++){
for(int j = 0 ; j < n; j++){
file >> v;
graph[i][j] = v;
}
}
cout << "Ford-Fulkerson -MATRIX- The maximum possible flow: " << fordFulkersonMatrix(graph, 0, 6) << endl;
function :
int fordFulkersonMatrix(int graph[7][7], int start, int target) {
int u, v;
int rGraph[7][7];
int parent[7];
int max_flow = 0;
for (u = 0; u < 7; u++) {
for (v = 0; v < 7; v++)
{
rGraph[u][v] = graph[u][v];
}
}
Error:
main.cpp|200|error: cannot convert 'int (*)[(((unsigned int)(((int)n) + -0x000000001)) + 1)]' to 'const int (*)[7]' for argument '1' to 'int fordFulkersonMatrix(const int (*)[7], int, int)'|
If you program in Java, for sure you will like the C++ STL interfaces:
// or even better - use Eigen as Peter K mentioned
using MyCustomMatrix = std::vector<std::vector<int> >;
// input by const ref to prevent std::vector copy
int fordFulkersonMatrix(const MyCustomMatrix& input, int start, int target) {
// do whatever you need to do
// you can access your matrix elements like this:
int elem34 = input[3][4]; // only if your matrix if big enough, of course
// you can iterare using C++11 range loops
for (const auto& row : input) {
for(auto elem : row) {
std::cout << "My elem: " << elem << std::endl;
}
}
// and you can access your matrix dim information like this:
int numRows = input.size();
if (numRows > 0) {
int numCols = input[0].size();
}
return 0;
}
Later in the code, you can construct your matrix like that:
MyCustomMatrix mat;
mat.push_back(MyCustomMatrix::value_type()); // add one row
mat[0].push_back(69); // add one elem to the first row
fordFulkersonMatrix(mat, 0, 6);
Expected output:
My elem: 69
This is of course very lazy solution, but maybe you don't need anything more. For some serious linear algebra operations consider using specialized libraries (like already mentioned Eigen, or boost uBLAS).
I am trying to get an understanding of how to work with matrices in C++. The code at the bottom is supposed to take an input matrix and return the places where there are 0s. However, I am getting the following errors:
matrix.cpp:47:3: error: no matching function for call to 'make_zero' make_zero(i,j,l);
^~~~~~~~~
matrix.cpp:8:6: note: candidate function not viable: no known conversion from 'double [i][j]' to
'double (*)[col]' for 3rd argument
void make_zero(int row, int col, double matrix[row][col])
^
1 error generated.
when I try to run the following code:
// Matrix
#include <iostream>
#include <stdio.h>
using namespace std;
void make_zero(int row, int col, double matrix[row][col])
{
int k,l;
for(k=0;k<row;k++)
for(l=0;l<col;l++)
{
if(matrix[k][l]==0)
printf("%d %d\n",k,l);
}
}
int main ()
{
int i = 0,j = 0;
cout << "Enter no of rows of the matrix";
cin >> i;
cout << "Enter no of columns of the matrix";
cin >> j;
double l[i][j];
int p = 0, q = 0;
while (p < i) {
while (q < j) {
cout << "Enter the" << p + 1 << "*" << q + 1 << "entry";
cin >> l[p][q];
q = q + 1;
}
p = p + 1;
q = 0;
}
cout << l << "\n";
make_zero(i,j,l);
}
Any help would be appreciated. Thanks.
There are a bunch of ways to do this with pointers. The most common is
void make_zero(int row, int col, double ** matrix)
defines a pointer (usually rows) to a pointer (usually columns). Unfortunately
double l[i][j];
does not define a pointer to a pointer. If this syntax is supported by the compiler, and the compiler is not required to allow arrays of variable length, it most likely defines a pointer to a 1D array (double l[i*j];) and hides the indexing arithmetic used to convert the array to two dimensions. Anyway, it can't be passed to a double ** because it isn't a double **
Trying to pass as an array is troublesome
void make_zero(int row, int col, double matrix[][NUMBER_OF_COLUMNS])
The number of columns in the array must be known to perform the indexing arithmetic and be provided to any functions called with it. This means that number of columns cannot be changed at run time because the indexing used by the function will be rendered invalid.
Getting around this would require changes to the compiler that will drive it further and further from the C++ standard. A bad idea since there are a number of simple ways around calling functions with multi dimensional arrays. Most depend on arrays of arrays or std::vectors of std::vectors.
And when it comes to these solutions, as far as I'm concerned, the best is don't. I'm not going to cover them.
None of the arrays representing a dimension are guaranteed to be anywhere close to the others in memory, and this limits the CPU's ability to read and cache. Without caching and being able to look ahead, a modern CPU is at a serious performance disadvantage. (Read for more information: Why is it faster to process a sorted array than an unsorted array?)
So what you want is a 1 D array, and those are easy to pass around. The indexing math is also easy, row number * size of column + column number, but you need to pass at least the size of the column around. Rather than scatter the book-keeping around like this:
void make_zero(int row, int col, std::vector<double> matrix)
make a wrapper class like this:
class Matrix
{
private:
std::vector<double> myArray;
size_t nrRows;
size_t nrColumns;
public:
Matrix(size_t rows, size_t columns) :
myArray(rows * columns), // allocate vector to store matrix.
nrRows(rows),
nrColumns(columns)
{
}
size_t getNrRows() const
{
return nrRows;
}
size_t getNrColumns() const
{
return nrColumns;
}
// gets value at row, column and returns a reference so caller can
// modify the value
double& operator()(size_t row, size_t column)
{
// note: No sanity check for row >= nrRows or column > nrColumns
return myArray[row * nrColumns + column];
}
// gets value at row, column and returns a copy so caller cannot
// change the contents of the Matrix
double operator()(size_t row, size_t column) const
{
return myArray[row * nrColumns + column];
}
};
Using the vector gets around a number of common pointer-to-array problems by managing its own memory. No destructor is required and Matrix can be copied and moved without requiring special handling because vector performs all that heavy lifting for us.
And as a usage example, let's make a function that prints the matrix out:
std::ostream & operator<<(std::ostream & out, const Matrix & in)
{
for (size_t i = 0; i < in.getNrRows(); i++)
{
for (size_t j = 0; j < in.getNrColumns(); j++)
{
out << in(i,j) << ' ';
}
out << "\n";
}
return out;
}
And modifying OP's main function to use Matrix we get:
int main()
{
int i = 0, j = 0;
cout << "Enter no of rows of the matrix";
cin >> i;
cout << "Enter no of columns of the matrix";
cin >> j;
Matrix matrix(i,j);
int p = 0, q = 0;
while (p < i)
{
while (q < j)
{
cout << "Enter the" << p + 1 << "*" << q + 1 << "entry";
cin >> matrix(p,q);
q = q + 1;
}
p = p + 1;
q = 0;
}
cout << matrix << "\n";
make_zero(matrix);
}
void make_zero(int row, int col, double ** matrix)
Note, that you need to pass also size of the matrix separately.
Also you can use
std::vector<std::vector<double> >
instead and pass this object by reference, pointer, or just make a copy.
Actually, it works, but your problem in this line also:
double l[i][j];
i, j is unknown during the compile time.
You have 2 ways.
1) dynamically allocate the memory
2) use std::vector<std::vector<double> >. Default constructor already sets zero values. But you can do it manually like this:
#include <iostream>
#include <vector>
void make_zero(std::vector<std::vector<double> > & to_zero) {
for (int i = 0; i < to_zero.size(); ++i) {
for (int j = 0; j < to_zero[i].size(); ++j) {
to_zero[i][j] = 0;
}
}
}
void print_double_vector(const std::vector<std::vector<double> > & to_print) {
for (int i = 0; i < to_print.size(); ++i) {
for (int j = 0; j < to_print[i].size(); ++j) {
std::cout << to_print[i][j] << " ";
}
std::cout << std::endl;
}
std::cout << std::endl;
}
int main() {
// your code goes here
int n, m;
std::cin >> n >> m;
std::vector<std::vector<double> > d(n, std::vector<double>(m));
print_double_vector(d);
make_zero(d);
print_double_vector(d);
return 0;
}
http://ideone.com/0X53Yj
With the help of SO members, the following program successfully converts a static 1D array into a 2D vector by considering below criteria:
Each time an element with value = 0 is encountered, a new row is created. Basically when a 0 is encountered, row value is increased and column value is reset to 0. If a non-zero value is encountered, the row value is maintained and column value is increased.
// declarations
int givenArray[9] = {1, 2, 3, 0, 4, 0, 1, 2, 1};
std::vector<int>::size_type j;
std::vector<int>::size_type i;
vector<vector<int>> my2dArray;
vector<int> dArray;
void calc(vector<int>&, int);
int task;
int sum = 0;
int main() {
for (int i = 0; i < 9;
i++) // iterate through all elements of the given array
{
if (i == 0) // adding the first element
{
my2dArray.resize(my2dArray.size() + 1);
my2dArray.back().push_back(givenArray[i]);
continue;
}
if (givenArray[i] == 0) // re-size if 0 is encountered
{
my2dArray.resize(my2dArray.size() + 1);
}
my2dArray.back().push_back(givenArray[i]);
}
for (std::vector<std::vector<int>>::size_type i = 0; i < my2dArray.size();
i++) {
for (std::vector<int>::size_type j = 0; j < my2dArray[i].size(); j++) {
std::cout << my2dArray[i][j] << ' ';
if (my2dArray[i].size() > 2) {
task = my2dArray[i].size();
calc(my2dArray[i], task);
}
}
std::cout << std::endl;
}
}
void calc(vector<int>& dArray, int task) {
int max = 0;
for (unsigned int j = 0; j < task; j++) {
if (dArray[i] > max)
dArray[i] = max;
}
cout << "\nMax is" << max;
}
However, I want to pass a single row of 2D vector 2dArray to function calc if the number of columns for each row exceeds 2. Function calc aims to find maximum value of all the elements in the passed row. The above program doesn't yield the desired output.
Some improvements:
i and j global variables are not needed, you are declaring the variables of the loops in the loop initialization (ex: for (int i = 0; i < 9; i++), the same for the other loops).
It's better not to used global variables, only when strictly necessary (with careful analysis of why). In this case it's not necessary.
The typedef are for more easy access to inner typedef of the type (ex: size_type).
You were doing the call to calc method in every iteration of the inner loop, and iterating over the same row multiple times, this call should be executed once per row.
Using the size of array givenArray as constant in the code is not recommended, later you could add some elements to the array and forgot to update that constant, it's better to declare a variable and calculated generally (with sizeof).
There is no need to pass the size of the vector to method calc if you are passing the vector.
As recommended earlier it's better to use std::max_element of algorithm header.
If you could use C++11 the givenArray could be converted to an std::vector<int> and maintain the easy initialization.
Code (Tested in GCC 4.9.0)
#include <vector>
#include <iostream>
using namespace std;
typedef std::vector<int> list_t;
typedef std::vector<list_t> list2d_t;
void calc(list_t& dArray, long& actual_max) {
for (unsigned int j = 0; j < dArray.size(); j++) {
if (dArray[j] > actual_max) {
actual_max = dArray[j];
}
}
cout << "Max is " << actual_max << "\n";
}
void calc(list_t& dArray) {
long actual_max = 0;
for (unsigned int j = 0; j < dArray.size(); j++) {
if (dArray[j] > actual_max) {
actual_max = dArray[j];
}
}
cout << "Max is " << actual_max << "\n";
}
int main() {
int givenArray[9] = {1, 2, 3, 0, 4, 0, 1, 2, 1};
int givenArraySize = sizeof(givenArray) / sizeof(givenArray[0]);
list2d_t my2dArray(1);
list_t dArray;
for (int i = 0; i < givenArraySize; i++) {
if (givenArray[i] == 0) {
my2dArray.push_back(list_t());
} else {
my2dArray.back().push_back(givenArray[i]);
}
}
long max = 0;
for (list2d_t::size_type i = 0; i < my2dArray.size(); i++) {
for (list_t::size_type j = 0; j < my2dArray[i].size(); j++) {
std::cout << my2dArray[i][j] << ' ';
}
std::cout << "\n";
if (my2dArray[i].size() > 2) {
// if you need the max of all the elements in rows with size > 2 uncoment bellow and comment other call
// calc(my2dArray[i], max);
calc(my2dArray[i]);
}
}
}
Obtained Output:
1 2 3
Max is 3
4
1 2 1
Max is 2
You have a few problems:
You don't need to loop over j in the main function - your calc function already does this.
Your calc function loops over j, but uses the global variable i when accessing the array.
Your calc function assigns the current max value to the array, rather than assigning the array value to max
Function calc aims to find maximum value of all the elements in the passed row. The above program doesn't yield the desired output.
Instead of writing a function, you could have used std::max_element.
#include <algorithm>
//...
int maxVal = *std::max_element(my2dArray[i].begin(), my2dArray[i].begin() + task);
cout << "\Max is " << maxVal;