Pass By Reference Multidimensional Array With Unknown Size - c++

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.

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;
}

pass address of arr[0][2] , that must be received in a double pointer

need a better approach to pass address arr[0][2], given that is has to be received in a double pointer.
want to pass arr[0][2] without storing in any other variable.
#include <iostream>
using namespace std;
int help(int **arr)
{
cout<<**arr;
}
int main()
{
{
int n=3,m=3,k=0;
int **arr = new int*[n];
for(int i = 0; i < n; i++) {
arr[i] = new int[m];
}
for(int i = 0; i < n; i++) {
for(int j = 0; j < m; j++) {
arr[i][j]=k;
k++;
}
}
int *g=*arr+2;
int **h=&g;
help(h);
}
}
There is no better way. Unfortunately C++ syntax x[y] can be used to mean two very different operations: if x is an array then is indexing, if x is a pointer they it's indirection and indexing.
If a caller expects a pointer to a pointer and you've a bidimensional matrix there's nothing you can do except actually creating the pointer that is not present in the matrix and pass its address.
The fact that with an array of pointers, with a pointer to a pointer and with a 2d array the syntax to reach an element is x[y][z] is irrelevant... they are three very different operations.
Why not just write
int *p = &arr[0][2];
help( &p );
If you want to get an access to the whole array using a pointer of the type int ** then you can use the following approach.
#include <iostream>
void help(int **arr, size_t n )
{
for ( size_t i = 0; i < n; i++ )
{
std::cout << ( *arr )[i] << ' ';
}
std::cout << '\n';
}
int main()
{
int arr[2][3]={{1,2,3},{4,5,6}};
int *p = reinterpret_cast<int *>( arr );
help( &p, 6 );
return 0;
}
The program output is
1 2 3 4 5 6

Is it possible for a function to owerwrite the input array with a smaller one?

The task: Create a function that takes a list of numbers as a parameter, and returns a list of numbers where every number in the list occurs only once
As far as I know, functions can't return arrays. But if a function's parameter is an array, it will be automatically a reference parameter, so it will "overwrite" the input array even if it's a void function. Is there any way to overwrite (as reference parameter) the input array with a smaller one?
To be specific: in the code below I would like to overwrite the number[10] array with the newArray[6]
I just started to learn code this week, this is a practice task for me, so I would like to use C++ basics to solve this one, without pointers and more complex stuff. If it's not possible, it's okay too.
#include <iostream>
#include <string>
void selectionSort(int[], int);
void unique(int[], int);
void print(int[], int);
int main(int argc, char *args[]) {
int numbers[] = {1, 11, 34, 11, 52, 61, 0, 1, 34, 1, 61, 72};
int size = sizeof(numbers) / sizeof(int);
unique(numbers, size);
return 0;
}
void unique(int arr[], int size) {
selectionSort(arr, size);
int newSize = 1;
for (int i = 0; i < size - 1; ++i) {
if (arr[i] < arr[i + 1]) {
newSize++;
}
}
int newArray[newSize];
int index = 0;
for (int i = 0; i < size - 1; ++i) {
if (arr[i] < arr[i + 1]) {
newArray[index] = arr[i];
++index;
}
}
newArray[newSize - 1] = arr[size - 1];
print(newArray, newSize);
}
void selectionSort(int arr[], int size) {
for (int i = 0; i < size; i++) {
int min = i;
for (int j = i; j < size; j++) {
if (arr[j] < arr[min]) {
min = j;
}
}
std::swap(arr[i], arr[min]);
}
}
void print(int arr[], int size) {
for (int i = 0; i < size; ++i) {
std::cout << arr[i] << " ";
}
std::cout << std::endl;
}
This is not valid C++:
int newArray[newSize];
That's VLA, which is C99, only available with gcc.
Instead, do:
int* newArray = new int[newSize];
Return this:
return std::make_pair(newArray, newSize);
As you need to return the size as well!! Even if you can overwrite the input array (you can, obviously, depends on your contract, the documentation of your function), you need to return the new size.
But you may want to take a real C++ class.

C++ parameterized constructor makes code to stop working when large input's are passed

void initialize(int arr[], int size[], int n)
{
int i;
for(i = 1; i <= n; i++) {
arr[i] = i;
size[i] = 1;
}
}
class hell
{
public:
int edges;
int vertices;
pair<int , pair<int,int>> p[100000];
int disjoint_set[10000];
int cc_size[10000]; // size of connected components
hell(int e, int v)
{
edges = e;
vertices = v;
initialize(disjoint_set, cc_size, vertices);
}
};
In the following class when I create an object using vertices=100000 and edges=100000, the code stops working. But when we remove the initialize(disjoint_set, cc_size, vertices) it starts working. I don't have any clue to such behavior. Please guide me.
Arrays in C++ are zero indexed, which means that valid index is in [0..n[ range. Your code does it wrong:
for(i = 1; i <= n; i++) {
arr[i] = i;
size[i] = 1;
}
it should be:
for(i = 0; i < n; i++) {
arr[i] = i + 1;
size[i] = 1 + 1;
}
or better use algo std::iota() and std::fill():
std::iota( arr, arr + n, 1 );
std::fill( size, size + n, 1 );
and you better use std::vector, which will adjust its size properly, rather than have huge array.

Porting code from C++ to C. How do I deal with this vector and range based loop

I am trying to port to C. Since there's no vectors in C, I used a normal array, but I don't know how I'm going to deal with the ranged based loop on line 18.
for (int u : d[i]) if (dfs(rev[u])) {
par[i] = u;
rev[u] = i;
return true;
}
Complete code:
#include <iostream>
#include <vector>
#include <string>
#include <sstream>
using namespace std;
const int Maxn = 200;
vector<int> d[Maxn];
int par[Maxn];
int rev[Maxn];
bool vs[Maxn];
bool dfs(int i) {
if (i < 0) return true;
if (vs[i]) return false;
vs[i] = true;
for (int u : d[i]) if (dfs(rev[u])) {
par[i] = u;
rev[u] = i;
return true;
}
return false;
}
int main() {
ios_base::sync_with_stdio(false);
int n;
cin >> n;
string s;
getline(cin, s);
for (int i = 0; i < n; i++) {
getline(cin, s);
stringstream ss(s);
vector<int> mk(n, 1);
mk[i] = 0;
int x;
while (ss >> x)
mk[x] = 0;
for (int x = 0; x < n; x++)
if (mk[x])
d[i].push_back(x);
}
memset(par, -1, sizeof par);
memset(rev, -1, sizeof rev);
for (bool ok = true; ok; ) {
ok = false;
memset(vs, 0, sizeof vs);
for (int i = 0; i < n; i++)
if (par[i] < 0) {
ok |= dfs(i);
}
}
int ans = 0;
for (int i = 0; i < n; i++)
ans += (par[i] < 0);
cout << ans;
}
In C there is no std::vector, the closes would be an array.
int array[] = [ 1, 3, 5, 7, 9 ];
for(int i = 0; i < sizeof array / sizeof *array; ++i)
printf("array[%d] = %d\n", i, array[i]);
If you get a pointer of an array of int, the you have to pass the length of
the array as well, as sizeof arr / sizeof *arr works with arrays only.
void foo(in *array, size_t len)
{
for(int i = 0; i < len; ++i)
printf("array[%d] = %d\n", i, array[i]);
}
void bar(void)
{
int array[] = [ 1, 3, 5, 7, 9 ];
foo(array, sizeof array / sizeof *array);
}
edit 2
I noticed that you've posted your code and that d is declared as vector<int> d[Maxn];. Also taking in consideration your recent comment
So this is an array of vectors. Do you have any idea how i can work with arrays taking that in consideration in C
There a couple of ways to convert the array of vectors in C. But this depends
on your needs. If for example you know that all vectors are going to have the
same size (for example int vectsize = 100), then you can create a two
dimensional array with the sizes1
int Maxn = 200;
int vectsize = 100;
int d[Maxn][vectsize];
memset(d, 0, sizeof d); // initialize all elements with 0
// filling the data
for(int i = 0; i < Maxn; ++i)
{
for(j = 0; j < vectsize; ++j)
d[i][j] = get_value_for(i, j);
}
The the range-loop is very easy:
// assuming that the variables i, par, rev are valid, i between 0 and Maxn-1
for(int j = 0; j < vectsize; ++j)
{
int u = d[i][j];
if (dfs(rev[u])) {
par[i] = u;
rev[u] = i;
return true;
}
}
It gets a little more complicated if you only know one dimension, for example
every vector in the array could have a different size.
d[0].size() --> 10
d[1].size() --> 1
d[2].size() --> 3
...
The you can create an array of pointers to int, but you would have to keep
another array of ints with the length for every d[i] vector.
int Maxn = 200;
int *d[Maxn]; // pointer to int[Maxn] arrays
int vectsize[Maxn];
// initializing with 0
memset(d, 0, sizeof d);
memset(vectsize, 0, sizeof vectsize);
// filling the data
for(int i = 0; i < Maxn; ++i)
{
vectsize[i] = get_length_for(i);
d[i] = malloc(vectsize[i] * sizeof *d[i]);
if(d[i] == NULL)
// error handling
for(j = 0; j < vectsize[i]; ++j)
d[i][j] = get_value_for(i, j);
}
Note that I'm using here (and in the last example) get_length_for() and get_value_for() as placeholders2.
Now your range-base loop would look like this:
// assuming that the variables i, par, rev are valid, i between 0 and Maxn-1
for(int j = 0; j < vectsize[i]; ++j)
{
int u = d[i][j];
if (dfs(rev[u])) {
par[i] = u;
rev[u] = i;
return true;
}
}
At some point however you would have to free the memory:
for(int i = 0; i < Maxn; ++i)
free(d[i]);
The third option would be using a double pointer and using malloc/realloc
to allocate the memory. This is the more general solution, but you have to
take care of memory management and that can be sometimes difficult, especially when you
haven't programmed in C to much. But also in case where both dimension are unknown, this is the way to go:
int Maxn = get_some_maxn_value();
int **d, *vectsize;
d = malloc(Maxn * sizeof *d);
if(d == NULL)
// error handling
vectsize = malloc(Maxn * sizeof *vectsize);
if(vectsize == NULL)
// error handling,
// if you exit the function, don't forget
// to do free(d) first as part of the
// error handling
// initialize all elements with 0
memset(d, 0, Maxn * sizeof *d);
memset(vectsize, 0, Maxn * sizeof *vectsize);
// filling the data (the same as above)
for(int i = 0; i < Maxn; ++i)
{
vectsize[i] = get_length_for(i);
d[i] = malloc(vectsize[i] * sizeof *d[i]);
if(d[i] == NULL)
// error handling
for(j = 0; j < vectsize[i]; ++j)
d[i][j] = get_value_for(i, j);
}
In this case the range-loop would look exactly as for the array of pointers.
Freeing the memory is a little bit different though:
for(int i = 0; i < Maxn; ++i)
free(d[i]);
free(d);
free(vectsize);
Like I said earlier, which one of these three methods to use depends on the way
the original C++ code fills the values, how long the vectors are, etc. Judging
form the C++ code you posted, you read an integer from the user and store it
in n. Then you read more values from the user and push then in the vector
d[i] for all i between 0 and Maxn-1. It seems that all vectors have at
most length n, but because of
if (mk[x])
d[i].push_back(x);
they also could have less than n elements. That's why I think that the third
solution is preferable here.
Annotations
1Prior to C99, Variable Length Arrays (VLA) were not supported, so if you had the
dimension in a variable, you had to use malloc to allocate enough memory.
C99 supports VLAs, but I'm not quite sure how well supported they are and/or
whether your compiler supports them.
I personally don't use them in my code at all, that's why I really don't know. I compiled this examples with GNU
GCC 6.4.0 (on linux) and they worked fine.
The first two options use VLAs, if your compiler doesn't support that, then
you have to use the third option.
For more information about VLAs:
malloced array VS. variable-length-array
What's the difference between a VLA and dynamic memory allocation via malloc?
Variable length array
GCC manual: 6.19 Arrays of Variable Length (in case you ise GCC)
2How you really get this values depends on the original C++ code.
So far I've only looked very briefly over your C++ code. Using the values from
my example get_length_for(0) would return 10, get_length_for(1) would return 1,
get_length_for(2) would return 3, etc.
Assuming d[i] is a vector, this is a similar loop:
for (size_t s = 0; s < d[i].size(); s++)
{
int u = d[i][s];
if (dfs(rev[u]))
{
par[i] = u;
rev[u] = i;
return true;
}
}