Passing Pointer To An Array Of Arrays Through Function - c++

There is a pointer-to-an-Array of Arrays i.e. NameList in the code. I want the contents of each of the Arrays in the Pointer(NameList) to get printed one by one. The below code is not able do the task. Pls. help.
int Data1[] = {10,10};
int Data2[] = {20,20};
int Data3[] = {30,30};
int *NameList[] = {Data1, Data2, Data3};
main()
{ Function(NameList); }
Function(int *ArrayPointer)
{
int i, j, index=0;
for (i=0; i < 3; i++)
{
for (j=0; j < 2; j++)
{
//It does not print the data
printf("\nName: %s", ArrayPointer[index++]);
}
index=0; //Counter reset to 0
ArrayPointer++; //Pointer is incremented by one to pick next array in the pointer
}
}
print("code sample");
Another note from the original poster of the question:
I have completed a pacman game in Turbo C. I was polishing some graphics routines so that it can be reused again easily. This is only a small sample created for the purpose of help and understanding the concept. All data in the code actually are char arrays for sprites. Now i simply want to call a function passing the pointer so that each arrays in the pointer are drawn to the screen. How can this code be modified to handle this? Im actually stuck up here.

Darn it litb, once again you beat me to the punch by mere minutes. (If only I didn't have kids who keep waking up...)
Ahh, what the hell. Perhaps this will still be useful to somebody.
Oh, and just to nail this thing down:
Arrays, such as int a[4] allocate memory space for their data.
Pointers, such as int * p allocate just enouch memory space for a pointer to another spot in memory.
That's why we can use sizeof on arrays and get the full memory footprint, but not on pointers.
Other than that little distinction, there really isn't a big difference between int[] and int*. (Consider how many folks declare *main(int argc, char **argv) vs main(int argc, char * argv[]).)
ATTENTION: All memory addresses here are fictional. I'm just making them up to illustrate a point.
Given:
int Data1[] = {10,11};
int Data2[] = {20,22};
int Data3[] = {30,33};
We now have 3 blocks of memory. Say:
0xffff0000-0xffff0003 with a value of (int)(10)
0xffff0004-0xffff0007 with a value of (int)(11)
0xffff0008-0xffff000b with a value of (int)(20)
0xffff000c-0xffff000f with a value of (int)(22)
0xffff0010-0xffff0013 with a value of (int)(30)
0xffff0014-0xffff0017 with a value of (int)(33)
Where:
Data1 == & Data1 [0] == 0xffff0000
Data2 == & Data2 [0] == 0xffff0008
Data3 == & Data3 [0] == 0xffff0010
NO, I'm not going to get into big-endian vs little-endian byte ordering here!
Yes, in this case, Data1[2] == Data2[0]. But you can't rely on your compiler laying things out in memory the same way I've laid them out here.
Next:
int *NameList[] = {Data1, Data2, Data3};
So we now have another block of memory. Say:
0xffff0018-0xffff001b with a value of (int*)(0xffff0000)
0xffff001c-0xffff001f with a value of (int*)(0xffff0008)
0xffff0020-0xffff0023 with a value of (int*)(0xffff0010)
Where:
NameList == & NameList [0] == 0xffff0018
Note that NameList is of int ** type, and NOT int* type!
We can then write:
void Function(int **ArrayPointer)
{
for ( int i=0; i < 3; i++ )
for ( int j=0; j < 2; j++)
printf("Name: %d\n", ArrayPointer[i][j] );
}
int main() { Function(NameList); }
ArrayPointer resolves to (int**)0xffff0018.
ArrayPointer[0] == *( (int**) 0xffff0018 ) == (int*)(0xffff0000) == Data1.
ArrayPointer[0][1] == *( ( * (int**) 0xffff0018 ) + 1 ) == (int) * ( (int*)0xffff0000 + 1 ) == (int) * (int*) 0xffff0004 == Data1[1].
You may want to review pointer arithmetic: array[N] == *( array + N )

main has to return a type. You forget to put "int" as a return type (implicit int in C++ is banned).
Having said that, i'm not sure what you mean by
// It does not print the data
printf("\nName: %s", ArrayPointer[index++]);
ArrayPointer[index++] would, as it is defined in the parameter list, return an int. How is that supposed to store a name ? It will store an integer!
Once again, that said, you can't call that Function (pun intended) with that particular argument. Let's view your types:
int Data1[] = {10,10};
int Data2[] = {20,20};
int Data3[] = {30,30};
int *NameList[] = {Data1, Data2, Data3};
Data1 Data2 Data3 NameList
int[2] int[2] int[2] int*[3]
Contrary to what you said, NameList is not a pointer to an array of arrays. I feel i need to show you what that would be:
int (*NameList)[N][M] = Some3DimensionalArray;
That wouldn't make sense at all. So what do you have?
Data1 = array of 2 int
Data2 = array of 2 int
Data3 = array of 2 int
NameList = array of poiners to int
That is what you got. And you pass NameList to a Function that wants a pointer to an int. It must fail already at the time you call Function in main! I've got no idea what you mean by name in that line in Function. But if you want to print out the integers that are stored in the arrays pointed to (by pointers to their first element), you can do it like this (keeping your code as much as i can):
// don't forget the return type, mate. Also see below
void Function(int **ArrayPointer)
{
int i, j, index=0;
for (i=0; i < 3; i++)
{
for (j=0; j < 2; j++)
{
// It does not print the data. It is not a string,
// but an int!
printf("\nName: %d\n", ArrayPointer[i][index++]);
}
index=0; //Counter reset to 0
// no need to increment the pointer. that's what the indexing by i
// above does
// ArrayPointer++;
}
}
I keep preaching people asking questions the difference between a pointer and an array. It's crucial to write correct code. I hope i could help. At the end, just a little though about the difference between int[] and int*. The first is an incomplete array type, while the second is a complete type (pointer to int):
typedef int Single[]; // array of indeterminate size.
typedef int *Pointer; // pointer to int
Single s1 = { 1, 2, 3, 4 }; // works!
Pointer s2 = { 1, 2, 3, 4 }; // no no, doesn't work. s2 wants an address
s2's type now has a type different from int[], because you initialized the array which would have incomplete type, the array s1 become complete after defined. It has type of int[4]. In parameter lists, however, there exist a special rule, which will cause any array type (even complete ones!) to be equivalent to a pointer to their first argument. Thus:
void f(int *a) <=> void f(int a[]) <=> void f(int a[42]);
void f(int (*a)[42]) <=> void f(int a[][42]) <=> void f(int a[13][42])
// ...
That's because you can't pass arrays by value. The compiler abuses that to make array types equivalent to pointers to their first element. Same deal with functions:
void f(int a()) <=> void f(int (*a)())
Because you can't pass functions by value (huh, doesn't even make sense at all to me), the compiler abuses it to make a function type in a parameter list equivalent to a pointer to that function type.

int Data1[]
has the type of
int *
and
int *NameList[]
has the type of
int **
You have a two-dimensional array there. Most likely you meant:
Function(int **ArrayPointer)
On that note, ANSI C/C89/C99 functions have an explicit return type (or void), e.g.
int main() { ... }
void Function() { ... }
The value pointed to by ArrayPointer is an int, not a string. Thus
printf("\nName: %s", ArrayPointer[index++]);
Should be written as something else.
A third thing: index == j in your code. Thus index can be removed in favor of j.
i and j are probably not good variable names here because ArrayPointer is not name describing a list of something.
If you need more help, please post what you're looking to do, because you code has several bugs (and oddities) in it.

Judging by your "answer" (you really should have edited your original post and added this information), you probably want something like this:
void draw_all_sprites(Sprite *sprites, size_t num_sprites)
{
Sprite *cur_sprite;
size_t i;
for(i = 0; i < num_sprites; ++i)
{
draw_sprite(cur_sprite);
++cur_sprite;
}
}
A fairly simple for loop to iterate through elements in an array.

Paramod,
is there a function you need to call that takes something along the lines of
void drawSprite(int *data, int rows, int cols)
?
Then you need to have all data in a single chunk of memory. In your example, the compiler allocates a separate chunk for every row, and then another chunk to hold the three pointers to rows. Thus, the array is kept in 4 different places.
What you need is a multidimensional array rather than array of arrays. Initialize your data like this:
int data[3,2] = {{10,10},{20,20},{30,30}};
Then you can call your function like this:
drawSprite(&data[0,0], 3, 2);
Using multidimensional array places all elements in one block of memory. The advantage is, you can pass the piointer to first element, and you know where all other elements are. The disadvantage - all rows are allocated the same size.

I made some corrections in your program please find them and compare. I know its too late for the response. But I saw this today itself.
int Data1[] = {10,10};
int Data2[] = {20,20};
int Data3[] = {30,30};
int *NameList[] = {Data1, Data2, Data3};
main()
{
Function(NameList);
}
Function(int *ArrayPointer)
{
int i, j, index=0;
for (i=0; i < 3; i++)
{
for (j=0; j < 5; j++)
{
//It does not print the data
printf("\nName: %d\n", *((int *)ArrayPointer[i] + index));
index++;
}
index=0; //Counter reset to 0
}
}
Explanation:
When you pass NameList to Function as a pointer to an integer, what gets passed is the address of the first element of the array, which happens to be Data1 (an address to an array). But since this address is held in an array of ints, it will be considered as an integer. To make it behave like an address to an array(or, for that matter pointer to an int) you need to cast it to (int *). Thats what I did in :
printf("\nName: %d\n", *((int *)ArrayPointer[i] + index));

Related

Passing 2D array of const size

How should an array of constant size:
const int m = 5, n = 3;
int arr[m][n];
be passed to a function in a way which is both C89 and C++-compatible?
void func(const int m, const int n, int arr[][n]) { }
isn't valid C++ (giving errors such as "A parameter is not allowed" and "Variable 'n' was not declared in this scope"), even though the size of arr is determinate at compile-time. (It is valid C, however.) #defineing m and n works but is not preferred due to scope issues. Passing a pointer to the first element of the array leads to ugly code in the function body.
Feel free to take a look at this FAQ for context.
In C++, you can pass an array to a function with full type information intact by utilizing a template and an array reference function argument:
template <unsigned M, unsigned N>
void func (int (&arr)[M][N]) {
//...
}
The function prototype you are using is using a C99 feature called VLA to provide a dynamic binding of the array dimension. This is not a C++ feature, although some C++ compilers will allow it as an extension to the C++ language.
The C-FAQ was written before C99 was ratified, so the variable length array feature was not yet a standard feature of C. With a modern C compiler with VLA support, the function prototype you provided works just fine.
There is another alternative to use if you have an older compiler for which VLA support is not available. That is to treat the 2-D array as a flattened 1-D array, and use manual calculations to index the correct integer:
void func(const int m, const int n, void *p) {
int *a = p;
int i, j;
for (i = 0; i < m; ++i) {
for (j = 0; j < n; ++j) {
printf(" %d", a[i*n + j]);
}
puts("");
}
}
Then you call func(m, n, arr). In side the function, the expression
a[i*n + j]
steps over n ints i times, then steps over j ints. Since each row is n ints long, the calculation returns the ith row and the jth column, which corresponds precisely to arr[i][j].
I have tried this code:
void func(const int m, const int n, int arr[][n])
{
printf("%d\n", arr[4][2]);
}
int main()
{
const int m = 5, n = 3;
int arr[m][n];
arr[4][2] = 10;
func(m, n, arr);
}
and this work with no warnings
Your array arr[m][n] is not constant. However you have constant variables M and N. You should also define the arr[m][n] as a constant and not just an int array.
You may want to consider dynamicaly allocating your array so that you can just pass the pointer address down.
const int m = 5, n = 3;
int i = 0;
int* *arr; //Pointer to an integer pointer (Note can also be int **arr or int** arr)
arr = malloc(sizeof(int*)*(m+1)); //I add one because I am assuming that 'm' does not account for the terminating null character. But if you do not need a terminating null then you can remove this and the perantheses around the 'm'.
for(i = 0; i < m; i++)
{
arr[i] = malloc(sizeof(int*)*(n+1)); //Same as before
}
The inital malloc() call allocates memory for an array of integer arrays or said in another way, it allocates a pointer to a series of other pointers. The for loop will allocate an integer array of 'm' size for each element of the original array or said another way it will allocate space for every pointer address pointed to by the original pointer address. I left out error checking in order to simplfy my example but here is the same example with error checking.
const int m = 5, n = 3;
int i = 0;
int* *arr = NULL;
if((arr = malloc(sizeof(int*)*(m+1))) == NULL)
{
perror("ERROR(1): Failed to allocate memory for the initial pointer address ");
return 1;
}
for(i = 0; i < m; i++)
{
if((arr = malloc(sizeof(int*)*(m+1))) == NULL)
{
perror("ERROR(2): Failed to allocate memory for a subsequent pointer address ");
return 2;
}
}
Now that you have dynamicaly allocated your array you can just pass the pointer address.
int* *arr in the following the way.
void fun(const int n, const int m, int* *arr) {}
Also you don't necessarily have to keep track of the size of your arrays if the sizes are constant and if you use null terminated arrays. You just have to malloc the array using the constant integer variable's actual value and then check for the terminating null byte when iterating threw the array.
int* *arr = NULL;
if((arr = malloc(sizeof(int*)*6)) == NULL)'m'+1 = 6;
{
perror("ERROR(1): Failed to allocate memory for the initial pointer address ");
return 1;
}
for(i = 0; i < m; i++)
{
if((arr = malloc(sizeof(int*)*4) == NULL)//'n'+1 = 4
{
perror("ERROR(2): Failed to allocate memory for a subsequent pointer address ");
return 2;
}
}
You can then display the entire two dimensional array in the following way. Note that '\000' is the octagonal value for a null byte(00000000).
int i, j;
for(i = 0; arr[i] != '\000'; i++)
{
for(j = 0; arr[i][j] != '\000'; j++)
{
printf("%i ", arr[i][j]); //Prints the current element of the current array
}
printf("\n"); //This just ends the line so that each of the arrays is printed on it's own line.
}
Of course the above mentioned loops would have the same result as the following.
int i, j;
int m = 5;
int n = 3;
for(i = 0; i < m; i++)
{
for(j = 0; i < n; j++)
{
printf("%i ", arr[i][j]); //Prints the current element of the current array
}
printf("\n"); //This just ends the line so that each of the arrays is printed on it's own line.
}
Which means, in most situations there is no need for keeping track of an array's size but there are situations in which it is necessary. For example if one your arrays could possible contain a null byte other than the terminating null byte. The new null byte would shorten the array's size to the index of the new null byte. If you have any questions or comments feel free to comment below or message me.
The problem here is the "missing" support for dynamic arrays in C++.
const int m = 5, n = 3;
int arr[m][n];
Works since m and n are compile time constant and accessible directly at the declaration of the array.
void func(const int m, const int n, int arr[][n]) { }
The compiler handles your function regardless of where it is called in first place.
Therefore n is unknown/variable and thus prohibited as a array dimensionality.
The following example won't work too because of the very same reason:
void foo (const int n)
{
int arr[n]; // error, n is const but not compile time constant
}
int main (void)
{
foo(4);
}
jxh answered what to do about it.

Pointing to a 2-dimensional array

I'm trying to write code that has a pointer point to a 2-dimensional array.
My main purpose is for not just one asd array, like I would like to point 5 array each of which is 2 dimensional.
int asd1[2][2];
int asd2[2][2];
int *se;
se[0] = asd1;
se[1] = asd2;
Use se = asd[0];
The reason is that the symbol asd yields not a pointer to an int but rather a pointer to a one-dimensional array of ints.
#Mig's solution may be good, too. It depends on what you want. In my experience, it tends to work better when you treat a two-dimensional array of a basic type like int as though it were a one-dimensional of length n*n. (This is expecially true in numerical work, where you are likely to call BLAS and LAPACK, but may be true elsewhere, as well. You probably aren't doing numerical work here, but, well, try #Mig's and mine both, and see which you don't prefer. Good luck.)
You can do this:
#include<stdio.h>
int main()
{
int asd[2][2] = {{0,1},{2,3}};
int (*se)[2]; // a pointer (*se) to an array (2-element array, but only you know it, not the compiler) of array-of-two-integers [2]
se = asd;
printf("%d %d\n%d %d\n", se[0][0], se[0][1], se[1][0], se[1][1]);
return 0;
}
or:
#include<stdio.h>
int main()
{
int asd[2][2] = {{0,1},{2,3}};
int (*se)[2][2]; // a pointer (*se) to a 2-element array (first [2]) of two element array (second [2]) of ints
se = &asd;
printf("%d %d\n%d %d\n", (*se)[0][0], (*se)[0][1], (*se)[1][0], (*se)[1][1]);
return 0;
}
You want something like this:
int asd[2][2];
int (*se)[2] = asd;
This is equivalent to
int (*se)[2] = &asd[0];
because asd decays to a pointer to its first element in this context.
The key thing to bear in mind is that the type of asd[0] is int[2], not int*, so you need a pointer to an int[2] (i.e. int (*)[2]) and not a pointer to an int* (i.e. int**).
Incidentally, you can make an int* point to the first element of the asd[0] if you like:
int *p = &asd[0][0]; // or just = asd[0];, because it decays to &asd[0][0];
but accessing the other elements of the 2D array as if it were a 1D array, e.g. p[2], would be undefined behaviour.
As a more general point, it's often better to eschew using raw C-style arrays altogether if you can help it. You might want to investigate std::array or std::vector, depending on your needs.
If you were allocating that array dynamically, you could do something like this:
#include <stdio.h>
#include <stdlib.h>
#define SIZE 10
int main() {
int i;
int **asd;
asd = (int **)malloc(sizeof(int *) * SIZE);
for (i = 0; i < SIZE; i++) {
asd[i] = (int*)malloc(sizeof(int) * SIZE);
}
int **se;
se = asd;
se[0][1] = 10;
printf("%d %d\n", se[0][1], asd[0][1]);
for (i = 0; i < SIZE; i++) {
free(asd[i]);
}
free(asd);
return 0;
}
EDIT: My first answer was wrong, here's what I had said:
You need a pointer to a pointer, since your array is 2-dimensional:
int asd[2][2];
int **se;
se = asd;
Now you should be able to:
se[0][1] = 10;

How to pass a multidimensional array to a function in C and C++

#include<stdio.h>
void print(int *arr[], int s1, int s2) {
int i, j;
for(i = 0; i<s1; i++)
for(j = 0; j<s2; j++)
printf("%d, ", *((arr+i)+j));
}
int main() {
int a[4][4] = {{0}};
print(a,4,4);
}
This works in C, but not in C++.
error:
cannot convert `int (*)[4]' to `int**' for argument `1' to
`void print(int**, int, int)'
Why does it not work in C++? What change is needed to be made?
This code will not work in either C or C++. An array of type int[4][4] is not convertible to a pointer of type int ** (which is what int *arr[] stands for in parameter declaration). If you managed to compile it in C, it is simply because you probably ignored a C compiler warning of basically the same format as the error message you got from C++ compiler. (Sometimes C compilers issue warnings for what is essentially an error.)
So, again, don't make assertions that are not true. This code does not work in C. In order to convert a built-in 2D array into a int ** pointer you can use a technique like this one
Converting multidimensional arrays to pointers in c++
(See the accepted answer. The problem is exactly the same.)
EDIT: The code appears to work in C because another bug in the printing code is masquerading the effects of the bug in array passing. In order to properly access an element of an int ** pseudo-array, you have to use expression *(*(arr + i) + j), or better a plain arr[i][j] (which is the same thing). You missed the extra * which made it print something that has absolutely nothing to do with the content of your array. Again, initialize your array in main to something else to see that the results you are printing in C have absolutely nothing to do with the your intended content of the array.
If you change the printf statement as shown above, your code will most likely crash because of the array-passing bug I described initially.
One more time: you cannot pass a int[4][4] array as an int ** pseudo-array. This is what the C++ is telling you in the error message. And, I'm sure, this is what your C compiler told you, but you probably ignored it, since it was "just a warning".
The problem is, that
int a[4][4];
will actually be stored in a physically continuous memory. So, to access an arbitrary part of your 4x4 array, the function "print" needs to know the dimensions of the array. For example the following little piece of code, will access the same part of the memory in two different ways.
#include <iostream>
void print(int a[][4]) {
for (int i = 0; i <4; i++) {
for (int j = 0; j < 4; j++) {
//accessing as 4x4 array
std::cout << a[i][j] <<std::endl;
//accessing corresponding to the physical layout in memory
std::cout << *(*(a)+ i*4 + j) << std::endl;
}
}
}
int main() {
int a[4][4];
//populating the array with the corresponding indices from 0 to 15
int m = 0;
for (int i = 0; i<4; i++) {
for (int j= 0; j < 4; j++) {
a[i][j] = m;
m++;
}
}
print(a);
}
So the memory layout doesn't change but the way of accessing does. It can be visualized like a checkerboard.
0 1 2 3
----------
0| 1 2 3 4
1| 5 6 7 8
2| 9 10 11 12
3|13 14 15 16
But the real physical memory looks like this.
0*4+0 0*4+1 0*4+2 0*4+3 1*4+0 1*4+1 1*4+2 1*4+3 2*4+1 etc.
-----------------------------------------------------
1 2 3 4 5 6 7 8 9 etc.
In c++ the data of an array is stored row-by-row and the length of a row (in this case 4) is always necessary to get to the proper memory offset for the next row. The first subscript therefore only indicates the amount of storage that is needed when the array is declared, but is no longer necessary to calculate the offset afterwards.
Note: this answer doesn't answer the specifics of the OP's question. There are already answers for that. Rather, it answers only the title of the OP's question: "How to pass a multidimensional array to a function in C and C++", since Google searches for that phrase or similar lead right here, and I have a lot to say on the topic. Keep in mind if I made my own question to post this as an answer, it would be closed as a duplicate of this question, so I'm posting this here instead.
For passing 1D arrays, see my other answer here instead: Passing an array as an argument to a function in C
If in a hurry:
...and:
you are using C++, it really is best to represent a 2D array as a vector of vectors (ex: std::vector<std::vector<int>> (recommended!)), so see my other answer here: How to pass a multidimensional array to a function in C++ only, via std::vector<std::vector<int>>&.
you really want to use C-style multi-dimensional arrays in C or C++, jump straight down and look at the 4 print examples under the "Summary of Conclusions and Recommendations..." section.
How to use multidimensional (ex: 2D) arrays, and pointers to them, as function parameters in C and C++
Multidimensional arrays are very confusing for just about everybody, myself included--for experienced programmers and beginners alike. So, I'd like to provide a canonical set of examples I can come back to and reference again and again (see comments below this answer, however; I don't cover it all), with some clear demonstrations and easy-to-follow guidelines. Here it goes.
Upfront notes:
NB: as of C2x (C20 or later), the following "original principle" guideline 15 is in effect (source: Wikipedia: C2x --> original source: Programming Language C - C2x Charter):
Application Programming Interfaces (APIs) should be self-documenting when possible. In particular, the order of parameters in function declarations should be arranged such that the size of an array appears before the array. The purpose is to allow Variable-Length Array (VLA) notation to be used. This not only makes the code's purpose clearer to human readers, but also makes static analysis easier. Any new APIs added to the Standard should take this into consideration.
So, if you'd like to be C2x-compliant (most std C functions to date are not), then re-arrange all of my functions below to put the array size arguments before the array or pointer-to-array arguments.
I began this answer as a response to this question: Passing a pointer to array to my function. But, it fits better here, so I'm putting it here instead.
The code below is found in my eRCaGuy_hello_world repo here: c/array_2d_practice.c. It compiles and runs in both C and C++ (tested in C11 and C++17). See the build and run commands at the top of the source code file. I use gcc build options -Wall -Wextra -Werror for safety.
My answer focuses on multidimensional 2D arrays, but could be easily extended to any number of dimensions: 3D, 4D, 5D, etc...ND arrays.
I use const in my print functions since I'm just printing the arrays and not modifying them. Remove const if you ever need to modify the arrays in-place.
Array Notes to be aware of first:
1. Fixed vs unspecified dimensions:
Arrays must be fixed (specified) size on all dimensions except the 1st (outermost) dimension, which can optionally be unspecified.
// OK; 1D array with unspecified 1st (and only) dimension
int array[] = {1, 2, 3};
// OK; 2D array with unspecified 1st dimensions
int array[][2] = {{1, 2}, {3, 4}};
// NOT allowed; 2D array with both dimensions unspecified!:
// `error: array type has incomplete element type ‘int[]’`
int array[][] = {{1, 2}, {3, 4}};
2. Natural type decay of array types:
First, let me distinguish between "array types", and "pointers to array types". "Array types" are arrays, and "pointers to array types" are pointers. Pointers cannot decay to (AKA "adjust" to become) pointers, because they are already pointers. Arrays, however can and do decay to ("adjust" to become) pointers.
(1) So, here are some examples of array types, meaning they are just regular "arrays": int array_2d[][2], int* array_2d[], int array_2d[3][2]. The first is a 2D array of ints, the 2nd is a 1D array of int*, and the 3rd is a 2D array of ints.
(2) However, this is a ptr to array type, or "pointer to array": int (*array_2d)[3][2]. The ptrs to arrays always have the parenthesis around the asterisk, like this: (*), just before the square braces. That's how you can recognize them. So, the first 3 arrays just above decay to ptrs when used as arguments, whereas the last one does not, since it's already a ptr.
The principle is: when used as function parameters, all array types (but NOT ptrs to array types) decay the first dimension down into a ptr, whether that dimension's size is explicitly specified or not! So, although int arr[] (array of ints) and int * arr (pointer to an int) are NOT the same types, a function definition with either of those in it will naturally decay the 1st dimension in the array (which is the only dimension in this 1D array case) down to a pointer, resulting in type (int * arr) being passed to the function in both cases:
// accepts `int *` as `array` parameter
void my_func(int * array, size_t len) {}
// also accepts `int *` as `array` parameter, since the `int []` type
// (array of ints) naturally decays down to type `int *` (ptr to int`).
void my_func(int array[], size_t len) {}
Taking this further, specifying the size to the first dimension on the array has no bearing on this effect. ie: it makes no difference whatsoever and is meaningless to the compiler. It simply serves as a visual indicator or type of "self documentation" to the programmer is all, that this particular function expects an array of at least this size or larger. See my answer here (Passing an array as an argument to a function in C) where I talk about this and also quote the MISRA-C standard which recommends using this feature for self-documentation purposes.
So, these are all the same as the functions above too:
// same as above: these ALL accept `int *` as the 1st parameter, and the
// specified size here in square brackets [] has no effect on the compiler.
void my_func(int array[1], size_t len) {}
void my_func(int array[10], size_t len) {}
void my_func(int array[100], size_t len) {}
So, this is fine:
int array[10];
my_func(array); // ok; `array` naturally decays down to type `int *`
And this is fine too:
int array[10];
int * array_p = array;
my_func(array_p); // ok; is already of type `int *`
HOWEVER, for pointers to arrays, the actual array type and size DOES matter, and no natural type decay from an array to a ptr occurs because the type is already a ptr--to an array of a specified type and size! Read my answer above.
Example: the following function REQUIRES an input parameter of type ptr to 1D array of size 10. It's already a ptr, so no natural type decay to a ptr occurs! Since this parameter is a ptr to an array, you must also pass the address of the array via the & character when making the function calls, as shown below. Notice that only 2 of the calls below work: my_func(&array2); and my_func(array2_p2);. I went through the effort of showing all of these calls, however, to be able to explain and demonstrate the various array types and how and when they decay to pointers, and of what type.
// 0. Define a function
/// `array` is a "ptr to an array of 10 ints".
void my_func(int (*array)[10]) {}
// 1. Create arrays
int array1[5];
int *array1_p = array1; // array1_p is of type `int *` (ptr to int)
int (*array1_p2)[5] = &array1; // array1_p2 is of type `int (*)[5]` (ptr
// to array of 5 ints)
int array2[10];
int *array2_p = array2; // array2_p is of type `int *` (ptr to int)
int (*array2_p2)[10] = &array2; // array2_p2 is of type `int (*)[10]` (ptr
// to array of 10 ints)
// 2. Make some calls
// 2.1. calling with `int array1[5]`
// FAILS! Expected `int (*)[10]` (ptr to array of 10 ints) but argument is
// of type `int *` (ptr to int); due to **natural type decay** from
// `int[5]` (array of 5 ints) to `int *` (ptr to int)
my_func(array1);
// FAILS! Expected `int (*)[10]` (ptr to array of 10 ints) but argument is
// of type `int *` (ptr to int); due to dereferencing to `int[5]` (array
// of 5 ints), followed by **natural type decay** from `int[5]`
// (array of 5 ints) to `int *` (ptr to int)
my_func(*array1_p2);
// FAILS! Expected `int (*)[10]` (ptr to array of 10 ints) but argument is
// of type `int *` (ptr to int)
my_func(array1_p);
// FAILS! Expected `int (*)[10]` (ptr to array of 10 ints) but argument is
// of type `int`; due to **natural type decay** from `int[5]` (array of
// 5 ints) to `int *` (ptr to int), in conjunction with dereferencing
// from that to `int`
my_func(*array1);
// FAILS! Expected `int (*)[10]` (ptr to array of 10 ints) but argument is
// of type `int`
my_func(*array1_p);
// FAILS! Expected `int (*)[10]` (ptr to array of 10 ints) but argument is
// of type `int (*)[5]` (ptr to array of 5 ints)
my_func(&array1);
// FAILS! Expected `int (*)[10]` (ptr to array of 10 ints) but argument is
// of type `int (*)[5]` (ptr to array of 5 ints)
my_func(array1_p2);
// FAILS! Expected `int (*)[10]` (ptr to array of 10 ints) but argument is
// of type `int (**)[5]` (ptr to "ptr to array of 5 ints")
my_func(&array1_p2);
// 2.2. calling with `int array2[10]`
// FAILS! Expected `int (*)[10]` (ptr to array of 10 ints) but argument is
// of type `int *` (ptr to int); due to **natural type decay** from
// `int[10]` (array of 10 ints) to `int *` (ptr to int)
my_func(array2);
// FAILS! Expected `int (*)[10]` (ptr to array of 10 ints) but argument is
// of type `int *` (ptr to int); due to dereferencing to `int[10]` (array
// of 10 ints), followed by **natural type decay** from `int[10]`
// (array of 10 ints) to `int *` (ptr to int)
my_func(*array2_p2);
// FAILS! Expected `int (*)[10]` (ptr to array of 10 ints) but argument is
// of type `int *` (ptr to int)
my_func(array2_p);
// FAILS! Expected `int (*)[10]` (ptr to array of 10 ints) but argument is
// of type `int`; due to **natural type decay** from `int[10]` (array of
// 10 ints) to `int *` (ptr to int), in conjunction with dereferencing
// from that to `int`
my_func(*array2);
// FAILS! Expected `int (*)[10]` (ptr to array of 10 ints) but argument is
// of type `int`
my_func(*array2_p);
// <===============
// <=== WORKS! ====
// <===============
// Expected and received `int (*)[10]` (ptr to array of 10 ints)
my_func(&array2);
// <===============
// <=== WORKS! ====
// <===============
// Expected and received `int (*)[10]` (ptr to array of 10 ints)
my_func(array2_p2);
// FAILS! Expected `int (*)[10]` (ptr to array of 10 ints) but argument is
// of type `int (**)[10]` (ptr to "ptr to array of 10 ints")
my_func(&array2_p2);
3. A quick reminder on pointers:
Remember that the types int *[2] and int (*)[2] are NOT the same type! The parenthesis matter! int *[2] is an "array of 2 int *s (pointers to int)", whereas int (*)[2] is a "ptr to an array of 2 ints". These are two very different things.
Also, a ptr can be indexed like an array, which leads to the very-frequent confusion that an array IS a ptr, which is FALSE. An array is NOT a ptr! But, the following concept is critical to understanding the code below: int array_2d[][2] is a 2D array. Variable array_2d is of type int [][2] (n x 2 (2D) array of ints), which is a 2D array with an unspecified number of rows (dimension 1), and 2 columns (dimension 2). When used as a function parameter, this int [][2] type naturally decays to type int (*)[2] (ptr to (1D) array of 2 ints). So, if this decayed type is a ptr, how is it still an array? Well, since a ptr can be indexed like an array, you can still do things like this to index into it: array_2d[row][col]. The outer dimension is the ptr, which is indexable as the row, while the inner dimension is the [2] (2 ints) part, which is indexable as the column since it is a sub-array within an array. This means that each row contains 2 ints, so once you index into a row, you then need to index into a column. So, the confusion between ptrs and arrays lies in the fact that all ptrs are indexable like arrays, even though arrays are NOT ptrs--rather, the first dimension of all arrays (but NOT ptrs to arrays) decays into a ptr when used as an argument.
So, with the above concepts in mind, the following will make more sense. For each function definition, pay attention to what the array type is and whether or not it will naturally decay, and to what. Again, when used as function parameters, all non-pointer array types decay the first dimension of the array down into a ptr, which is still indexable like an array.
Summary of Conclusions and Recommendations for passing multidimensional arrays:
Here are my 4 use-cases and techniques to pass multi-dimensional arrays as parameters, and recommendations on when to use each. You can see from the function prototypes and definitions for each technique the varying tradeoffs, complexities, and benefits that each offers.
Assume you have the following 2D array:
int arr[][2] =
{
{1, 2},
{5, 6},
{7, 8},
};
...and the following macro definitions:
// Get the number of elements in any C array
// - from my repo here:
// https://github.com/ElectricRCAircraftGuy/eRCaGuy_hello_world/blob/master/c/utilities.h#L42
#define ARRAY_LEN(array) (sizeof(array) / sizeof(array[0]))
/// Definitions: `rows` = "rows"; `cols` = "columns"
/// Get number of rows in a 2D array
#define NUM_ROWS(array_2d) ARRAY_LEN(array_2d)
/// Get number of columns in a 2D array
#define NUM_COLS(array_2d) ARRAY_LEN(array_2d[0])
Example 1: Fixed-size multi-dimensional arrays: if the 2D array is ALWAYS the same size each time (it has a FIXED number of rows, and a FIXED number of columns) (3 rows and 2 columns in the below example), do this:
// 1. Function definition
/// \brief Print a 2D array which has a FIXED number of rows and
/// FIXED number of columns.
/// \param[in] array_2d a 2D array; is of type `int (*)[3][2]` (ptr to
/// 3 x 2 (2D) array of ints); since it is already
/// explicitly a ptr, it does NOT naturally decay to
/// any other type of ptr
/// \return None
void print_array2(const int (*array_2d)[3][2])
{
printf("print_array2:\n");
for (size_t row = 0; row < NUM_ROWS(*array_2d); row++)
{
for (size_t col = 0; col < NUM_COLS(*array_2d); col++)
{
printf("array_2d[%zu][%zu]=%i ", row, col, (*array_2d)[row][col]);
}
printf("\n");
}
printf("\n");
}
// 2. Basic usage
// NB: `&` is REQUIRED! See my answer for why: https://stackoverflow.com/a/51527502/4561887
print_array2(&arr);
// 3. Usage via a pointer
// `int (*array_2d)[3][2]` is an explicit ptr to a 3x2 array of `int`. This
// pointer to an array does NOT naturally decay to a simpler type.
int (*p2)[3][2] = &arr; // must use `&` and MUST USE THESE PARENTHESIS!
print_array2(p2);
Example 2: If the 2D array has a VARIABLE number of rows, but a FIXED number of columns (2 in this case),
do this:
// 1. Function definition
/// \brief Print a 2D array which has a VARIABLE number of rows but
/// FIXED number of columns.
/// \param[in] array_2d a 2D array; is of type `int [][2]` (n x 2 (2D) array
/// of ints), which naturally decays to type
/// `int (*)[2]` (ptr to (1D) array of 2 ints)
/// \param[in] num_rows The number of rows in the array
/// \return None
void print_array3(const int array_2d[][2], size_t num_rows)
{
printf("print_array3:\n");
// Technique 1: use `array_2d` directly.
printf("--- Technique 1: ---\n");
for (size_t row = 0; row < num_rows; row++)
{
for (size_t col = 0; col < NUM_COLS(array_2d); col++)
{
printf("array_2d[%zu][%zu]=%i ", row, col, array_2d[row][col]);
}
printf("\n");
}
// Technique 2: cast the `array_2d` decayed ptr to a ptr to a sized array of
// the correct size, then use that ptr to the properly-sized array
// directly! NB: after obtaining this ptr via the cast below, this
// technique is **exactly identical** to (I copy/pasted it from, then
// renamed the variable) the implementation inside `print_array2()` above!
printf("--- Technique 2: ---\n");
int (*array_2d_ptr)[num_rows][NUM_COLS(array_2d)] =
(int (*)[num_rows][NUM_COLS(array_2d)])array_2d;
for (size_t row = 0; row < NUM_ROWS(*array_2d_ptr); row++)
{
for (size_t col = 0; col < NUM_COLS(*array_2d_ptr); col++)
{
printf("array_2d_ptr[%zu][%zu]=%i ", row, col, (*array_2d_ptr)[row][col]);
}
printf("\n");
}
printf("\n");
}
// 2. Basic usage
print_array3(arr, NUM_ROWS(arr));
// 3. Usage via a pointer
// `int array_2d[][2]` (n x 2 (2D) array of ints) naturally decays to
// `int (*)[2]` (ptr to (1D) array of 2 ints)
int (*p3)[2] = arr; // MUST USE THESE PARENTHESIS!
print_array3(p3, NUM_ROWS(arr));
Example 3: If the 2D array has a VARIABLE number of rows AND a VARIABLE number of columns, do this (this
approach is the most-versatile and is therefore generally my overall preferred approach, and go-to approach for multidimensional arrays):
// 1. Function definition
/// \brief Print a 2D array which has a VARIABLE number of rows and
/// VARIABLE number of columns.
/// \param[in] array_2d a 2D array; is of type `int *` (ptr to int); even
/// though a 1D array of type `int []` (array of ints)
/// naturally decays to this type, don't think about it
/// that way; rather, think of it as a ptr to the first
/// `int` in a contiguous block of memory containing a
/// multidimensional array, and we will manually index
/// into it as required and according to its dimensions
/// \param[in] num_rows The number of rows in the array
/// \param[in] num_cols The number of columns in the array
/// \return None
void print_array4(const int *array_2d, size_t num_rows, size_t num_cols)
{
printf("print_array4:\n");
// Technique 1: use `array_2d` directly, manually indexing into this
// contiguous block of memory holding the 2D array data.
printf("--- Technique 1: ---\n");
for (size_t row = 0; row < num_rows; row++)
{
const int *row_start = &array_2d[row*num_cols];
for (size_t col = 0; col < num_cols; col++)
{
// NB: THIS PART IS VERY DIFFERENT FROM THE OTHERS! Notice `row_start[col]`.
printf("array_2d[%zu][%zu]=%i ", row, col, row_start[col]);
}
printf("\n");
}
// Technique 2: cast the `array_2d` decayed ptr to a ptr to a sized array of
// the correct size, then use that ptr to the properly-sized array
// directly! NB: after obtaining this ptr via the cast below, this
// technique is **exactly identical** to (I copy/pasted it from, then
// renamed the variable) the implementation inside `print_array2()` above!
printf("--- Technique 2: ---\n");
int (*array_2d_ptr)[num_rows][num_cols] =
(int (*)[num_rows][num_cols])array_2d;
for (size_t row = 0; row < NUM_ROWS(*array_2d_ptr); row++)
{
for (size_t col = 0; col < NUM_COLS(*array_2d_ptr); col++)
{
printf("array_2d_ptr[%zu][%zu]=%i ", row, col, (*array_2d_ptr)[row][col]);
}
printf("\n");
}
printf("\n");
}
// 2. Basic usage
print_array4((int *)arr, NUM_ROWS(arr), NUM_COLS(arr));
// OR: alternative call technique:
print_array4(&arr[0][0], NUM_ROWS(arr), NUM_COLS(arr));
// 3. Usage via a pointer
// The easiest one by far!
int *p4_1 = (int*)arr;
// OR
int *p4_2 = &arr[0][0];
print_array4(p4_1, NUM_ROWS(arr), NUM_COLS(arr));
print_array4(p4_2, NUM_ROWS(arr), NUM_COLS(arr));
If you have the following "2D" array, however, you must do something different:
// Each row is an array of `int`s.
int row1[] = {1, 2};
int row2[] = {5, 6};
int row3[] = {7, 8};
// This is an array of `int *`, or "pointer to int". The blob of all rows
// together does NOT have to be in contiguous memory. This is very different
// from the `arr` array above, which contains all data in contiguous memory.
int* all_rows[] = {row1, row2, row3}; // "2D" array
Example 4: If the 2D array is actually built up of a bunch of ptrs to other arrays (as shown just above),
do this:
// 1. Function definition
/// \brief Print a 2D-like array, where the array passed in is an array of
/// ptrs (int *) to other sub-arrays. Each index into the outer
/// array is the row, then each index into a sub-array in a given
/// row is the column. This handles a VARIABLE number of rows and
/// VARIABLE number of columns.
/// \details `array_2d` here is different from all of the cases above. It is
/// NOT a contiguous 2D array of `int`s; rather, it is an array of
/// pointers to ints, where each pointer in the array can be
/// thought of as a sub-array. Therefore, the length of the outer
/// array is the number of rows, and the length of each sub-array,
/// or inner array, is the number of columns. Each sub-array
/// (a single row of `int`s) DOES have to be in contiguous memory,
/// and the array of _pointers_ DOES have to be in contiguous
/// memory, but the total _storage space_ for the combined total of
/// all rows can be in NON-contiguous memory. Again, this is VERY
/// different from every other function above.
/// \param[in] array_2d a 2D array; is of type `int * []` (array of ptrs to
/// int) (where each ptr is a sub-array of ints);
/// `int * []` naturally decays to type `int**` (ptr to
/// "ptr to int")
/// \param[in] num_rows The number of rows in the array (number of elements
/// in the `array_2d` outer array)
/// \param[in] num_cols The number of columns in the array (number of
/// elements in each sub-array)
/// \return None
void print_array5(const int* array_2d[], size_t num_rows, size_t num_cols)
{
printf("print_array5:\n");
printf("--- Technique 1: use `row_start[col]` ---\n");
for (size_t row = 0; row < num_rows; row++)
{
const int *row_start = array_2d[row]; // VERY DIFFERENT FROM `print_array4` above!
for (size_t col = 0; col < num_cols; col++)
{
// Identical to `print_array4` above.
printf("array_2d[%zu][%zu]=%i ", row, col, row_start[col]);
}
printf("\n");
}
printf("--- Technique 2: use `array_2d[row][col]` ---\n");
for (size_t row = 0; row < num_rows; row++)
{
for (size_t col = 0; col < num_cols; col++)
{
// OR you can simply do this!
printf("array_2d[%zu][%zu]=%i ", row, col, array_2d[row][col]);
}
printf("\n");
}
printf("\n");
}
// 2. Basic usage
print_array5(all_rows, ARRAY_LEN(all_rows), ARRAY_LEN(row1));
// 3. Usage via a pointer
//
// 3.1. Easier way: ptr to "ptr to int"; note: `int* array_2d[]` naturally
// decays to `int**`.
const int **p5_1 = all_rows;
print_array5(p5_1, ARRAY_LEN(all_rows), ARRAY_LEN(row1));
//
// 3.2. OR this more-complicated way, for the sake of demonstration:
// ptr to array of 3 `int*`s
const int* (*p5_2)[ARRAY_LEN(all_rows)] = &all_rows;
// Explanation: the type of `p5_2` is `int* (*)[3]` (ptr to array of 3
// int*), so the type of `*p5_2` is `int* [3]` (array of 3 int*), which
// decays naturally to `int**`, which is what `*p5_2` ends up passing to
// this function call! So, this call to `print_array5()` here and the one
// just above are therefore exactly identical!
print_array5(*p5_2, ARRAY_LEN(all_rows), ARRAY_LEN(row1));
Don't forget about structs!
Don't forget, however, that sometimes, just using structs is so much easier!
Example:
typedef struct data_s
{
int x;
int y;
} data_t;
// Array of the above struct
data_t data_array[] =
{
{1, 2},
{5, 6},
{7, 8},
};
void print_struct_data(data_t * data, size_t len)
{
for (size_t i = 0; i < len; i++)
{
printf("[data[%zu].x, data[%zu].y] = [%i, %i]\n",
i, i, data[i].x, data[i].y);
}
printf("\n");
}
print_struct_data(data_array, ARRAY_LEN(data_array));
Output:
[data[0].x, data[0].y] = [1, 2]
[data[1].x, data[1].y] = [5, 6]
[data[2].x, data[2].y] = [7, 8]
The full, runnable code:
The full, runnable code causes this answer to exceed the 30000 max chars allowed in an answer. So, download the full code here: c/array_2d_practice.c, in my eRCaGuy_hello_world repo.
Sample output (reduced; please run the full code yourself):
print_array1:
array_2d[0][0]=1 array_2d[0][1]=2
array_2d[1][0]=5 array_2d[1][1]=6
array_2d[2][0]=7 array_2d[2][1]=8
print_array2:
array_2d[0][0]=1 array_2d[0][1]=2
array_2d[1][0]=5 array_2d[1][1]=6
array_2d[2][0]=7 array_2d[2][1]=8
print_array3:
--- Technique 1: ---
array_2d[0][0]=1 array_2d[0][1]=2
array_2d[1][0]=5 array_2d[1][1]=6
array_2d[2][0]=7 array_2d[2][1]=8
--- Technique 2: ---
array_2d_ptr[0][0]=1 array_2d_ptr[0][1]=2
array_2d_ptr[1][0]=5 array_2d_ptr[1][1]=6
array_2d_ptr[2][0]=7 array_2d_ptr[2][1]=8
print_array4:
--- Technique 1: ---
array_2d[0][0]=1 array_2d[0][1]=2
array_2d[1][0]=5 array_2d[1][1]=6
array_2d[2][0]=7 array_2d[2][1]=8
--- Technique 2: ---
array_2d_ptr[0][0]=1 array_2d_ptr[0][1]=2
array_2d_ptr[1][0]=5 array_2d_ptr[1][1]=6
array_2d_ptr[2][0]=7 array_2d_ptr[2][1]=8
print_array5:
--- Technique 1: use `row_start[col]` ---
...
--- Technique 2: use `array_2d[row][col]` ---
...
Don't forget about just using structs and arrays of structs instead, which
is sometimes much easier!
[data[0].x, data[0].y] = [1, 2]
[data[1].x, data[1].y] = [5, 6]
[data[2].x, data[2].y] = [7, 8]
References:
The main reference I used: my own answer containing information on "Forcing type safety on arrays in C", and how to interpret and read 1D pointers to arrays like this: int (*a)[2]: Passing an array as an argument to a function in C
https://www.geeksforgeeks.org/pass-2d-array-parameter-c/
Related/See Also:
[my answer] How to make a 1D PROGMEM array of 2D PROGMEM arrays - I borrowed heavily from my "Example 2" code above to write this answer where I use PROGMEM to store and read an array of 2D arrays into Flash memory on an AVR/Arduino microcontroller.
[my answer] Arduino Stack Exchange: Initializing Array of structs
[my answer which references this answer] Passing a pointer to array to my function
#include<stdio.h>
void print(int arr[][4], int s1, int s2) {
int i, j;
printf("\n");
for(i = 0; i<s1; i++) {
for(j = 0; j<s2; j++) {
printf("%d, ", *((arr+i)+j));
}
}
printf("\n");
}
int main() {
int a[4][4] = {{0}};
print(a,4,4);
}
This will work, where by work I mean compile. #AndreyT explained why your version doesn't work already.
This is how you should pass a 2d array.
For clarity, you can also specify both sizes in the function declaration:
#include<stdio.h>
void print(int arr[4][4], int s1, int s2) {
int i, j;
printf("\n");
for(i = 0; i<s1; i++) {
for(j = 0; j<s2; j++) {
printf("%d, ", *((arr+i)+j));
}
}
printf("\n");
}
int main() {
int a[4][4] = {{0}};
print(a,4,4);
}
Both will work.
You should also change *((arr+i)+j) to either a[i][j] (preferably) or *(*(arr+i)+j) if your intention is to access the jth element of row i.
Here's a version which is both working, but theoretically invalid (see below) C90 and C++98:
#include <stdio.h>
static void print(int *arr, size_t s1, size_t s2)
{
size_t i, j;
printf("\n");
for(i = 0; i < s1; i++) {
for(j = 0; j < s2; j++) {
printf("%d, ", arr[i * s2 + j]);
}
}
printf("\n");
}
int main(void) {
int a[4][4] = {{0}};
print(a[0], 4, 4);
return 0;
}
A C++ version using templates (adapted from Notinlist's answer) could look like this:
#include <iostream>
#include <cstring>
using namespace std;
template <size_t N, size_t M>
struct IntMatrix
{
int data[N][M];
IntMatrix() { memset(data, 0, sizeof data); }
};
template <size_t N, size_t M>
ostream& operator<<(ostream& out, const IntMatrix<N,M>& m)
{
out << "\n";
for(size_t i = 0; i < N; i++) {
for(size_t j = 0; j < M; j++) {
out << m.data[i][j] << ", ";
}
}
out << "\n";
return out;
}
int main()
{
IntMatrix<4,4> a;
cout << a;
return 0;
}
Alternatively, you could use nested STL containers - ie vector< vector<int> > - instead of a plain array.
With C99, you could do
static void print(size_t s1, size_t s2, int arr[s1][s2]) {
printf("\n");
for(size_t i = 0; i < s1; i++) {
for(size_t j = 0; j < s2; j++) {
printf("%d, ", arr[i][j]);
}
}
printf("\n");
}
and call it as
print(4, 4, a);
As Robert pointed out in the comments, the first snippet actually involves undefined behaviour. However, assuming that pointer arithmetics will always result in a pointer even when undefined behaviour is involved (and not blow up your computer), there is only a single possible result because of other restrictions within the standard, ie this is an instance of where the standard leaves something unnecessarily undefined.
As far as I can tell, substituting
print(a[0], 4, 4);
with
union m2f { int multi[4][4]; int flat[16]; } *foo = (union m2f *)&a;
print(foo->flat, 4, 4);
will make it legal C.
You can use int** instead. Its much more flexible:
#include <stdio.h>
#include <stdlib.h>
void print(int **a, int numRows, int numCols )
{
int row, col ;
for( int row = 0; row < numRows; row++ )
{
for( int col = 0; col < numCols ; col++ )
{
printf("%5d, ", a[row][col]);
}
puts("");
}
}
int main()
{
int numRows = 16 ;
int numCols = 5 ;
int **a ;
// a will be a 2d array with numRows rows and numCols cols
// allocate an "array of arrays" of int
a = (int**)malloc( numRows* sizeof(int*) ) ;
// each entry in the array of arrays of int
// isn't allocated yet, so allocate it
for( int row = 0 ; row < numRows ; row++ )
{
// Allocate an array of int's, at each
// entry in the "array of arrays"
a[row] = (int*)malloc( numCols*sizeof(int) ) ;
}
int count = 1 ;
for( int row = 0 ; row < numRows ; row++ )
{
for( int col = 0 ; col < numCols ; col++ )
{
a[row][col] = count++ ;
}
}
print( a, numRows, numCols );
}
Another thing which you may be interested in is a structure like D3DMATRIX:
typedef struct _D3DMATRIX {
union {
struct {
float _11, _12, _13, _14;
float _21, _22, _23, _24;
float _31, _32, _33, _34;
float _41, _42, _43, _44;
};
float m[4][4];
};
} D3DMATRIX;
D3DMATRIX myMatrix ;
The sweet thing about this little tidbit is you can use both myMatrix.m[0][0] (to access the first element), or you can use myMatrix._11 to access that same element as well. The union is the secret.
#include<cstdio>
template <size_t N, size_t M>
struct DataHolder
{
int data[N][M];
DataHolder()
{
for(int i=0; i<N; ++i)
for(int j=0; j<M; ++j)
data[i][j] = 0;
}
};
template <size_t N, size_t M>
void print(const DataHolder<N,M>& dataHolder) {
printf("\n");
for(int i = 0; i<N; i++) {
for(int j = 0; j<M; j++) {
printf("%d, ", dataHolder.data[i][j]);
}
}
printf("\n");
}
int main() {
DataHolder<4,4> a;
print(a);
}
Aside from using variable-length arrays in C99, you can't really portably write a function to accept a multidimensional array if the sizes of the arrays are not known at compile-time, See Question 6.19 of the C-FAQ. The best way to handle this is to simulate multidimensional arrays using dynamically allocated memory. Question 6.16 does a very good job of explaining the details of doing this.
Short answer, you may change the program as following
void print(int arr[], int s1, int s2) {
...
printf("%d,", *(a+i + s2*j));
...
print((int*)a,4,4);
This would need a better answer explaining the differences between pointer and pointer arithmetic and arrays in C and C++. I won't launch into that now. Maybe someone else ?
I obviously am not shocked by the same point as other posters in your code. What bother me most in the print function header is that you use a double indirection for an array where you do not intend to change initial pointer back (in fact it can't be done as it is a constant). #|V|lad answer fix this by setting one or two dimensions to a fixed constant, but then passing s1 and s2 become useless.
All depends of what you really want to do. Is print a general purpose array printing function or a specialized one for some array types ?
First thing to do is get the types right. If C++'s rules are the same as C's with respect to array types (I'm pretty sure they are), then given the declaration
int a[4][4];
the expression a has type int [4][4], which is implicitly converted ("decays") to a pointer type of int (*)[4] (pointer to 4-element array of int) when passed to print, so you need to change print to
void print(int (*arr)[4], int s1, int s2)
{
int i, j;
for(i = 0; i<s1; i++)
for(j = 0; j<s2; j++)
printf("%d, ", arr[i][j]);
}
The expression arr[i] implicitly dereferences arr, so you don't need to mess with an explicit dereference.
The drawback is that print can only handle Nx4 arrays of int; if you want to handle other array sizes, you'll need to take a different approach.
One thing you can do is instead of passing the array, pass the address of the first element, and have print manually compute the offsets, as so:
int main() {
int a[4][4] = {{0}};
print(&a[0][0],4,4); // note how a is being passed
}
void print(int *arr, int s1, int s2) // note that arr is a simple int *
{
int i, j;
for (i = 0; i < s1; i++)
for (j = 0; j < s2; j++)
printf("%d, ", arr[i * s2 + j]);
}
#include<stdio.h>
void print(int (*arr)[4], int s1, int s2) {
int i, j;
for(i = 0; i<s1; i++)
for(j = 0; j<s2; j++)
printf("%d, ", arr[i][j]);
}
int main() {
int a[4][4] = {{6}};
print(a,4,4);
}
this will compile edit: someone already posted this solution my bad
Multidimensional arrays are continuous blocks of memory. So you can do it this way:
#include <stdio.h>
void pa(const int *a, int y, int x)
{
int i, j;
for (i=0;i<y;i++)
{
for (j=0;j<x;j++)
printf("%i", *(a+j+i*x));
printf("\n");
}
}
int main()
{
int a[4][3] = { {1,2,3},
{4,5,6},
{4,5,6},
{7,8,9} };
pa(a[0], 4, 3);
return 0;
}
It also works in C++;
As all(most) of the systems today is Row Major Ordered.
Here is a self-explanatory code, which takes the benefit of the concept that multi-dimensional arrays are also stored serially.
Sample working code:
#include<bits/stdc++.h>
using namespace std;
void print1DArray(int arr[]){
cout << "1D array print: " << arr[3] << endl;
}
int get1DIndex(int r, int c, int noOfColumns){
return r*noOfColumns + c;
}
void print2DArray(int *mat, int noOfColumns){
cout << "\n-------------------------------\n";
cout << "1D index generated: " << get1DIndex(1, 2, noOfColumns); // prints 5
cout << endl << "Inside printAllPaths: " << mat[get1DIndex(1, 2, noOfColumns)]; // prints 5
}
int main(){
int arr[5] = {0, 1, 2, 3, 4};
int mat[3][3] = { {0, 1, 2}, {3, 4, 5}, {6, 7, 8}};
print1DArray(arr);
print2DArray(*mat, 3);
return 0;
}
Youre code does not work in C, though it compiles with warnings. The basic problem is that you're passing the wrong type of pointer as the argument to print, so you get a warning. Your element calculation is also bogus.
You can rewrite it as
#include<stdio.h>
void print(int s1, int s2, int arr[s1][s2]) {
int i, j;
for(i = 0; i<s1; i++)
for(j = 0; j<s2; j++)
printf("%d, ", arr[i][j]);
}
int main() {
int a[4][4] = {{0}};
print(4,4,a);
}
and it will work, though only if you compile it as C. If you try to compile with a C++ compiler, it will not work.
If you really need your code to run in C too, you'll either need to:
Follow my other really stinking long and really thorough answer about C-style arrays, here, or:
Build up your own multi-dimensional array containers in C, from scratch.
However, if using C++, using a vector of vectors really is best for this! Hence, my new answer here:
How to pass a multidimensional array to a function in C++ only, via std::vector<std::vector<int>>&
If using C++, use a std::vector<> of std::vector<>s!:
// Example:
std::vector<std::vector<int>> array2d;
NB: see and run the full demo code used below in my eRCaGuy_hello_world repo here: array_2d_via_std_vector.cpp.
Example 1: pass it by reference: std::vector<std::vector<int>>&:
// Version 2: demonstrate passing the type withOUT the `array2d_t` type above,
// and iterating via range-based for loops.
void print_array2d_2(const std::vector<std::vector<int>>& array2d)
{
// Option 2: range-based for loops
// Iterate over all rows
size_t i_row = 0;
for (std::vector<int> row : array2d)
{
// Iterate over all columns
size_t i_col = 0;
for (int val : row)
{
printf("array2d[%zu][%zu]=%i ", i_row, i_col, val);
i_col++;
}
i_row++;
printf("\n");
}
printf("\n");
}
You can also typedef the type or use the using declaration to make the type easier to manage:
using array2d_t = std::vector<std::vector<int>>;
using grid_t = array2d_t; // alternative alias for a 2D array
// OR with typedef:
typedef std::vector<std::vector<int>> array2d_t;
typedef array2d_t grid_t; // alternative alias for a 2D array
Then pass it as array2d_t& or grid_t& or whatever. Here's another example:
// Version 1: demonstrate passing using the `array2d_t` above, and iterating
// using regular for loops.
void print_array2d_1(const array2d_t& array2d)
{
// Option 1: regular for loops
// Iterate over all rows
for (size_t i_row = 0; i_row < array2d.size(); i_row++)
{
// To get access to just a row, do this if you like
// const std::vector<int>* row = &array2d[i_row];
// row->size();
// Iterate over all columns
for (size_t i_col = 0; i_col < array2d[i_row].size(); i_col++)
{
printf("array2d[%zu][%zu]=%i ",
i_row, i_col, array2d[i_row][i_col]);
}
printf("\n");
}
printf("\n");
}
Generating arrays
Generating the arrays can be done at construction time:
// a regular 2 x 3 2D grid or array
array2d_t array2d_1 = {
{11, 12, 13},
{14, 15, 16},
};
print_array2d_1(array2d_1);
print_array2d_2(array2d_1);
printf("-------------\n\n");
Using a vector of vectors (std::vector<std::vector<int>>) also has the neat benefit of allowing you to have non-uniform multi-dimensional arrays. Ex: an array with 3 rows, and 3 columns in the first and last row, but 4 columns in the middle row:
// Notice that having varying numbers of columns in each row in
// `std::vector<>`-based 2D arrays is fine!
array2d_t array2d_2 = {
{1, 2, 3},
{4, 5, 6, 7},
{8, 9, 10},
};
print_array2d_1(array2d_2);
print_array2d_2(array2d_2);
printf("-------------\n\n");
You can also pre-size the array to have a certain number of rows and columns at construction, so that you can then populate it via the [][] operators after construction, like this:
constexpr size_t NUM_ROWS = 3;
constexpr size_t NUM_COLS = 4;
// By default, this creates a `NUM_ROWS x NUM_COLS` array with all zeros in
// it, since that is the default value for type `int` when called as a
// constructor-like default initializer, as in `int()`, which
// performs "value initialization". See my Q:
// https://stackoverflow.com/q/72367123/4561887
array2d_t array2d_4(NUM_ROWS, std::vector<int>(NUM_COLS));
// Let's just fill in a few of the values with non-zeros, as an example
array2d_4[0][0] = 1;
array2d_4[1][1] = 2;
array2d_4[2][2] = 3;
array2d_4[2][3] = 4;
// array2d_4[3][3] = 5; // UNDEFINED BEHAVIOR! OUT OF ROW BOUNDS! Results
// // in: `Segmentation fault (core dumped)`
print_array2d_1(array2d_4);
print_array2d_2(array2d_4);
printf("-------------\n\n");
Here's what the last printed output looks like from the code just above:
array2d[0][0]=1 array2d[0][1]=0 array2d[0][2]=0 array2d[0][3]=0
array2d[1][0]=0 array2d[1][1]=2 array2d[1][2]=0 array2d[1][3]=0
array2d[2][0]=0 array2d[2][1]=0 array2d[2][2]=3 array2d[2][3]=4
array2d[0][0]=1 array2d[0][1]=0 array2d[0][2]=0 array2d[0][3]=0
array2d[1][0]=0 array2d[1][1]=2 array2d[1][2]=0 array2d[1][3]=0
array2d[2][0]=0 array2d[2][1]=0 array2d[2][2]=3 array2d[2][3]=4
-------------
Just remember: using the brace operator ([]; AKA: operator[]) does NOT automatically allocate new space for a new member if you index outside the array. Rather, that is undefined behavior and will result in a segmentation fault! See here: https://en.cppreference.com/w/cpp/container/vector/operator_at (emphasis added):
Unlike std::map::operator[], this operator never inserts a new element into the container. Accessing a nonexistent element through this operator is undefined behavior.
Use .resize() to change the size, or .push_back() to auto-grow the array as you add new elements to it.
References
See the full demo code used above in my eRCaGuy_hello_world repo here: array_2d_via_std_vector.cpp
I just want to show C++ version of bobobobo's answer.
int numRows = 16 ;
int numCols = 5 ;
int **a ;
a = new int*[ numRows* sizeof(int*) ];
for( int row = 0 ; row < numRows ; row++ )
{
a[row] = new int[ numCols*sizeof(int) ];
}
The rest of code is the same with bobobobo's.

C++ two dimensional arrays with pointers

I have a problem with two dimensional arrays :( I feel very stupid and Visual C does not help me :( and I also think that my mistake is very stupid but still I can't find it :( I have this code:
double matrix[100][100]; //which is full with a matrix 3x4
double nVector[10000]; // for negative doubles
//I wanted to see if there are negative doubles in each row and column
//and I want this to happen with function
And this is my function:
double* negativeVector(double*nVector, double*fromVector, int m, int n){
int position = 0;
double *myNegArray = nVector;
double *myMatrix = fromVector;
for(int i = 0; i < m*n; i++)
if(*(*(myMatrix+i)) < 0){
*(myNegArray+position) = *(*(myMatrix+i));
position++;
}
return myNegArray;
}
//for double*nVector I'm passing nVector
//for double*fromVector I'm passing *matrix
Visual C tells me that I have an error C2100: illegal indirection here: *(*(myMatrix+i)) I hope someone can help me (happy)
Thanks in advance!
*(*(myMatrix+i)) is wrong. This is a common mistake.
2D matrix does not create an array of pointers which you can access this way. It is a different structure. Even though an array is a pointer, 2D array is not a pointer to pointer, and it cannot be dereferrenced twice. Nor you have any other way to access element at coordinates (x,y) without knowing the layout in memory, because pointers to every line are nowhere to be found. For instance, char **argv parameter of main() is not a 2D array. This is an array of pointers to arrays, which is something else.
There're two ways to fix it.
One is replace
double *myMatrix = fromVector;
by
double *myMatrix[100] = (appropriate cast)fromVector;
and index it as myMatrix[i/n][i%n]
But then remember that 100 is a constant expression, and it cannot be passed as a parameter. Alternatively, you can implement the indexing operation yourself:
Pass additional parameter: matrix line size (100)
Instead of *(*(myMatrix+i)), write:
int row = i/n;
int col = i%n;
*(myMatrix+row*line_size+col) is your element.
first you might wanna start a small struct like
struct tmp {
bool negative;
double value;
};
and make your own way up to the
tmp *myvars [100][100];
.
instead try using that struct and try the std::vectors instead of arrays if that's possible then try using pointers on decalring the variable "1 time only" when declaring the variable as i said above
then pass arguments
( tmp *mystructpointer )
mystructpointer->.......
access your matrix directly ... peice of cake :D
If you are passing *matrix, you are actually passing a double[100] (an array of 100 doubles), that happens to be passed as a pointer to its first element. If you advance further than those 100 doubles using i added to that pointer, you advance into the next array of 100 doubles, since the 100 arrays of 100 doubles are stored next to each other.
Background: A multi-dimensional array is an array whose element type is itself an array. An array like double a[100][100]; can be declared equivalently as typedef double aT[100]; aT a[100];. If you use an array like a pointer, a temporary pointer is created to the array's first element (which might be an array). The * operator is such an operation, and doing *a creates a pointer of type double(*)[100] (which is a pointer to an array of 100 doubles), and dereferences it. So what you end up with *matrix is a double[100]. Passing it to the negativeVector function will create a pointer to its first element, which is of type double*.
Your pointer parameters point to the start of each of two arrays of 100 doubles each. So you should rewrite the function as
double* negativeVector(double*nVector, double*fromVector, int m, int n){
int position = 0;
double *myNegArray = nVector;
double *myMatrix = fromVector;
for(int i = 0; i < m*n; i++)
if(*(myMatrix + i) < 0){
*(myNegArray + position) = *(myMatrix + i);
position++;
}
return myNegArray;
}
Notice that since your i iterates beyond the first of the 100 arrays stored in the 2d array, you will formally not be correct with this. But as it happens those arrays must be allocated next to each other, it will work in practice (and in fact, is recommended as a good enough work around for passing multi-dimensional arrays around as pointers to their first scalar element).
I have no clue why you are copying the arrays twice (once in the parameters of the function and a second time by declaring some new arrays)... You should also think of using the STL... std::vector will make the your life way easier ;)
double* negativeVector(double*nVector, double*fromVector, int m, int n){
int position = 0;
double *myNegArray = nVector;
double *myMatrix = fromVector;
for(int i = 0; i < m*n; i++)
if(*((myMatrix+i)) < 0){
*(myNegArray+position) = *((myMatrix+i));
position++;
}
return myNegArray;
}
is that homework? some templates - just for fun ;-)
double matrix[100][100];
double nVector[10000];
template< const int m, const int n >
double* negativeVector( double* myNegArray, const double (&myMatrix)[m][n] )
{
int position = 0;
for( int i = 0; i < m; ++i )
{
for( int j = 0; j < n; ++j )
{
const double value = myMatrix[ i ][ j ];
if ( value < 0 )
{
myNegArray[ position ] = value;
++position;
}
}
}
return myNegArray;
}
int main()
{
//...initialize matrix here...
negativeVector( nVector, matrix );
}
Perhaps rewrite this using std::vector to increase readability? (#):
#include <vector>
std::vector< std::vector<double> > matrix; //which is full with a matrix 3x4
std::vector<double> row;
row.resize(100,0);
matrix.resize(100,row);
std::vector<double> nVector; // for negative doubles, no size, we'll "push_back"
//I wanted to see if there are negative doubles in each row and column
//and I want this to happen with function
This is the stl enabled version of the function:
//I'm returning void because nvector contains the result,
//so I don't feel the need to return anything. vectors contain their
//own size so n and m are also not needed. Alsom pass in references
void negativeVector(std::vector<double>& nVector,
std::vector< std::vector<double> >& fromVector){
nVector.clear();
int i,j;
for(i = 0; i < fromVector.size(); i++) {
for(j = 0; j < fromVector[i].size(); j++) {
if(fromVector[i][j] < 0){
nVector.push_back(fromVector[i][j]);
}
}
}
}
call with:
negativeVector(nVector, matrix);
Once the function completes, nVector contains all negative numbers in matrix.
Read more about std::vector here.
(#) for people like me who are too lazy/stupid to comprehend code containing pointers.
Take a look at C++ Faq site:
How do I allocate multidimensional arrays using new?
link
And read until point [16.20] summarize all the answers you are getting and at the end you get a very useful Matrix template class.
Have a good read.

Passing a variable of type int[5][5] to a function that requires int**

I'd like to test a function that takes runtime-allocated multidimensional arrays, by passing it a hardcoded array.
The function has a signature of void generate_all_paths(int** maze, int size) and the array is defined as int arr[5][5] = {REMOVED}.
I'm not exactly sure how to properly coerce the array for the function (or if that is impossible).
This multi dimensional array topic unfortunately confuses so many C++ programmers. Well, here is the solution:
void generate_all_paths(int (*maze)[5], int size);
That is what the function declaration has to look like. An alternative, but fully equivalent is
void generate_all_paths(int maze[][5], int size);
Both are creating a parameter that is a pointer to an array of 5 integers. You can then pass your array of arrays of 5 integers to that function:
generate_all_paths(arr, 5);
Because your array's first element is an array of 5 integers, it will be converted automatically (implicitly) to a pointer to that first element when passed to that function.
In the comments, you have shown you are bound to an int**, because both your inner and outer dimension must have runtime values. A multi-dimensional array can not be used anymore. What you can do for testing purposes then is to create an array of pointers like this:
int store[5 * 5] = { ..... };
int *arr[5] = { store, store + 5, store + 10, store + 15, store + 20 };
Then, actually, you can have your function accept a int**. As the first element of you array then is a int*, it will be converted to a int** automatically. Another way of doing this is keeping the data in the 2 dimensional array, but just creating a "view" structured of pointers to that array:
int *arr[5] = { store[0], store[1], store[2], store[3], store[4] };
Where store is your int[5][5] array. Since store[n] accesses the n'th sub-array of that two-dimensional array and the element type of it is int, the pointer-converted type of it is int*, which will be compatible again.
You can write:
void display(char **a)
And then use a[i][j] to refer to elements in it.
The declaration char ** means "pointer to pointer to integer". To break it down into steps:
char *b = a[i];
That gets you a pointer to the first element of the i'th array in the array-of-arrays.
char c = b[j];
That gets you the j'th element in the array b.
The next problem you'll have is of allocating such an array-of-arrays.
char **arrayOfArrays = new char *[10];
for (int n = 0; n < 10; n++)
arrayOfArrays[n] = new char[20];
That allocates an array of 10 arrays, each "child" array having 20 characters.
In C/C++, array access syntax is just a way of retrieving a value some distance away from a pointer.
char *p = "Hello";
char *pl = p + 2; // get pointer to middle 'l'
char l = *pl; // fetch
char o = p[4]; // use array syntax instead
void display(char ** array)
should work. Also I don't think that it is a reserved word in standard C/C++.
And also, why is array a reserved word?
It isn't. You are probably using Visual Studio where it's displayed as a keyword due to its use in C++/CLI as a native managed type. However, this is irrelevant for C++ and Visual Studio is misleading in that regard.
As to your problem: You can simply pass a pointer-to-pointers-to-char and then pass your nested array directly (provided you are working with a dynamically allocated array):
void display(char** array) …
That said, your function assumes a fixed, known array length and some other details. Better would be to use a nested std::vector, or std::string (for instance). Using such existing data types makes your life much easier.
void display(std::vector<std::string> const& array) {
for (size_t i = 0; i < array.length(); ++i)
cout << array[i] << endl;
}
To take advantage of this, your calling code needs to be changed as well to use these data structures instead of plain C arrays on chars.
The Earwicker's answer is missing an important fact. What he is proposing is an array of arrays. For the first this wastes memory for the array of pointers ("char **arrayOfArrays = new char *[10]" is the creation point of this). For the second the array of chars may then not be a continuous block of memory, which is often a problem.
The only workaround in C++ is to create a one dimensional array and calculate the indexes when you need them.
char *b = new char[width*height];
then you can refer to element x,y (x is along width, y along height) like this
char c=b[width*y+x];
This may be however a bit slower than the solution above (measured on GCC 3.4.5), so if you are not interested in continuous memory (for example you always access the elements with [][], never by adding integer to a pointer and dereferencing it), then you should use the array af arrays. However, if you are interested in having the continuous memory, e.g. to pass it as initializer to an std::string object or to send it as a whole through a network, you should use the second one.
The best is to use pointers, but Borland C++ admits passing arrays as parameters for functions. Look at this code (includes: iostream and conio):
////////////////////////////////////////////
void ReceivedArray(char x[5]){
for (int i=0; i<5; i++ )
cout << x[i];
}
void main(){
char *x = new char[5];
for (int i=0; i<5; i++ )
x[i]='o';
ReceivedArray(x);
getchar();
}
///////////////////////////////////////////////////////////////
For passing 2D arrays (oops! some lines in spanish, sorry!):
(includes: iostream, stdlb, stdio and math)
/////////////////////////////////////////////////
using namespace std;
void ver(int x[][20]){
for(int i=0; i<15; i++) {
for(int j=0; j<20; j++) {
cout<< x[i][j] <<" "; }
cout << "\n"; }
}
void cambiar0(int x[][20]){ int n[255];
for (int i=255; i>=0; i--)
n[255-i]=i;
for(int i=0; i<15; i++)
for(int j=0; j<20; j++)
for(int k=0; k<255; k++)
if(x[i][j]==n[k]) {
x[i][j]=k; break; }
}
int main(int argc, char* argv[]){
int x[15][20]; char a;
for(int i=0; i<15; i++)
for(int j=0; j<20; j++)
x[i][j]=rand()%255;
cout << "¿desea ver la matriz? s/n ";
cin >> a;
if(a=='s') ver(x);
cambiar0(x);
cout << "\n\n";
cout << "¿desea ver la matriz? s/n ";
cin >> a;
if(a=='s') ver(x);
system("PAUSE"); return 0;
}
///////////////////////////////////
Hope this is what you meant.
arr is a pointer to the multi-dimesional array you have and is actually a pointer to an int. Now since your function accepts a pointer to an int pointer, you need to get the address of arr using: &arr and pass that to the function so that you will have this code:
To coerce the array: Pass &arr to the function.
To reference the array inside the func: *maze[x][y]