How to have a function act on non-argument variables? - c++

I am trying to write a function which will take in multiple indices and do something based on the values in an array at those indices. If I do not declare the arrays as arguments to the function (which will always operate on the same two arrays) I get X/Y was not declared in this scope, but if I do attempt to declare them, I get "error: declaration of ‘X’ as multidimensional array must have bounds for all dimensions except the first," and the bounds are not known until runtime.
Is there any way to do this in a function, or do I have to explicitly write the code in main every time?
Code:
double foo(int A, int B, int t){//A, B, and t are indices
int x = X[A][t]-X[B][t]; //X and Y are 2D arrays
int y = Y[A][t]-Y[B][t];
double d;
//do some math ...
return d;
}
int main{
.
.
.
int X[nPeople][tMax]={0};
int Y[nPeople][tMax]={0};
.
.
.
for(int t=0; t<tMax; t++){
for(int n=0; n<nPeople; n++){
foo(n,a,t);
}
}
.
.
.
return 0;
}

There are multiple ways:
1- Use built-in std::vector library with the following inclusion:
#include <vector>
Vectors are dynamic arrays so when you initialize them they do not have a strict capacity which you can never change. On constrast, they grow larger with each element you push or insert. As far as I can see you are dealing with matrices so you need two dimensional arrays, no problem. Here is the code for it:
std::vector<std::vector<int> >
2- Use global variables. Variables that are declared outside of the functions are considered global so they will be visible to every function beneath it. Altough it is not considered to be good coding practise because of the bugs it may cause in a large scale problem, if you are confident enough that it will not pose a threat to your code safety/cleanness, go ahead use it!
3- Use dynamically allocated arrays and pass the pointers as parameters so that you can deal with any size you want

There are several ways a function can work with data:
Use global data:
std::vector<std::vector<int>> X;
std::vector<std::vector<int>> Y;
double foo(int A, int B, int t){ //A, B, and t are indices
int x = X[A][t]-X[B][t]; // X and Y are global 2D arrays
int y = Y[A][t]-Y[B][t];
double d;
//do some math ...
return d;
}
unfortunately shown too many times in sample code, but (mutable) global have lot of issues (hard to test, hard to re-use the code, hard to reason about the code)
Pass them as arguments:
double foo(const std::vector<std::vector<int>>& X, // X and Y are 2D arrays
const std::vector<std::vector<int>>& Y, // As we can see, so unneeded comment
int A, int B, int t){ //A, B, and t are indices
int x = X[A][t]-X[B][t];
int y = Y[A][t]-Y[B][t];
double d;
//do some math ...
return d;
}
bind them using a class:
class C
{
std::vector<std::vector<int>> X;
std::vector<std::vector<int>> Y;
public:
double foo(int A, int B, int t){ //A, B, and t are indices
int x = X[A][t]-X[B][t]; // X and Y are member 2D arrays (it should be trivial (`this->` might help), so comment not needed neither)
int y = Y[A][t]-Y[B][t];
double d;
//do some math ...
return d;
}
};
care to create coherent classes and avoid god class (which have mostly same default as global).

Related

What is the preferred syntax for initializing an object to pass as an argument in C++08?

Let's say I have a struct that I am just using as an aggregate data holding device. As an example, a struct below holds two integer values. Let's assume I have a vector of these structs called myVec and I want to add a new struct to the vector with push_back. My understanding is that in C++11 and after one can achieve this without needing to make a named variable and passing that variable as an argument but instead can do the following.
struct coordinate {
int y;
int x;
};
//assume an initialized vector<coordinate> myVec
//and two ints newY, newX not known at compile time
myVec.push_back( {newY,newX});
Based on the Notes section of https://en.cppreference.com/w/cpp/language/aggregate_initialization,
It seems like this is an example of using aggregate initialization in a constructor initializer list but I might be wrong about that. That source indicates that this syntax doesn't work pre-C++11 and while it works with MSVS2017 it doesn't with Visiual C++ for Python which is what I am targeting. Is there a syntax pre-C++11 that would allow me to add another struct to the vector without first making a named struct variable and passing that named variable to the push_back function? While this is a single example of what I'm trying to accomplish, I will have several such vectors in my project and the structs won't always be simple pairs of ints. I would prefer to avoid having several "temp" dummy variables floating around as placeholders for arguments simply because it feels cleaner to avoid having them floating around. An example of what I would prefer to avoid but will use if necessary is given below. The example adds the list of all coordinates where both the x and y values are between 0 and 9 inclusive to the vector.
coordinate temp = {0,0};
for (int r = 0; r < 10; ++r){
for (int c = 0; c < 10; ++c){
temp.y = r;
temp.x = c;
myVec.push_back(temp);
}
}
Just give your struct a constructor:
struct coordinate {
int x, y;
coordinate( int ax, int ay ) : x(ax), y(ay) {}
};
You can then say things like:
myVec.push_back( coordinate( 12, 42 ) );

Assigning vector sizes as array lengths

So I am currently working on a program in c++, and I want to make the following decleration:
methodOne()
{
vector<int> one;
vector<int> two;
... assigning to one and two...
int a = one.size();
int b = two.size();
methodTwo(a, b);
}
methodTwo(int a, int b)
{
int array[a][b];
}
When I attempt this, I get an error: a and b must be constant
I have tried to assign a and b to const int a, const int b. However, that was no help. I was wondering if anyone knows how I can fix this kind of error. Thanks in advance for any help you are able to give!
An array's size must be known before the program runs. Its size is part its complete type, just like the element type itself.
You need something with a dynamic size instead. Use a std::vector<int> of size a * b:
methodTwo(int a, int b)
{
std::vector<int> array(a * b);
}
You could also use a std::vector<std::vector<int>> instead, but why take all the trouble? After all, you can access the one-dimensional vector's elements as if it was two-dimensional data structure by calculating the offsets accordingly:
methodTwo(int a, int b)
{
std::vector<int> array(a * b);
// ...
int x = 5;
int y = 6;
auto const element = array[y * a + x];
}
I see you already using vector so you can replace your array with
typedef std::vector< std::vector<int> > matrix;
matrix name(a, std::vector<int>(b));

Using a 2-d Array in a function

I am trying to solve a dynamic programming problem and I need to take the user input in the form of a 2-d array and use the values from the 2-d array inside the function.
The values of the 2-d array will not be changed when used inside the function.
In the function int dp i am getting the
error:
declaration of 'a' as multidimensional array must have bounds for all dimensions except the first
int max(int a,int b,int c)
{
if(a>=b && a>=c)return a;
if(b>=c && b>=a)return b;
else return c;
}
int max2(int a,int b)
{
if(a>b)return a;
else return b;
}
int dp(int i,int j,int a[][],int p,int q)
{
if((i-1)>=0 && (j-1)>=0 &&(i+1)<p &&(j+1)<q )
return max(a[i][j]+dp(i-1,j+1,a,p,q),a[i][j]+dp(i+1,j+1,p,q),
a[i][j]+dp(i,j+1,p,q));
if(i==0 && j!=0 && (j+1)<q)
return max2(a[i][j]+dp(i+1,j+1,p,q),a[i][j]+dp(i,j+1,p,q));
}
int main()
{
int p,q,r,s,T,a,b,i,j,k;
scanf("%d",&T);
for(a=0;a<T;a++)
{
scanf("%d %d",p,q);
int z[p][q];
int max=0;
for(i=0;i<q;i++)
{
for(j=0;j<p-1;j++)
scanf("%d ",&z[j][i]);
scanf("%d",&z[j+1][i]);
}
for(i=0;i<p;i++)
{
if(dp(i,0,z,p,q)>max)
max=dp(i,0,z,p,q);
}
}
}
It's all in the error message:
declaration of 'a' as multidimensional array must have bounds for all dimensions except the first
Your function signature does not have bounds for a's 2nd dimension:
int dp(int i,int j,int a[][],int p,int q)
// ^^^^^
You need to fill it in with a[][N] where N is whatever the correct bound is. The issue is that you are using VLAs here:
scanf("%d %d",p,q);
int z[p][q];
That is non-standard C++, and basically means you cannot write the signature of dp, since the second bound has to be known as a compile-time constant. You could either make it a single-dimensional array:
int* z = new int[p*q];
int dp(int i, int j, int* a, int p, int q)
// ^^^^^^
or dynamically allocate it in 2 dimensions and just pass it in that way:
int** z = new int*[p];
for (int i = 0; i < p; ++i) {
z[i] = new int[q];
}
int dp(int i, int j, int** a, int p, int q)
// ^^^^^^^
The function dp needs some information to perform meaningful index calculations, either done by the compiler or in the actual inplementation. Either a dimension must be specified in the type or the argument a could be of type int** while its dimensions are provided as separate arguments to dp. As this is C++, a type of std::vector< std::vector< int > > might be more suitable for the task.
You get that error because you cannot leave both the index(row,column) empty in int a[][] in your function declaration. You must have both specified or atleast the value of column index.
Use dynamic declaration
int **z = new int*[p];
for (int i = 0; i < p; i++)
z[i] = new int[q];
Change the parameter int a[][] to int **a
You can't dynamically declare an array on the stack as the size has to be known at compile time. The only way to do this would be by allocating memory for the array on the heap using the new keyword, then you could declare the size at run time.
Far easier, however, would be just to use a container class, or in your case, a container of containers like a vector of vector of ints;
#include <vector>
vector< vector<int> > arrArray(rows, vector<int>(columns));
The syntax might look a bit strange, but breaking it down;
vector<int> - a vector of type int
vector< vector<int> > - a vector of vectors of type int
arrArray(rows, vector<int>(columns)); - here in the first parameter, we are saying; create rows number of vector<int>'s in our array, and the second parameter initalises the array to some value. If it were just a 2D array of int, we might initalise it to 0, or omit the second parameter and rely on the default value of int. But, because our multidimensional vector also contains vectors, we set each row of our main vector to store a vector of int's which holds columns amount of integers.
Now you can access the array like you would any other;
arrArray[2][0] = 5;
You also get all the added benefits that container classes contain, including iterators and a lot of useful class methods for manipulating and checking your array. Once you understand the syntax of creating container classes, you'll find them much easier to work with than arrays. You also don't have to worry about having to manage your own memory, and have the ability to do bounds checking before accessing vector elements.

Replace Numerical Recipe's dmatrix with a C++ class

I'm revamping an old application that use Numerical Recipes' dmatrix quite extensively. Since one of the reasons I'm working on the application is because its code is about to be opened, I want to replace all of the Numerical Recipes code with code that can be freely distributed.
dmatrix is a function that returns a matrix of doubles. The called supplies the lower and upper bound for each index, like so:
double **mat = dmatrix(1,3,1,3);
mat now has 3 rows, from 1 to 3, and 3 columns, from 1 to 3, so that mat[1][1] is the first element and mat[3][3] is the last.
I looked at various C++ matrix implementations, none of them allowed me to specify the lower bound of each dimension. Is there something I can use, or do I have to write yet another matrix class for this?
I believe that you can easily make a wrapper of some other matrix implementation to add the lower bound feature. Example (untested):
class Matrix {
OtherMatrix m;
int lowerX, lowerY;
public:
Matrix(int lx, int hx, int ly, int hy) :
m(hx-lx, hy-ly),
lowerX(lx), lowerY(ly) { }
MatrixCol operator[] (int x) {
return {this, x};
}
};
class MatrixCol {
friend class Matrix;
Matrix* mm;
int x;
public:
double& operator[] (int y) {
return mm->m[x - mm->lowerX, y - mm->lowerY];
}
};
This may require a little more robust implementation depending on your use case. But this is the basic idea, expand from it.

C++ returning an array

I'm new to C++ programming and i want to make a function that gives you all the common dividers into an array, and afterwards use it in int main()
Is returning an array from a function possible :D?
Thank you!
Code: http://pastebin.com/K8195wzF
Returning a dynamically-sized container like std::vector has the best use case here:
#include <vector>
...
std::vector<int> dividers(int x, int y) {
std::vector<int> divi;
...
return divi;
}
Returning by value creates a copy, ensuring no dangling pointers. Such is the case when returning a local array through a pointer: the memory will be lost when the function exits leaving the pointer to point to garbage.
Yes it is possible to return an array in form of a pointer, but this is not recommended as you won't know its size in advance. But take care not to return the address of a local variable (allocated on the stack!!). Another problem with your code is that you didn't initialize d. The preferred C++ way would be to return a vector of the type (you do not need d anymore)
#include <vector>
....
vector<int> dividers(int y,int x){
int yx;
vector<int> divi;
divi.reserve(100);
if(y > x){
yx = y;
}
if(x > y){
yx = x;
}
for (int n = 1; n <= yx; n++){
if ((n%y==0) && (n%x==0)){
divi.push_back(n);
}
}
return divi;
}
You should read about iterators too to modify the loop that is in your main function.
Big mistake in my code removed... Thanks for pointing it out. I did the same mistake with vector that what you had with the array. Fixed now... Stupid me...
No it's not possible. You could return a vector, or you could pass a pointer to the first element of an array to your function.
Looking at your code, the pointer option would look something like this
int dividers(int y,int x, int* divi){
...
}
int main()
{
int divi[100];
...
dividers(x, y, divi);
}
The vector solution might look like this
std::vector<int> dividers(int y,int x){
std::vector<int> divi;
...
divi.push_back(n); // when you want to add a divider to your vector
...
return divi;
}
int main()
{
std::vector<int> divi;
...
divi = dividers(x, y);
}
You could do the following:
typedef int arrT[10]
arrT *func() {}
whereby one is defining arrT to be an alias of an array of 10 ints or
int (*func())[10]{}
whereby one is defining func when dereferenced to return an array of 10 ints.
A using declaration such that using arrT = int[10] is also possible.
As others have noted, returning a std::vector from a function containing the type desired is possible with a function declared as std::vector<int> func(){}.
Also, you could use another container std::array<> and forget built-in arrays altogether.
Reference: C++ Primer; Lippman, Lajoie, Moo