C++ generalize two dimension array in function - c++

I want to write a function in C++ that take a matrix of any size and print it.
my code is as follows and it works. But my questions:
1) Is it the best practice?
2) Why casting using (int *) works but static_cast<int *> does not?
Thanks
#include <iostream>
using namespace std;
void print_matrix(int *, int, int);
int main()
{
int mat[3][3] = {{1, 2, 3},
{4, 5, 6},
{7, 8, 9}
};
int mat2[5][5] = {{1, 2, 3, 40, 50},
{4, 5, 6, 70, 80},
{7, 8, 9, 10, 20},
{17, 18, 19, 10, 20},
{71, 81, 91, 110, 120}
};
print_matrix((int *)mat2, 5, 5);
cout << endl;
print_matrix((int *)(mat), 3, 3);
cout << endl;
// static cast does not work:
// error: invalid static_cast from type 'int [3][3]' to type 'int*'|
// print_matrix(static_cast<int *>(mat), 3, 3);
return 0;
}
void print_matrix(int *matPtr, int row, int col)
{
for(int i = 0; i < row; i++) {
for(int j = 0; j < col; j++)
cout << *(matPtr + col * i + j) << '\t';
cout << endl;
}
}

Is it the best practice?
No, it is not.
It will be better to use a function template.
template <size_t NR, size_t NC>
void print_matrix(int (&matrix)[NR][NC])
{
...
}
and call it as:
print_matrix(mat2); // NR and NC are deduced by the compiler
Why casting using (int *) works but static_cast<int *> does not?
Given
int mat[3][3] = { ... };
the following pointers have the same numerical value even though the pointers are of different types.
int (*p1)[3][3] = &mat;
int (*p2)[3] = &mat[0];
int *p3 = &mat[0][0];
Because of this coincidence, use of (int*) works.
Using static_cast<int*> does not work because when a 2D array decays to a pointer, it does not decay to int* -- mat decays to int (*)[3] (pointer to an "array of 3 ints") and mat2 decays to int (*)[5] (pointer to an "array of 5 ints"). They cannot be cast to int* in general.

Related

Convert 'array of pointers to arrays' to 'array of pointers to the first elements'

I have an array of pointers to arrays:
int a1[6] = { 3, 7, 2, 4, 9, 8 };
int a2[6] = { 4, 8, 3, 0, 3, 5 };
int a3[6] = { 1, 7, 2, 3, 9, 2 };
int (*a[3])[6] = { &a1, &a2, &a3 };
and the following function that expects "a pointer to the first element of an array[3] of pointers pointing to the first elements of array[6]s":
void foo(int **pp) {
for (std::size_t i = 0; i < 3; ++i) {
for (std::size_t j = 0; j < 6; ++j) {
std::cout << pp[i][j] << ", ";
}
std::cout << "\n";
}
}
This works:
int *b[3] = { a1, a2, a3 };
foo(b);
But I can't find a way to pass a to foo.
To me, it seems quite natural for "array of pointers to arrays" to be converted to "array of pointers to the first element of the individual arrays". Just as an array can be converted to a pointer to its first element.
To support this argument, foo(reinterpret_cast<int **>(a)) prints the same output as foo(b) in my environment.
Is it possible to convert int (*[3])[6] to int *[3] using only static_casts?
If not, is foo(reinterpret_cast<int **>(a)) well defined by the standard?

Using arithmetic with arrays

Two quantities u and v are said to be at right angles if
nuv = u1v1 + u2v2 + u3v3 + u4v4 +………… + unvn = 0
Write a function that computes whether u and v are at right angles. You may use arrays if you wish. The function can assume that the vectors have the same dimension (n, say), but this number should be passed as a parameter to the function.
I have a few errors in my program. I'd appreciate some help, as I'm a beginner. The errors are telling me:
In function 'void function(int*,int*)'
cpp 26: error expected ';' before '}' token
cpp 29: error ;value required as left operand of assignment
#include <iostream>
using namespace std;
const int n = 5;
void function(int array[n],int array2[n]);
int main(){
int array[n] = {5, 3 , -4, 2, 8};
int array2[n] ={-7, -9, 5, 2, 9};
function(array, array2);
return 0;
}
void function(int array[n], int array2[n]){
int multiple;
for(int i=0; i <=5, i++)
{
(array[i]*array2[i]) + (array[i+1]*array2[i+1]) = multiple;
}
cout << multiple << endl;
}
Your for loop is malformed. You need to use < instead of <=, use n instead of 5, and use ; instead of ,.
Your assignment of multiple is backwards. The value on the right-side of the = operator is assigned to the variable on the left-side of =. You are trying to assign the value of multiple (which is uninitialized) to a dynamically computed value that has no explicit variable of its own. You should be assigning the computed value to multiple instead.
Also, you didn't follow the "this number [array dimensions] should be passed as a parameter to the function" requirement of your instructions.
Try this:
#include <iostream>
using namespace std;
const int n = 5;
void function(const int *array1, const int *array2, const int size);
int main()
{
int array1[n] = { 5, 3, -4, 2, 8};
int array2[n] = {-7, -9, 5, 2, 9};
function(array1, array2, n);
return 0;
}
void function(const int *array1, const int *array2, const int size)
{
int multiple = 0;
for(int i = 0; i < size; i++)
{
multiple += (array1[i] * array2[i]);
}
cout << multiple << endl;
}
Syntax error is where you are using the for loop in this fashion:
for(int i=0;i<=5,i++)
Use this instead:
for(int i=0; i <= 5; i++)
The function can assume that the vectors have the same dimension (n,
say), but this number should be passed as a parameter to the
function.
This function declaration
void function(int array[n],int array2[n]);
does not include a parameter that specifies the dimension of the arrays.
The above declaration is equivalent to
void function(int *array,int *array2);
because arrays passed by value are implicitly converted to pointers to their first elements.
There are a typo and a bug in this for statement
for(int i=0; i <=5, i++)
^^^^^^
There shall be
for ( int i=0; i < n; i++)
The variable multiple
int multiple;
is not initialized and this assignment
(array[i]*array2[i]) + (array[i+1]*array2[i+1]) = multiple;
does not have sense and has nothing common with the condition
nuv = u1v1 + u2v2 + u3v3 + u4v4 +………… + unvn = 0
It seems what you mean is the following
#include <iostream>
bool function( const int array[], const int array2[], size_t n )
{
long long int product = 0;
for ( size_t i = 0; i < n; i++)
{
product += array[i] * array2[i];
}
return product == 0;
}
int main()
{
const size_t N = 5;
int array[N] = { 5, 3 , -4, 2, 8 };
int array2[N] = { -7, -9, 5, 2, 9 };
std::cout << "array and array2 are "
<< (function(array, array2, N) ? "" : "not ")
<< "at right angles"
<< std::endl;
return 0;
}
These arrays
int array[N] = { 5, 3 , -4, 2, 8 };
int array2[N] = { -7, -9, 5, 2, 9 };
are not a right angles,
But these arrays
int array[N] = { 5, 3 , -4, 1, 9 };
int array2[N] = { -7, -9, 5, 1, 9 };
are at right angles. Try them.
Alternative: try the C++ way. Use std::array that knows it's length. Use algorithms provided by the standard library like std::inner_product.
#include <iostream>
#include <algorithm>
#include <array>
#include <numeric>
int main()
{
using arr_t = std::array<int,5>;
arr_t arr1 = {5, 3 , -4, 2, 8};
arr_t arr2 = {-7, -9, 5, 2, 9};
int mult = std::inner_product( begin(arr1), end(arr1), begin(arr2), 0,
std::plus<>(), std::multiplies<>() );
std::cerr << mult << "\n";
}

Can't convert std::array to int?

I am just learning c++ and am attempting to understand arrays.. So forgive my ignorance on what's wrong here.
#include <iostream>
#include <string>
#include <array>
using namespace std;
void readArray(int *readfile, int ArraySize){
int Interator;
for(Interator = 1; Interator < ArraySize; Interator++){
cout << " " << readfile[Interator];
}
}
int main(){
std::array<int, 5> array2={{1, 2, 3, 4, 5}};
readArray(array2, array2.end());
}
Error: Can't Convert 'std::array' to 'int*' for arg '1'to void 'readArray'
How would I fix this?
You cannot convert std::array to int* as compiler says. For such conversion you can use plain old array:
void readArray(int *readfile, int ArraySize)
{
int Interator;
for(Interator = 0; Interator < ArraySize; Interator++)
{
cout << " " << readfile[Interator];
}
}
int main()
{
//std::array<int, 5> array2={{1, 2, 3, 4, 5}};
int array2[] = {1, 2, 3, 4, 5};
readArray(array2, 5);
}
Also, Interator is changed to start from zero. If you need std::array then use std::array::begin() and std::array::begin():
void readArray2(const std::array<int, 5>& a)
{
for (auto elem : a)
cout << " " << elem;
}
int main()
{
std::array<int, 5> array2={{1, 2, 3, 4, 5}};
//int array2[] = {1, 2, 3, 4, 5};
readArray2(array2);
}
Just browse some reference to discover that std::array has a T* data() and a constexpr size_type size() which can and should be used for that purpose.
But this is a poor solution. The best solution would be to use iterators directly, eg:
template <typename T> void readArray(const T& data) {
for (const auto& element : data)
cout << element;
}
std::array<int, 5> data1 = { 1, 2, 3, 4, 5};
readArray(data1);
std::vector<int> data2 = {1, 2, 3, 4, 5};
readArray(data2);
std::list<int> data3 = {1, 2, 3, 4, 5};
readArray(data3);
Which would expect T to be a type that has proper begin and end() overloads.
It makes no sense to tag questions with C++11 if you try to use C solutions,

Passing a reference to an offset position in an STL vector

I'm trying to convert some old C functions to C++. My original programme stores a matrix in a single array, and I just pass a pointer to the first element to a function so that I am working on the correct row, e.g.
double f1(int *a){
return a[0] + a[1];
}
int main(void){
int x[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
for(i = 0; i < 5; i++){
printf("%d\n", f1(&x[2 * i]));
}
I would like to be able to do something similar using the STL without copying. So my programme would look something like this
double f1(vector<int>& a){
return a[0] + a[1];
}
int main(void){
int x[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
vector<int> y(x, x + 10);
for(i = 0; i < 5; i++){
cout << f1(y) << endl; // This is clearly wrong
}
How would I do this? I could change my function to receive a reference to a vector::iterator I guess, but is there another way?
You could simply pass an iterator to the function. Random access iterators are very similar to pointers (in fact, pointers qualify as random access iterators.) For example,
#include <vector>
double f1(std::vector<int>::const_iterator a)
{
return a[0] + a[1];
}
#include <iostream>
int main()
{
vector<int> y{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
auto it = y.cbegin();
for(int i = 0; i < y.size()/2; ++i)
std::cout << f1(it + 2*i) <<std::endl;
}
Write array view. An array view is a pair of pointers with begin end size empty, operator[], front and back methods, and constructors from C arrays, std::array<T,N>&, std::vector<T,A>&, std::vector<non_const_T,A>const&, std::array<non_const_T,N>const&, std::initializer_list<non_const_T>, etc.
Oh, and T*,size_t and T*,T* ctors, which are great for slicing (use forwarding ctors: T*,size_t->T*,T*, and everything else to those 2).
It does not own its data, so all of its methods are const except operator=. (non-const methods would be methods that change the view range -- changing the elements is a const operation on a view).
Then
double f1(array_view<const int> a){
return a[0] + a[1];
}
You don't need to make so many changes:
double f1(int *a)
{
return a[0] + a[1];
}
int main(void)
{
vector<int> y = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
for (int i = 0; i < 5; i++) {
cout << f1(&y[2 * i]) << endl;
}
}

array copy reversal in c++

Is there a way to copy an array to another way in reverse order by using a while loop in c++??
I'm pretty sure I know how to do one with a for loop, but I'm curious if anyone knows of a way by using a while loop
Why not something like this?
#include <algorithm>
int src[] = {1, 2, 3, 4, 5};
int dst[5];
std::reverse_copy(src, src+5, dst);
int anArray = {1, 2, 3, 4, 5};
int reverseArray[5];
int count = 4;
int place = 0;
while(place < 5) {
reverseArray[place] = anArray[count];
count--;
place++;
}
As you said that you have done using for loop, you can follow following steps to convert it to while loop.
for(int i = sizeof(arr) - 1; i >= 0; i--)
{
// your logic
}
now convert it to,
int i = sizeof(arr);
for(; i >= 0; )
{
// your logic
i--;
}
simply replace for with while and remove ; within the braces.
int i = sizeof(arr);
while(i >= 0)
{
// your logic
i--;
}
You can use std::reverse for reversing the same array and std::reverse_copy for reversing to another output array as:
int main() {
int a[]= {1,2,3,4,5,6,7,8,9,10};
const int size = sizeof(a)/sizeof(int);
int b[size];
//copying reverse to another array
reverse_copy(a, a + size, b);
cout << "b = {";
copy(b, b + size, ostream_iterator<int>(cout, ", "));
cout << "}" << endl;
//reverse the same array
reverse(a, a + size);
cout << "a = {";
copy(a, a + size, ostream_iterator<int>(cout, ", "));
cout << "}" << endl;
return 0;
}
Output:
b = {10, 9, 8, 7, 6, 5, 4, 3, 2, 1, }
a = {10, 9, 8, 7, 6, 5, 4, 3, 2, 1, }
Demo : http://www.ideone.com/Fe5uj
There's been a few questions similar to this recently. I wonder if it is homework or an interview question somewhere. Here's one answer:
#define ELEMENT_COUNT(a) (sizeof((a))/sizeof((a)[0]))
int anArray[] = { 1, 2, 3, 4, 5 };
int reverseArray[ELEMENT_COUNT(anArray)];
int n = ELEMENT_COUNT(anArray);
int i = 0;
while(n--)
reverseArray[i++] = anArray[n];
I think it might be probing to see if you understand when expression like i++ and n-- are evaluated.