Why can't functions change vectors when they can change arrays? - c++

I am trying to move from arrays to vectors in cpp for problem-solving and its overall benefits. I am facing some issues here even though this logic works on arrays.
#include <iostream>
#include <vector>
using namespace std;
void PrintArray(vector<int> v) { // O(n)
for (int i=0; i<v.size(); i++)
cout << v[i] << " ";
cout << endl;
}
void LF1(vector<int> A) { // O(n)
int temp = A[0],i;
for (i=0; i<A.size()-1; i++)
A.at(i) = A.at(i+1);
A.at(i)=temp;
// PrintArray(A); <-- shows updated array here
}
void LF(vector<int> A, int d) {
d = d % (A.size());
cout << "d%n: " << d << endl;
for (int j=0; j<d; j++)
LF1(A);
PrintArray(A);
}
int main(int argc, char const *argv[]) {
vector<int> A;
int d;
for(int i=1; i<6; i++)
A.push_back(i);
PrintArray(A);
cout << "Enter number of Left rotations to perform : ";
cin >> d;
LF(A,d);
return 0;
}
Problem 1: When I am calling LF1 inside of LF it returns the same array without rotating but when I write the code for LF1 inside of LF it seems to rotate.
Problem 2: The PrintArray() prints the rotated array only when called from LF1() or just immediately after its code when written (instead of calling LF1()) in LF() when causes it to print the array d times. Where d is the required rotations.

Regarding what you're doing wrong...you are passing the vectors by value. You don't expect changes to an integer to affect it in the caller when you pass it as a value...
void SomeFunction(int i) {
i = i + 1;
printf("Inside SomeFunction %d\n", i); // changed, 11
}
int i = 10;
SomeFunction(i);
printf("Outside SomeFunction %d\n", i); // unchanged, 10
...if you wanted to see a change, you would have to pass a pointer, such as int *pi, and then update it as *pi = *pi + 1;
The same principle applies to vectors and other C++ classes. If you just pass it as a value, the whole vector is copied. (Well, if it needs to be, a temporary could just be reused). But for now think of it as being copied: just as there's a difference between passing an integer and a pointer-to-an-integer, there's a difference between a vector and a pointer-to-a-vector.
You could pass a pointer to the vector if you intend to change it...or... C++ offers another tool called the reference, where references are very much like pointers but with a few differences. If you just changed your arguments to vector<int> &A then your code should work, because the arrays would be "passed by reference" instead of getting copied when they are "passed by value", so changes would take effect. If you don't want a function to need to be able to modify an array but still want to avoid the copy, pass by const reference, e.g. const vector<int> &A (e.g. this is what your PrintArray() should use).
You might not want to get too hung up on the details of references for now, other than thinking of it as a "convenient kind of pointer where you don't have to put the * on all the places you want to dereference". But in case you want to know more specifics:
What are the differences between a pointer variable and a reference variable in C++?
I am facing some issues here even though this logic works on arrays.
And this is probably the source of your confusion. Which comes from the fact that C-style arrays decay into pointers under the hood:
Passing an Array by reference in C
I think that's something that it's reasonable to be confused by, given that other types (such as integers and vectors) don't. It's just a quirk of C, that C++ inherited. So when C++11 wanted to clean that up, a wrapper class called std::array was introduced:
https://embeddedartistry.com/blog/2017/6/28/an-introduction-to-stdarray
https://en.cppreference.com/w/cpp/container/array
But C++ also has an algorithm to do rotation...
So if you want to see a good example of how this would be done, it's a place to start:
#include <vector>
#include <iostream>
#include <algorithm>
int main() {
std::vector<int> v{1, 2, 3, 4};
std::rotate(v.begin(), v.begin() + 1, v.end());
for (auto &i : v)
std::cout << i << " ";
std::cout << "\n";
}
That will get you 2 3 4 1. The documentation has other examples, read through:
https://en.cppreference.com/w/cpp/algorithm/rotate

Related

2-D array and pointer in C++ -- how to go through every every element using pointer of a 2-D matrix

For practice, I want to define a Matrix addition of two 2-D Matrces by pulling the pointers of them. Here is the initiation
const double A[2][2]={{1,2},{3,4}};
double B[2][2]={{4,3},{2,1}};
const double* a=*A;
double* b=*B;
However, since the pointer merely points to the first element of the first array within each matrix, a=*(A+0), how can i go through every element of each Matrix? And I only wnat to use pointer as parameter here.
void D2Add(const double*, double*){
...for loop here...
}
I only wnat to use pointer as parameter here
That way you will have undefined behavior. The different sub arrays may be placed in different pages/segments in memory and Accessing an array out of bounds is not guaranteed to work. I removed the sentence trying to explain a possible pitfall when accessing a sub array out of bounds because I can't find a good description of it right now.
One way to avoid undefined behavior is to take the arrays by reference instead:
#include <cstddef>
#include <iostream>
template<std::size_t Y, std::size_t X>
void D2Add(const double(&A)[Y][X], double(&B)[Y][X]) {
for(std::size_t y = 0; y < Y; ++y) {
for(std::size_t x = 0; x < X; ++x) {
B[y][x] += A[y][x];
}
}
}
int main() {
const double A[2][2]={{1,2},{3,4}};
double B[2][2]={{4,3},{2,1}};
D2Add(A, B);
for(auto& inner : B) {
for(auto value : inner) std::cout << value << ' ';
std::cout << '\n';
}
}
Output:
5 5
5 5
This is a very interesting question actually.
Formally, you're indeed only allowed to access the elements of the first sub-array, and trying to access the other one would cause undefined behavior.
But practically, there's a good chance that you might be able to loop from 0 to 4, treating the arrays as 1D arrays of size 4. But I would advise against doing this if possible.
I Hope you have good understanding of how Multi-Dimensional array is laid in memory.
problem- It is not possible by just pointers until your function has a way to know dimensions of array.
As specified, we need to pass dimensions to functions as well.
Since you only want to go through every element, I'll be print each element for demonstration.
void D2Add(const double* ptr, int nRow, int nCol) {
for (int i=0; i<nRow; i++) {
for (int j=0; j<nCol; j++) {
std::cout << *(ptr+(i*nCol)+j) << std::endl;
}
}
}

Passing class with array member into overload of function that uses that array member

I'm trying to implement a polynomial class consisting of an int (degree) and an integer array (the coefficients for each term). I have a function to print the polynomial, which works fine when I pass in the degree and term array directly, but things get funky when I try to put those values into an instance of my polynomial class.
I am using variadic arguments in the polynomial's constructor, such that you should be able to call polynomial(degree, ). I made sure to output each term in my va_list so I know I'm targeting what I want to.
Here's my class:
class polynomial{
public:
polynomial(int degree...){
va_list args;
_degree = degree;
int p[degree];
va_start(args,degree);
for(int i = 0; i < degree; i++){
p[i] = va_arg(args,int);
cout << p[i] << endl; //just to verify that I'm grabbing the right values.
}
va_end(args);
_terms = p;
}
int degree(){return _degree;}
int* terms(){return _terms;}
private:
int _degree;
int* _terms;
};
And here's the function(s) I'm using to print the polynomial:
void printArray(int*p, int l){
std::cout << "[";
for(int i = 0; i < l; i++){
std::cout << p[i];
if(i != l-1) std::cout << ",";
}
std::cout << "]" << std::endl;
}
void printArray(polynomial p){
printArray(p.terms(), p.degree());
}
my main function:
int main()
{
int a[3] = {2,5,3};
printArray(a,3);
polynomial p1(3,2,5,3);
printArray(p1.terms(), p1.degree());
printArray(p1);
return 0;
}
and the output:
[2,5,3]
2
5
3
[2,0,94004573]
[1,0,1]
As you can see, I call printArray() 3 times. The first time, I directly create an integer array and pass it and its length into printArray(). This time, it works fine, outputting [2,5,3] as expected. The second time, I again use the first implementation of printArray(), but this time I pass in the int* and int from an instance of my polynomial. This time, I get some array whose first two elements always seem to be 0 and 2 and whose last value is some garbage value.
The third time, I simply pass in the polynomial to the second implementation of printArray(). This seems to output [1,0,1] consistently (which is of course incorrect).
I suppose it wouldn't be too confusing if the second and third calls to printArray() generated the same garbage values, but as it stands, I am fairly lost in terms of what's happening behind the scene. Any help at all would be appreciated. Thank you!
The problem is these two lines:
int p[degree];
and
_terms = p;
The first (besides not being a non-portable variable-length array extension of your compiler) defined p to be a local variable.
The second line makes _terms point to the first element of this array.
Then the constructor ends, and the life-time of p with it, leaving you with an invalid pointer in _terms.
The natural solution is to use std::vector instead. And if you need to use pointers (because assignment/exercise requirements) you need to use dynamic allocation (using new[], and also then you need to learn about the rule of three/five).

How to pass 3D arrays using triple pointers?

Is it really possible?
I know how to pass 2-D arrays using double pointer. And as per my understanding, it should for 3-D arrays as well. But I would love to be proven wrong. This question will surely reveal how the arrays are interpreted.
The fact here is that the 3-D array is a contiguous block, not some array of pointers of smaller chunks.
This program gives me error :
#include <iostream>
using namespace std;
void display(int ***arr, int l, int m, int n)
{
for(int i=0; i<l; i++)
for(int j=0; j<m; j++)
for(int k=0; k<n; k++)
cout << *(*(*(arr+i)+j)+k) << endl;
}
int main()
{
int arr[][2][2] = {{{1,2},{3,4}},{{10,20},{30,40}}};
display((int***)arr,2,2,2);
}
OUTPUT
test.cpp:17:19: error: cannot convert 'int (*)[2][2]' to 'int***' for argument '1' to 'void display(int***, int, int, int)'
display(arr,2,2,2);
^
2D Arrays passed to double pointer
I believe I can do something similar to 3D arrays as well, but this is way too bad to read.
#include <iostream>
using namespace std;
void display(int **arr, int m, int n)
{
for(int i=0; i<m; i++)
for(int j=0; j<n; j++)
cout << *(*(arr+i)+j) << " " << arr[i][j] << endl;
}
int main()
{
int arr[][3] = {{1,2,3},{4,5,6}};
int *temp[2];
for(int i=0; i<2; i++)
temp[i] = *(arr+i);
display(temp,2,3);
}
OUTPUT
1 1
2 2
3 3
4 4
5 5
6 6
What you do for 2D arrays is correct because you have built an auxiliary array of pointers and you pass that array of pointer as a int **. Even for 2D arrays, this
void display(int **arr, int m, int n);
...
int arr[][3] = {{1,2,3},{4,5,6}};
display(arr,2,3); // WRONG! use a 2D array as an array of pointers
would be wrong.
And anyway, the C++ standard is unfriendly with multi-dimensional arrays: there is no way to write a strictly conformant program passing a multi-dimensional arrays of unknown dimension. Many compilers accept it as extensions, but it may be non portable on other compilers.
The idiomatic way is to only use 1D arrays as the underlying data structure, and provide methods to process it as a multi-dimensional container by internally doing index computations.
BTW I have tried to build a multi-dimensional contiguous container with arbitrary run-time dimensions, respecting all the constraints of the standard containers, and given up after realizing that the standard did not allow it: it is impossible to build a nice iterator over object that do not hold their own data. Here is my best attempt. The answers and comments explain why it is hopeless.
Although you can pass a 1-D array like this
void pass1Darray(int a[])
{
statements;
}
int main()
{
int a[10];
pass1Darray(a);
}
In fact, compiler would see int a[] as int* a and this is the reason why people wonder is it possible to pass a 2-D array by pointer_to_pointer.
But it doesn't make sense!
If you want to pass a 2-D arraybob[5][10], you can see bob as a array and its element is a array, and pass it like this
void pass2Darray( int (*array) [10] ) // it means you pass a pointer which points to a int[10]
{
statements;
}
int main()
{
int bob[5][10];
pass2Darray(bob);
}
This is about passing a 2-D array.
btw, English is not my native langueue, and I'm a beginner of c++ , too.
If there's something wrong, please let me know, thank you.
When you declare an array locally int arr[][2][2] the compiler instantiate a one dimensional vector and "remember" what the offset is to get the right index.
Also local arrays are stored in the stack which is not good if you need large matrices. Another property of int arr[][2][2] is that why when you try to pass it as argument to a function, int arr[][2][2] is the type. You have to specify all the dimensions.
Pointers work differently. If you instantiate a 2D array you need to allocate an array of pointers to rows, and allocate each row array to hold data individually. In C++ I think it's best to use the standard library, which has a standard implementation of dynamic pointers that take care of all allocations. std::vector
In conclusion:
I would use local arrays when the memory required is small and I don't need to use pointers. Local arrays are good if you want to avoid using the heap.
Using pointersm new/delete or malloc/free is allowed but I think it's better to use the standard library in C++, so I would use std::vector in all other scenarios.
I believe I can do something similar to 3D arrays as well, but this is way too bad to read.
Yes, as n.m. explained in their comment
In your 2D code you have created a brand new array of pointers, populated it, and passed it to your function instead of your original 2D array. In your 3D code you have not attempted anything of the sort.
Since the question is tagged as C++, we can use a different toolbox than C coders have to.
In C++, a parameter can be passed to a function by reference, not only by value, and we can write a template that can be used by the compiler to generate the right function for used type.
#include <iostream>
#include <iomanip>
template <class T, size_t L, size_t M, size_t N>
void display( T const (&arr)[L][M][N], int width )
// ^^^^^^
{
for (size_t i = 0; i < L; ++i) {
for (size_t j = 0; j < M; ++j) {
for (size_t k = 0; k < N; ++k) {
std::cout << std::setw(width) << arr[i][j][k];
}
std::cout << '\n';
}
std::cout << '\n';
}
}
int main()
{
int arr[3][2][4] = {
{ {1,2,3,4},
{5,6,7,8}
},
{ {10,20,30,40},
{50,60,70,80}
},
{ {100,200,300,400},
{500,600,700,800}
}
};
display(arr, 5);
}
Live, HERE.
The next step would be, of course, to write a class which encapsulates the concept of a multidimensional array.

Array as argument to function

Here in f() I accept array to be of maximum size 4 but it still runs fine when I pass an array of size greater than 4(here 10), I know arrays in c++ are passed as pointers by default but than when is this method of passing array useful?
#include<iostream>
using namespace std;
void f(int a[4]){
for(int i = 0;i < 3;i++){
a[i] += 10;
}
}
int main(){
int a[10];
for(int i = 0;i < 10;i++)
a[i] = i;
f(a);
for(int i =0 ;i < 10;i++){
cout<<a[i]<<" ";
}
cout<<"\n";
return 0;
}
output: 10 11 12 3 4 5 6 7 8 9
I know arrays in c++ are passed as pointers by default
Correct.
This:
void foo(int a[4])
is literally rewritten to this:
void foo(int* a)
… and then when you call the function your array's name decays to the pointer, matching the rewritten/"real" argument type.
So you're not really passing an array at all.
When is this method of passing array useful?
Never.
This is a shameful oddity inherited from C. One might argue that the [4] is a useful hint to the developer that the pointed-to array "should" have four elements, but modern wisdom is that this is just unnecessarily and dangerously misleading.
Better alternatives include:
Pointer/size pair (two arguments): this is not less dangerous per se, but at least it does not lie about the type and lull you into a false sense of security!
Array by reference: lovely jubbly, but less flexible
std::array<int, 4> (by reference): as above, but neater
Either make f() more restrictive as shown by #songyuanyao or consider using a C++ std::array instead:
#include <iostream>
#include <array>
// make an alias for the array you'd like to accept
using myarray_t = std::array<int, 4>;
// accept the array by reference
void f(myarray_t& a) {
// use a range based for loop to access elements by reference
for(int& a_i : a) a_i += 10;
}
int main() {
// declare your array
myarray_t a;
for(size_t i = 0; i < a.size(); ++i) a[i] = static_cast<int>(i);
f(a);
// and you can use a range based for loop to extract by value too
for(int a__i : a)
std::cout << a_i << " ";
std::cout << "\n";
return 0;
}
If you want to impose restrictions on the size of the array passed in, you can change to pass-by-reference.
void f(int (&a)[4]){
for(int i = 0;i < 3;i++){
a[i] += 10;
}
}
void f(int a[4]) is same as void f(int* a); that means you can pass the array with any size which will decay to pointer (i.e. int*) when being passed.

Converting a vector to an array - Is there a 'standard' way to do this?

I know you can just do: &theVector[0], but is this standard? Is this behavior always guaranteed?
If not, is there a better, less 'hackish' way to do this?
Yes, that behavior is guaranteed. Although I can't quote it, the standard guarantees that vector elements are stored consecutively in memory to allow this.
There is one exception though:
It will not work for vector<bool> because of a template specialization.
http://en.wikipedia.org/wiki/Sequence_container_%28C%2B%2B%29#Specialization_for_bool
This specialization attempts to save memory by packing bools together in a bit-field. However, it breaks some semantics and as such, &theVector[0] on a vector<bool> will not work.
In any case, vector<bool> is widely considered to be a mistake so the alternative is to use std::deque<bool> instead.
C++11 provides the data() method on std::vector which returns a T*. This allows you to do:
#include <iostream>
#include <vector>
int main()
{
std::vector<int> vector = {1,2,3,4,5};
int* array = vector.data();
std::cout << array[4] << std::endl; //Prints '5'
}
However, doing this (or any of the methods mentioned above) can be dangerous as the pointer could become invalid if the vector is resized. This can be shown with:
#include <iostream>
#include <vector>
int main()
{
std::vector<int> vector = {1,2,3,4,5};
int* array = vector.data();
vector.resize(100); //This will reserve more memory and move the internal array
//This _may_ end up taking the place of the old array
std::vector<int> other = {6,7,8,9,10};
std::cout << array[4] << std::endl; //_May_ now print '10'
}
This could could crash or do just about anything so be careful using this.
We can do this using data() method. C++11 provides this method.
It returns a pointer to the first element in the vector. vector Even if it is empty, we can call this function itself without problems
vector<int>v;
int *arr = v.data();
A less 'hackish' way? Well you could simply copy :
#include <iostream>
#include <vector>
using namespace std;
int main()
{
vector<int> vect0r;
int array[100];
//Fill vector
for(int i = 0; i < 10 ; i++) vect0r.push_back( i ) ;
//Copy vector to array[ ]
for( i = 0; i < vect0r.size(); i++) array[i] = vect0r[i];
//Dispay array[ ]
for( i = 0; i < vect0r.size(); i++) cout<< array[i] <<" \n";
cout<<" \n";
return 0;
}
More here : How to convert vector to array in C++