Passing custom size multidimensional array to function - c++

I have array with known x size (5) and the y is taken from variable, so the array is something like this - array[5][y];
And now I'm quite troubled how to pass it to function, I won't edit it, just read the data from it.
I thought to do something like this:
void someFunction(double **array)
but I get
convert error: cannot convert `double (*)[((unsigned int)((int)n))]' to `double**' for argument `2' to `void findMax(int, double**, int)'|

For Array [5][x]
Unfortunately you cannot define a type for an array like double[5][]. You can only omit the first dimension of a multidimensional array, not the last.
For Array [x][5]
You should go with void someFunction(double array[][5], int size).
And then you loop trough the elements with for (int i = 0; i < size; i++).
Example:
void someFunction(double array[][5], int size) {
for (int k = 0; i < size; i++)
for (int i = 0; i < 5; i++)
std::cout << array[k][i] << std::endl;
}
double a[10][5];
// populate data
someFunction(a, 10);
Usually it's preferred to use std:: containers instead of raw C arrays.
Take a look at std::vector for example.

If you are not using the STL, you can also do this:
void someFunction(double **mat, const int Xsize, const int Ysize )
{
for(unsigned int i = 0 ; i < Xsize ; ++i)
{
for(unsigned int j = 0 ; j < Ysize ; ++j)
{
std::cout << ((double *)mat + Ysize * i)[j] << " " ;
}
std::cout << std::endl;
}
return ;
}
And call the function like this:
int main(int argc, char** argv)
{
double matrice[2][3] = {{1,2,3},{4,5,6}};
someFunction( (double**)matrice, 2, 3 );
return 1;
}

Related

C++ syntax difference: 2D- and 1D-arrays (pointer arithmetic)

Problem
I am learning C++, and am writing code to transpose a 2D array and to reverse a 1D-array.
Please look at the invocations. Why do I have to use reverse(arr, 4) for reverse, whereas I have to use transpose(*in_matrix, *out_matrix) for transpose?
There are two ways of writing each function signature. Both seem to give the same results.
Thank you.
EDIT: I know how to solve it with array-subscript. I am doing it this way deliberately for practice. Now I understand there's no point trying this. However, I have added some notes summarised from the answers below.
Code
#include <iostream>
using namespace std;
const int LENGTH = 2;
const int WIDTH = 3;
void printArray(const int arr[], const int N) {
cout << arr[0];
for (int i = 1; i < N; ++i) {
cout << ", " << arr[i];
}
cout << "\n";
}
// void transpose(int* const input, int* const output) { // both these signatures
void transpose(const int input[], int output[]) { // works (I find the top one clearer)
for (int i = 0; i < WIDTH; ++i) {
for (int j = 0; j < LENGTH; ++j) {
*(output + j * WIDTH + i) = *(input + i * LENGTH + j);
}
}
}
// void reverse(int arr[], const int N) { // both these signatures
void reverse(int* arr, const int N) { // works (I prefer this one)
for (int i = 0; i < N / 2; ++i) {
int temp = *(arr + i);
*(arr + i) = *(arr + N - 1 - i);
*(arr + N - 1 - i) = temp;
}
}
int main() {
int arr[4] = {2,4,6,8};
printArray(arr, 4);
reverse(arr, 4); // this works
// reverse(*arr, 4); // this doesn't work
printArray(arr, 4);
int in_matrix[WIDTH][LENGTH];
in_matrix[0][0] = 1;
in_matrix[0][1] = 2;
in_matrix[1][0] = 3;
in_matrix[1][1] = 4;
in_matrix[2][0] = 5;
in_matrix[2][1] = 6;
int out_matrix[LENGTH][WIDTH];
// transpose(in_matrix, out_matrix); // this doesn't work
transpose(*in_matrix, *out_matrix); // this works
cout << "in_matrix is:\n";
for (int i = 0; i < WIDTH; ++i) {
printArray(in_matrix[i], LENGTH);
}
cout << "out_matrix is:\n";
for (int i = 0; i < LENGTH; ++i) {
printArray(out_matrix[i], WIDTH);
}
return 0;
}
Summary of answers
LESSON: DO NOT USE pointer-arithmetic for 2D-arrays
decay
KEY IDEA: arr -----> &arr[0] type int*
This is also the reason the two function signatures are equivalent.
// transpose(int* const input, int* const output) // alt.
Signature: transpose(const int input[], int output[])
i.e. it expects an array of ints (or equiv., a pointer to an int)
(id)
IDENTITY: a[i] = *(a + i) ALWAYS TRUE
Reason transpose(in_matrix, out_matrix) doesn't work:
decay
out_matrix -----> &out_matrix[0] type int(*)[WIDTH]
Reason transpose(*in_matrix, *out_matrix) works:
(id) decay
*out_matrix = out_matrix[0] -----> &(out_matrix[0])[0]
In C, arrays and pointers are a bit intricately mixed up. An array can be considered as a pointer with some 'size' information attached to it (that is not stored anywhere, but the compiler knows). Hence, sizeof when used on an array gives you the size of the contents of the entire array, while on a pointer, it gives the size of the pointer.
When you pass an array to a function, the size information is lost - in effect, the array decays to a pointer. For most practical purposes, a pointer to a type can be used exactly like a one-dimensional array of that type. The array subscript notation ([]) can also be used to access consecutive elements using a pointer.
However, with 2D arrays, this gets more complicated. 2D arrays and double pointers may use the same access syntax of the form a[i][j] but they are not interchangeable. A 2D array decays to a pointer to an array while a double pointer is a pointer to a pointer.
Coming back to your question, the two ways of writing the function signatures are essentially equivalent because 1D arrays decay to pointers when passed to functions. So void reverse(int* arr, const int N) is the same as void reverse(int arr[], const int N).
In your transpose function however, you are passing a 2D array. It would decay to a pointer to an array. But in your function declaration, you are accepting these arguments as arrays (or in effect, pointers). This still works fine because of the quirks of C. A 2D array can be also treated as one big 1D array with the rows laid out consecutively one after the other. It is, however, not the best approach. This also reflects in the fact that you had to de-reference the array names when you passed them to the transpose function, because it expects a 1D array (or a pointer) and not a 2D array (or a pointer to an array).
Also, C/C++ provides a much more elegant way to access arrays than using unwieldy pointer arithmetic. So the following approach is what I would recommend. It should work exactly like the code you originally posted, but would be cleaner and more readable.
#include <iostream>
using namespace std;
const int LENGTH = 2;
const int WIDTH = 3;
void printArray(const int arr[], const int N) {
cout << arr[0];
for (int i = 1; i < N; ++i) {
cout << ", " << arr[i];
}
cout << "\n";
}
void transpose(const int input[][LENGTH], int output[][WIDTH]) {
for (int i = 0; i < WIDTH; ++i) {
for (int j = 0; j < LENGTH; ++j) {
output[j][i] = input[i][j];
}
}
}
void reverse(int* arr, const int N) {
for (int i = 0; i < N / 2; ++i) {
int temp = arr[i];
arr[i] = arr[N - 1 - i];
arr[N - 1 - i] = temp;
}
}
int main() {
int arr[4] = {2,4,6,8};
printArray(arr, 4);
reverse(arr, 4);
printArray(arr, 4);
int in_matrix[WIDTH][LENGTH];
in_matrix[0][0] = 1;
in_matrix[0][1] = 2;
in_matrix[1][0] = 3;
in_matrix[1][1] = 4;
in_matrix[2][0] = 5;
in_matrix[2][1] = 6;
int out_matrix[LENGTH][WIDTH];
transpose(in_matrix, out_matrix);
cout << "in_matrix is:\n";
for (int i = 0; i < WIDTH; ++i) {
printArray(in_matrix[i], LENGTH);
}
cout << "out_matrix is:\n";
for (int i = 0; i < LENGTH; ++i) {
printArray(out_matrix[i], WIDTH);
}
return 0;
}

Cannot pass 2d array into a helper function in c++

I was learning c++ and implementing the game of life when I created a helper function to print the current board which is a 2d array. I cannot seem to pass the array into the function as I get an error, "Candidate function not viable: no known conversion from 'char [rows][cols]' to 'char (*)[cols]' for 3rd argument." I am using Xcode as an ide if that helps.
void printArray(int rows, int cols, char board[rows][cols]){
for(int r = 0; r < rows; r++){
for(int c = 0; c < cols; c++){
cout << board[r][c];
cout << " ";
}
cout << "\n";
}
}
int main(){
char board[5][5];
for(int r = 0; r < 5; r++){
for(int c = 0; c < 5; c++){
board[r][c] = 0;
}
}
printArray(5, 5, board);
return 0;
}
I've tried switching up the parameter to different things such as char **board, char board[][cols], char (*board)[cols]. Even casting my input board which leads to other errors.
If you want to pass 2d arrays to a function there is a special syntax. Unfortunately, the other previous 2 answers do not answer fully correctly.
You can pass by reference or by pointer. The array dimensions must be compile time constants. That is a requirement from C++.
Please see:
constexpr size_t NumberOfRows = 3;
constexpr size_t NumberOfColumns = 4;
// Typedef for easier usage
using IntMatrix2d = int[NumberOfRows][NumberOfColumns];
//Solution 1 ------
// Pass by reference
void function1(int(&matrix)[NumberOfRows][NumberOfColumns]) {}
// Pass by pointer
void function2(int(*m)[NumberOfRows][NumberOfColumns]) {}
//Solution 2 ------
// Pass by reference
void function3(IntMatrix2d& matrix) {}
// Pass by pointer
void function4(IntMatrix2d* matrix) {}
int main()
{
// Solution 1
// Handwritten matrix. Dimension is compile time constant
int matrix1[NumberOfRows][NumberOfColumns];
// Pass by reference
function1(matrix1);
// Pass by pointer
function2(&matrix1);
// Solution 2 -----
IntMatrix2d matrix2;
// Pass by reference
function3(matrix2);
// Pass by pointer
function4(&matrix2);
return 0;
}
If you typedef or use using for your type definition, then it gets rather intuitive.
If you are not very comfortable with pointers then there are some easy ways to do the task
1. You have to define the 2d array size by default, before passing array to the function so that the size doesn't seem to be unknown to the function.
#include <iostream>
const std::size_t rows=5;
const std::size_t cols=5;
void printArray(char board[rows][cols]) {
for (int r = 0; r < rows; r++) {
for (int c = 0; c < cols; c++) {
std::cout << board[r][c];
std::cout << " ";
}
std::cout << "\n";
}
}
int main() {
char board[rows][cols];
for (int r = 0; r < rows; r++) {
for (int c = 0; c < cols; c++) {
board[r][c] = '0';
}
}
printArray(board);
return 0;
}
2. Use vector. Make your board a vector.
#include <iostream>
#include <vector>
void printArray(std::vector<std::vector<char>> &board) {
for (int r = 0; r < board.size(); r++) {
for (int c = 0; c < board[0].size(); c++) {
std::cout << board[r][c];
std::cout << " ";
}
std::cout << "\n";
}
}
int main() {
std::vector<std::vector<char>> board(rows, std::vector<char>(cols, '0'));
printArray(board);
}
I encountered this problem while doing a project for a class. To work around it, I made a double pointer array, and then used passed it to the function to manipulate it.
int** createArr(){
int** pixels = 0;
pixels = new int*[numrows];
for (int row = 0; row < numrows; row++){
pixels[row] = new int[numcols];
for (int col = 0; col < numcols; col++){
ss >> pixels[row][col];
}
}
return pixels;
}
int** newArr = createArr(); //calls function to create array
func(newArr); //where func is a function that modifies the array.
Don't forget to delete your arrays at the end to avoid memory leaks. Hope this helps.

Retrieve index of element of array stored in vector

I have a 2D array used to store non-repeated values and some entries are randomly picked and push_back-ed into a vector as favorite list.
int num[10][10];
vector<int> fav_list;
int retrieved_i, retrieved_j, retrieve_vector_position;
for(i=0;i<10;i++) for(j=0;j<10;j++)
// ...assign numbers to num...
fav_list.push_back(num[2][3]);
fav_list.push_back(num[4][7]);
fav_list.push_back(num[6][2]);
//...push_back more random selected num[...][...] into fav_list...
The problem is, how can I retrieve the i, j index of particular fav_list[...]?
I've tried to make struct struct Num{int value, index_i, index_j;}num[10][10]; so that I can do in this way
retrieved_i = fav_list[retrieve_vector_position].index_i;
retrieved_j = fav_list[retrieve_vector_position].index_j;
but I wish to know is there any other better/ efficient ways?
Using a plain vector to store your 2D array would solve the problem. You could access elements in the vector by calculating absolute index (i * row_len + j) and store in fav_list absolute indices.
Also, you may want to use std::unordered_map for fav_list. Generally, hash tables is the most efficient data structure for such caches.
There are a few possibilities depending on how often you want to access the i & j indices / the favorite number itself.
One approach is, to save the indices instead of the number (or additional to it). With this approach, more memory is required but the the time to access the indices will be constant, regardless how big your array becomes. This uses std::pair to store 2 elements in your favorite vector.
#include <vector>
#include <iostream>
#include <utility>
using namespace std;
int main(int argc, char* argv[]) {
int num[10][10];
vector<std::pair<int, int>> fav_list;
for (int i = 0; i < 10; i++) {
for (int j = 0; j < 10; j++) {
if (/* your condition for favorites */) {
fav_list.push_back(num[i][j]);
}
}
}
/* example get the indices of the first favorite */
cout << "i: " << fav_list[0].first << "j: " << fav_list[0].second << endl;
/* example get the first favorite */
cout << num[fav_list[0].first][fav_list[0].second] << endl;
return 0;
}
Another approach is to "lookup" the indices, when you require it: it has the condition, that one number is not multiple times contained in your num[][] array (otherwise the first entry is found). There is no additional memory overhead required, but the time to lookup the indices will increase when your array gets bigger.
#include <vector>
#include <iostream>
using namespace std;
int main(int argc, char* argv[]) {
int num[10][10];
vector<int> fav_list;
for (int i = 0; i < 10; i++) {
for (int j = 0; j < 10; j++) {
if (/* your condition for favorites */) {
fav_list.push_back(num[i][j]);
}
}
}
/* example get the indices of the first favorite */
int indexI = -1, indexJ = -1;
for (int i = 0; i < 10; i++) {
for (int j = 0; j < 10; j++) {
if (fav_list[0] == num[i][j]) {
indexI = i;
indexJ = j;
break;
}
}
}
cout << "i: " << indexI << "j: " << indexJ << endl;
/* example get the first favorite */
cout << fav_list[0] << endl;
return 0;
}
Instead of storing 3 variable value, x and y just store a single unsigned int via which you can retrieve x and y.
struct fav_list
{
unsigned int total_rows;
unsigned int total_columns;
fav_list(unsigned int _rows, unsigned int _columns)
{
total_rows = _rows;
total_columns = _columns;
}
unsigned int get_x(unsigned int _index)
{
return v[_index] / total_columns;
}
unsigned int get_y(unsigned int _index)
{
return v[_index] % total_columns;
}
void append_xy_to_list(unsigned int _x, unsigned int _y)
{
v.push_back(_x * total_columns + _y);
}
vector <unsigned int> v;
};
fav_list f(10, 10);
for(x = 0; x < 10; ++x)
{
for(y = 0; y < 10; ++y)
{
//suppose you want to store the indexes of element num[x][y] then:
f.append_xy_to_list(x, y);
}
}
retrieved_i = f.get_x(retrieve_vector_position);
retrieved_j = f.get_y(retrieve_vector_position);

C++: Pass two-dimensional array to function

This is probably so simple, but I can't figure out why this won't compile.
void display(int);
const int rows = 2;
const int cols = 2;
int main()
{
int ray[rows][cols] = {{1,2 },
{3,4}};
display(ray);
return 0;
}
void display(const int ray[][cols]){
for(int i = 0; i < 2; i ++){
for(int j = 0; j < 2; j ++){
cout << ray[i][j] << endl;
}
}
}
invalid conversion from ‘int (*)[2]’ to ‘int’ [-fpermissive]|
This code will work
const int rows = 2;
const int cols = 2;
void display( const int ray[][cols]);
int main()
{
int ray[rows][cols] = {{1,2 },
{3,4}};
display(ray);
return 0;
}
void display( const int ray[][cols]){
for(int i = 0; i < 2; i ++){
for(int j = 0; j < 2; j ++){
cout << ray[i][j] << endl;
}
}
}
Your function definition and function declaration do not match, one of them is of type int while the other is type void
Your function declaration is
void display(int);
and the definition is
int display(const int ray[0][cols])
and
int display(const int ray[0][cols])
^
0 ?
I think I see the problem here
The prototype is wrong. If you want a 2D array arg, it's more like this
int display(const int ray**);
The forward declaration of display is wrong. Either fix forward declaration or change order of functions:
#include <iostream>
using namespace std;
const int rows = 2;
const int cols = 2;
int display(const int ray[0][cols]){
for(int i = 0; i < 2; i ++){
for(int j = 0; j < 2; j ++){
cout << ray[i][j] << endl;
}
}
}
int main()
{
int ray[rows][cols] = {{1,2 },
{3,4}};
display(ray);
return 0;
}
Live Example
Since you use global variables anyway, the easy thing is to change your declaration of display:
Declare display like this:
void display(int** array)
{...}
In this case you will actually be able to send your 2D array to the function because the type will match. A 2D array is an array of arrays and an array is just a pointer associated with some memory.
I am not giving the appropriate answer to this question. But an alternative.
As C++ suggests to use std::string inplace of char* . It also suggests to use vectors instead of array wherever applicable.
#include <iostream>
#include <vector>
void display( std::vector<std::vector<int>> );
int main()
{
std::vector<std::vector<int>> int_vec{ { 1 , 2 } , { 3 , 4 } };
display( int_vec );
system("PAUSE");
return EXIT_SUCCESS;
}
void display( std::vector<std::vector<int>> integer_vector )
{
for( auto& i : integer_vector )
{
for( auto& j : i )
{
std::cout << j << std::endl;
}
}
}
The global variables as rows and cols are gone :).

Pass By Reference Multidimensional Array With Unknown Size

How to pass by reference multidimensional array with unknown size in C or C++?
EDIT:
For example, in main function I have:
int main(){
int x, y;
int arr[x][y];
// pass_by_ref(/* passing just arr[][] by reference */);
}
and the function:
void pass_by_ref(/* proper parameter for arr[][] */){
// int size_x_Arr = ???
// int size_y_arr = ???
}
How to implement the commented line?
Simply put, you can't. In C, you can't pass by reference, since C has no references. In C++, you can't pass arrays with unknown size, since C++ doesn't support variable-lenght arrays.
Alternative solutions: in C99, pass a pointer to the variable-length array; in C++, pass a reference to std::vector<std::vector<T>>.
Demonstration for C99:
#include <stdio.h>
void foo(int n, int k, int (*arr)[n][k])
{
int i, j;
for (i = 0; i < n; i++) {
for (j = 0; j < k; j++) {
printf("%3d ", (*arr)[i][j]);
}
printf("\n");
}
}
int main(int argc, char *argv[])
{
int a = strtol(argv[1], NULL, 10);
int b = strtol(argv[2], NULL, 10);
int arr[a][b];
int i, j;
for (i = 0; i < a; i++) {
for (j = 0; j < b; j++) {
arr[i][j] = i * j;
}
}
foo(a, b, &arr);
return 0;
}
Demonstration for C++03:
#include <iostream>
#include <vector>
#include <cstdlib>
#include <ctime>
void foo(std::vector < std::vector < int > > &vec)
{
for (std::vector < std::vector < int > >::iterator i = vec.begin(); i != vec.end(); i++) {
for (std::vector<int>::iterator j = i->begin(); j != i->end(); j++) {
std::cout << *j << " ";
}
std::cout << std::endl;
}
}
int main(int argc, char *argv[])
{
int i = strtol(argv[1], NULL, 10);
int j = strtol(argv[2], NULL, 10);
srand(time(NULL));
std::vector < std::vector < int > > vec;
vec.resize(i);
for (std::vector < std::vector < int > >::iterator it = vec.begin(); it != vec.end(); it++) {
it->resize(j);
for (std::vector<int>::iterator jt = it->begin(); jt != it->end(); jt++) {
*jt = random() % 10;
}
}
foo(vec);
return 0;
}
H2CO3's solution will work for C99 or a C2011 compiler that supports VLAs. For C89 or a C2011 compiler that doesn't support VLAs, or (God forbid) a K&R C compiler, you'd have to do something else.
Assuming you're passing a contiguously allocated array, you can pass a pointer to the first element (&a[0][0]) along with the dimension sizes, and then treat it as a 1-D array, mapping indices like so:
void foo( int *a, size_t rows, size_t cols )
{
size_t i, j;
for (i = 0; i < rows; i++)
{
for (j = 0; j < cols; j++)
{
a[i * rows + j] = some_value();
}
}
}
int main( void )
{
int arr[10][20];
foo( &arr[0][0], 10, 20 );
...
return 0;
}
This will work for arrays allocated on the stack:
T a[M][N];
and for dynamically allocated arrays of the form:
T (*ap)[N] = malloc( M * sizeof *ap );
since both will have contiguously allocated rows. This will not work (or at least, not be guaranteed to work) for dynamically allocated arrays of the form:
T **ap = malloc( M * sizeof *ap );
if (ap)
{
size_t i;
for (i = 0; i < M; i++)
{
ap[i] = malloc( N * sizeof *ap[i] );
}
}
since it's not guaranteed that all the rows will be allocated contiguously to each other.
This is a sort of comment to the good answer of #John Bode
This will not work (or at least, not be guaranteed to work) for
dynamically allocated arrays of the form:
But this variant will:
T **ap = malloc( M * sizeof *ap );
if (ap) return NULL; ---> some error atention
if (ap)
{
ap[0] = malloc( M * N * sizeof *ap[i] );
if (ap[0]) { free(ap); return NULL;} ---> some error atention
size_t i;
for (i = 1; i < M; i++)
{
ap[i] = ap[0] + i * N;
}
}
After use :
free(ap[0]);
free(ap);
for T being int you call foo exactly als for the array int ap[M][N];
foo( &ap[0][0], M, N);
since you guaranteed that all the rows are allocated contiguously to each other.
This allocation is a litter more efficient.
John Bode's explanation is very good, but there is a little mistake:
it should be
i * cols + j
instead of
i * rows + j
If you really want references, then it's only in C++.
En example of a two-dimensional int array passed by reference
void function_taking_an_array(int**& multi_dim_array);
But the reference doesn't have any advantage, so simply use :
void function_taking_an_array(int** multi_dim_array);
I would advice you to use a container to hold your array.