C++ Passing arrays by reference to a function but contents remain unchanged - c++

I'm working on a program to solve an Economics model. First, I declare a namespace as follows:
namespace myNameSpace
{
const int d1{10};
const int d2{5};
const int d3{7};
double array[d1][d2][d3]={};
}
Then, I have a function that modifies array:
void doSomething(double (&array)[myNameSpace::d1][myNameSpace::d2][myNameSpace::d3])
{
int i,j,k;
for (i=0, j=0, k=0; i<myNameSpace::d1,j<myNameSpace::d2,k<myNameSpace::d3; i++,j++,k++)
array[i][j][k]=i+j+k+1.0;
}
In the main function I call doSomething as:
int main()
{
doSomething(myNameSpace::array);
for (int i=0;j<myNameSpace::d1;j++)
std::cout << myNameSpace::array[i][1][1] << std::endl;
}
The output I get in the console is:
0
0
0
Can you provide any guidance on this? I've tried passing array without the address-of operator &, but then inside doSomething, array losses the first dimension. Any help will be highly appreciated!!

First of all, your for loop
for (i=0, j=0, k=0; i<myNameSpace::d1,j<myNameSpace::d2,k<myNameSpace::d3; i++,j++,k++)
doesn't do what you think it does, and you would've (hopefully) noticed that if you compiled with warnings (warning: relational comparison result unused).
It has 2, related, major problems:
Since i<myNameSpace::d1,j<myNameSpace::d2,k<myNameSpace::d3 only returns the value of the last comparison, due to the comma operator being used. So, you are effectively iterating until k<myNameSpace::d3.
The for loop you wrote - is just a single loop. It doesn't iterate through all possible combinations of values of i, j, and k, as you might have wanted.
It initializes i, j, k to 0; checks comparison expression (which, as explained by (1) only checks the value of k); and after the code in the loop was run - increments all of i, j, k by 1. Hence - you are setting only the 0/0/0, 1/1/1, 2/2/2, ..., up until k/k/k indices of your array. And, because your middle array has a bound, which is smaller than k - you invoke undefined behavior by stepping out of bounds.
And, lastly, you are printing only the i/1/1 index of your array, and since the only one value in the index range 0/1/1-d1/1/1 that's set is 1/1/1 - it is, exactly what's printed with a non-zero value.
To iterate over the whole array, as, might have been your intention - you should use nested loops, so they would allow all of the loop variables to change independently of one another:
for (i=0; i<myNameSpace::d1; i++)
{
for (j=0; j<myNameSpace::d2; j++)
{
for (k=0; k<myNameSpace::d3; k++)
{
array[i][j][k]=i+j+k+1.0;
}
}
}

for start you have a problem with your for loop
initialize i and running over j. once I changed it, I received some values.

If your array declared with those sizes it's way shorter (and readable)to write:
void doSomething( declspec(myNameSpace::array) &array )
or much better to declare type alias to use it everywhere:
using myArrayType = double[myNameSpace::d1][myNameSpace::d2][myNameSpace::d3];
not to mention that d1,d2 and d3 should be const. Toset ALL elements of array your loops should look like this:
void doSomething( myArrayType &array )
{
int i,j,k;
for ( i = 0; i < myNameSpace::d1; i++)
for ( j = 0; j < myNameSpace::d2; j++)
for (k = 0; k < myNameSpace::d3; k++)
array[i][j][k]=i+j+k+1.0;
}
Everything written in single for divided by comma is happening in single iteration. There are perverted ways to write it in single for() but I don't recommend that code.
for() loop is very flexible. pretty much it looks like
for(expressionFirst; expressionCheck; expressionEach )
statement to execute
expressionFirst can be ANY statement OR a single declaration, it executes only once, before loop starts. expressionCheck executed at beginning of each iteration, it must be any expression that is contextually convertible to bool (i.e. if even explicit T::operator bool() const; is applicable in this case), if it returns false, the loop stops. expressionEach is any expression that evaluates at end of each iteration.
Equivalent of for()
{
expressionFirst
while ( expressionCheck )
{
statement to execute
expressionEach;
}
}
All expressions are optional, so you can use for(;;) - a "forever" loop.
Comma operator you use allows to sequence several expressions, only last one is returned as result. Thus it is called sequence operator. And that's why your loop is wrong.
And you have a typo in main function, which led you to print only the first element of array, no increment of i.

I tried to compile your code, and I got an error in this line:
for (int i=0;j<myNameSpace::d1;j++)
The variable j is undeclared. As you can note, you declared the variable i inside the for loop, but not j. Do you want to loop using i or j? ...Maybe it's i because inside the body of the loop you used it as first-dimension index?
So, maybe you meant this code?
for (int i = 0; i < myNameSpace::d1; i++)
std::cout << myNameSpace::array[i][1][1] << std::endl;
In addition, are you sure the loop inside doSomething does what you mean?
Or maybe you want to loop using three nested loops for each array dimension?
E.g.:
void doSomething(double (&array)[myNameSpace::d1][myNameSpace::d2][myNameSpace::d3])
{
for (int i = 0; i < myNameSpace::d1; i++) {
for (int j = 0; j < myNameSpace::d2; j++) {
for (int k = 0; k < myNameSpace::d3; k++) {
array[i][j][k] = i + j + k + 1.0;
}
}
}
}
Note that in C++ raw arrays are passed by reference, so the &array syntax is unnecessary. Moreover, the compiler also ignores the raw array dimensions (myNameSpace::d1, etc.) for array parameters. Those may be good for documentation purposes though.

Related

the declare scope of loop

Can anyone explain to me, why the below codes have different output?
void GenerateMatrix(int mat[][MaxSize],int ran[],const int rows,const int cols)
{
int i,k=0;
while (i<rows)
{
int j=0;
while (j<cols)
{
mat[i][j]=ran[k];
j,k++;
}
i++;
}
}
and the correct one
void GenerateMatrix(int mat[][MaxSize],int ran[],const int rows,const int cols)
{
int k=0;
for (int i=0; i<rows;i++)
{
for (int j=0; j<cols;j++)
{
mat[i][j]=ran[k];
k++;
}
}
}
the ran[] is an array declared in main()
int main()
{
srand(time(NULL));
int a[10];
for (int i=0;i<10;i++)
{
a[i]={(rand() % 20-0+1)+1};
cout<<a[i]<<endl;
}
.
.
.
}
the first one always output strange random numbers, not in the range of random numbers I set for a[] in main().
The second one is correct.
I have change the scope of declaration of k in the first one function, still the same. I'm just wondering witch part result in this?
You seem to be following a "spoken English" approach to using the ,, like "do something to this list of variables". In this reading, the initialisation failure (where it does create a list other than you mean; spotted by CherryDT) and the incrementation failure (caused by misuse as comma operator; spotted by two commenters, including me) can be "read".
I propose to change that by reading up on the "comma operator" and reviewing some tutorials on other uses of ",".
Consider reducing/avoiding the use altogether, it is too dangerous for your coding habits.
In the first function you have two errors:
The statement
int i,k=0;
is equivalent to
int i;
int k=0;
This means that i is uninitialized and will have an indeterminate value.
You need to explicitly initialize it as well:
int i = 0, k = 0;
The second error is the statement:
j,k++;
This is equivalent to
j;
k++;
That is, it evaluates the left-hand side of the comma operator (i.e. j) and then throws away the result. Then it evaluates and returns the result of the right-hand side (i.e. k++).
You need to increment both variables:
j++;
k++;
Or you can use the for loops which are more compact, still as readable, and harder to make such mistakes as in the first function.

outputting a row of a vector

I am learning c++ and I am currently at halt.
I am trying to write a function such that:
It takes in input a one dimensional vector and an integer which specifies a row.
The numbers on that row are put into an output vector for later use.
The only issue is that this online course states that I must use another function that I have made before that allows a 1d vector with one index be able to have two indexes.
it is:
int twod_to_oned(int row, int col, int rowlen){
return row*rowlen+col;
}
logically what I am trying to do:
I use this function to store the input vector into a temporary vector as a 2D matric with i as the x axis and y as the y axis.
from there I have a loop which reads out the numbers on the row needed and stores it in the output vector.
so far I have:
void get_row(int r, const std::vector<int>& in, std::vector<int>& out){
int rowlength = std::sqrt(in.size());
std::vector <int> temp;
for(int i = 0; i < rowlength; i++){ // i is vertical and j is horizontal
for(int j = 0; j < rowlength; j++){
temp[in[twod_to_oned(i,j,side)]]; // now stored as a 2D array(matrix?)
}
}
for(int i=r; i=r; i++){
for(int j=0; j< rowlength; j++){
out[temp[i][j]];
}
}
I'm pretty sure there is something wrong in the first and last loop which turns into a 2D matric then stores the row.
I starred the parts that are incomplete due to my lack of knowledge.
How could I overcome this issue? I would appreciate any help, Many thanks.
takes in input a one dimensional vector
but
int rowlength = std::sqrt(in.size());
The line of code appears to assume that the input is actually a square two dimensional matrix ( i.e. same number of rows and columns ) So which is it? What if the number of elements in the in vector is not a perfect square?
This confusion about the input is likely to cuase your problem and should be sorted out before doing anything else.
I think what you wanted to do is the following:
void get_row(int r, const std::vector<int>& in, std::vector<int>& out) {
int rowlength = std::sqrt(in.size());
std::vector<std::vector<int>> temp; // now a 2D vector (vector of vectors)
for(int i = 0; i < rowlength; i++) {
temp.emplace_back(); // for each row, we need to emplace it
for(int j = 0; j < rowlength; j++) {
// we need to copy every value to the i-th row
temp[i].push_back(in[twod_to_oned(i, j, rowlength)]);
}
}
for(int j = 0; j < rowlength; j++) {
// we copy the r-th row to out
out.push_back(temp[r][j]);
}
}
Your solution used std::vector<int> instead of std::vector<std::vector<int>>. The former does not support accessing elements by [][] syntax.
You were also assigning to that vector out of its bounds. That lead to undefined behaviour. Always use push_back or emplate_back to add elements. Use operator [] only to access the present data.
Lastly, the same holds true for inserting the row to out vector. Only you can know if the out vector holds enough elements. My solution assumes that out is empty, thus we need to push_back the entire row to it.
In addition: you might want to use std::vector::insert instead of manual for() loop. Consider replacing the third loop with:
out.insert(out.end(), temp[r].begin(), temp[r].end());
which may prove being more efficient and readable. The inner for() look of the first loop could also be replaced in such a way (or even better - one could emplace the vector using iterators obtained from the in vector). I highly advise you to try to implement that.

why won't push_back function insert values into vector with defined size

I just started learning C++. So, I cannot figure out why vector member function does not insert values into vector.
int main (){
vector<char> v(5);
char x = 'a';
for (int i = 0; i < v.size(); ++i) {
v.push_back(x);
++x;
}
for (int i = 0; i < v.size(); ++i)
cout << v[i];
keep_window_open();
return 0;
}
I cannot figure out why vector member function does not insert values into vector
It does insert the values in the fact. The execution, just doesn't reach the printing of vector contents, since the loop:
for (int i = 0; i < v.size(); ++i) {
v.push_back(x);
++x;
}
Is an infinite one.
Before the first iteration v.size() return 5 (since that is the number of elements, the vector was constructed with), hence the i < v.size() during the first iteration evaluate to 0 < 5.
The loop, then does its thing, by inserting the element into the vector (increasing the v.size() by 1 in the process), and increasing i by 1. Hence, the comparison during the second iteration evaluates to 1 < 6.
It, then, continues, in the similar fashion, towards infinity (or until you kill it).
#juanchopanza "Even if it were, UB could still leave you with an infinite loop." - That's not how UB works. If a program has UB anywhere, the entire program is invalid and any behaviour is OK. Doing what you intended, an infinite loop, a crash, formatting your harddrive. All are OK results of a program invoking UB.

2D array elements not being read properly

The output is a string of numbers of entire row/column instead of a single number. Can someone please help me in this?
int main() {
/* Enter your code here. Read input from STDIN. Print output to STDOUT */
int t;
cin>>t;
while(t--){
int n,m,cnt=0;
cin>>n>>m;
for(int i=0;i<=n+1;i++){
for(int j=0;j<=m+1;j++){
if(i==0||i==n+1||j==m+1||j==0) G[i][j]=0;
cin>>G[i][j];
}
}
cout<<G[1][2]<<endl;//this gives wrong o/p
return 0;
}
Most likely you are reading out of bounds due to a i <= n + 1 and j <= m + 1 conditions in your for loops thus invoking undefined behavior resulting in a corrupted stack which explains the output you are seeing. Modify the boundaries to:
i < n and j < m. Arrays are zero indexed in C++. First array element is accessed via somearray[0] and the last element is somearray[n-1] not somearray[n] which is what you are trying to access in your code. The same goes for multi-dimensional arrays. The statement of:
cout << G[i][j] << endl;
is wrongly placed outside the for loops. It should be inside the inner for loop. The array should be defined as a second statement in your while loop:
int G[n][m]; // Avoid VLAs
That being said variable length arrays are not part of the C++ standard and you should prefer std::vector and std::array to raw arrays.
Assuming G is a 2D array of size n x m, then you go out of bounds here:
for(int i=0;i<=n+1;i++) {
for(int j=0;j<=m+1;j++)
since array indexing starts from 0, and ends at size - 1.
As a result, your code invokes Undefined Behavior. To avoid that, simply change your double for loop to this:
for(int i = 0; i < n; i++) {
for(int j = 0;j < m; j++)

Pointer Array Sorting Algorithm in C++

hoping I can get a little advice on a sorting method I made.
This is just a test for another program i am making and this test has a bug I can't figure out. The purpose of this code is to create a int pointer array and sort the pointers in that array by the contents of regular int array.
The bug is for my second for loop which doesn't allow me to use a j!=-1 therefore not allowing me to sort the first element of the array. Please help. Thanks!!
//create array
int c[8] = {3,1,5,7,8,2,6,4};
//create pointer array
int *newptr[8];
for(int k = 0; k<8; k++)
{
newptr[k] = &c[k];
}
//sort pointer array
for(int j = 0; j<8; j++)
{
cout << "test1\n\n";
cout << *newptr[j] << "and" << *newptr[j+1];
for(;*newptr[j] < *newptr[j+1] && j!=0; j--)
//using j!=-1 doesn't work which causes me to not be able to sort the first element
//in the array properly
{
cout<< "test2";
int *temp;
temp = newptr[j+1];
newptr[j+1] = newptr[j];
newptr[j] = temp;
}
}**
Order matters.
Change
for(;*newptr[j] < *newptr[j+1] && j!=0; j--)
to:
for(; j != -1 && *newptr[j] < *newptr[j+1]; j--)
Presumably the bug is something that causes the code to crash. This happens because the expression in the for loop is evaluated left-to-right. So *newptr[j] is evaluated before checking if j != -1. So it's conceivable that, at some point, j is equal to -1 when *newptr[j] is evaluated, which is illegal.
Changing the order does make a difference for a second reason: short-circuit evaluation.
When evaluating two an expression made of two conditions A and B, C++ does not always need to evaluate both conditions.
For example in the statement
if (A && B) {
//do something
}
if A is evaluated to be false, then obviously A && B cannot evaluate to true regardless of what B evaluates to. So B's value is never even checked. So in your case, in the expression
j != -1 && *newptr[j] < *newptr[j+1]
if j != -1 is false, C++ will not need to evaluate the rest of the expression in order to know that the whole expression is false. So *newptr[j] never happens and you don't get the bug.
As pointed out by maditya the problem is that the expression tries to access an invalid index before checking the index itself but I see the question is tagged C++. Do you have any explicit reason to not use STL?
struct sorter {
bool operator() (const int* i, const int* j) { return (*i<*j);}
};
int c[8] = {3,1,5,7,8,2,6,4};
int *newptr[8];
for(int k = 0; k<8; k++)
newptr[k] = &c[k];
std::sort(newptr, newptr+8, sorter());
or even shorter in C++11:
int c[8] = {3,1,5,7,8,2,6,4};
int *newptr[8];
for(int k = 0; k<8; k++)
newptr[k] = &c[k];
std::sort(newptr, newptr+8, [](const int *i, const int *j){return *i < *j;});