I am trying to globally define a multidimensional array. The dimensions will ultimately depend on some other computations. Here I'll just consider n and B to be 5 but I place them inside function2 to stress that the dimensions are not known initially. At some point I'll also need to duplicate this array. The code below gives the error Subscripted value is not an array, pointer, or vector on the line where I'm printing the array2 entries. How can I fix this error and is there anything else I need to change to accomplish this?
int n,B;
double ** array;
double ** array2;
void function(){
double array[n][B][n];
for(int i = 1; i <= n; i++){
for(int j = 1; j <= B; j++){
for(int k = 1; k <= n; k++){
array[i-1][j-1][k-1] = i*j*k;
}
}
}
}
void function2(){
n=5;
B = 5;
function();
array2 = array;
for(int i = 1; i <= n; i++){
for(int j = 1; j <= B; j++){
for(int k = 1; k <= n; k++){
printf("%lf",array2[i-1][j-1][k-1]);
}
}
}
}
int main(){
function2();
return 0;
}
Oops... I am trying to globally define a multidimensional array. The dimensions will ultimately depend on some other computations... Don't. At least do not try that in C language. Arrays are not first class citizens in C, not speaking of multi-dimensional ones. Said differently AFAIK, there is no way in C to declare a multi-dimensional array where all dimensions but the last one are not compile time constants.
But there are another problems in your code: double ** array; at global level declares a pointer to pointer (or a pointer to array) which is a totally different animal than a multi-dimensional array. And double array[n][B][n]; (wrongly) declares a totaly independant multi-dim. array, hiding the global symbol.
So my advice is:
avoid if possible globaly defined variables. There are indeed correct use cases but most of the time, it is cleaner to pass them as parameter of functions, possibly inside structs
make your choice between a multi-dimensional array and an array of pointers. The former is a consecutive containers where all dimensions but the last have to be constant, the latter if much more versatile, because each row could have a different size. But it is slightly more complex to declare and slightly less efficient.
int a1[5], a2[6], a3[7];
int **parray = {a1, a2, a3};
elt_i_j = parray[i][j];
do not forget about the good old idiom allowing to see a 1-D array as a multi-dim one:
size_t size1, size2, size3;
// compute the sizes...
int *array = malloc(size1, size2, size3);
elt_i_j_k = array[k + size2 * (j + size1 * i)]
Good luck in learning C arrays...
First note that in function2 :
function();
array2 = array;
array refers to the global variable, while function initialized its local variable array and not the global one. So array and array value NULL
Subscripted value is not an array, pointer, or vector
array2 is only known as double ** array2; so array2[i-1][j-1][k-1] cannot be resolved because it needs at least the last two dimensions. Note also it is strange to use a double pointer for a 3D array.
If you want to use array2 supposing it is in fact double array2[n][B][n] you can cast it as double (*)[B][n], but in your code array2 is NULL. Or of course you have array2 as a double * and you compute yourself the right offset to access the double you want
First thing, arrays in C are stored in contiguous memory locations. So if you do not provide the number of rows or the number of columns, how will the compiler know how many rows and columns there are?
So, you have to specify the rows and columns at the start.
However, you can have some workaround. Refer to this Initializing Arrays in C/C++ With Unknown Size
There are few issues in the code which you should have a look at:
functions() has a local declaration of array2. So,
double ** array2;
and
array2 = array;
are different.
You can't assign arrays in C. You can copy them with the memcpy() function, declared in string.h as follows:
memcpy(&array2, &array, sizeof array2);
array2 is declared as double ** array2; so array2[i-1][j-1][k-1] cannot be resolved.
Happy coding!
Related
I can pass int arrays to both of these functions (1d and 2d arrays). What is the difference between them? With the second function you need to specify the size of the array. Why?
void foo(int *a, int cols)
void bar(int (*a)[N])
I have a program where I want to pass 2d int arrays to functions. Which is the better one to use and does it matter?
There are significant differences difference between these methods for 2D matrices
in the first method you pass a pointer to int, which is not the proper type for the matrix, even after implicit decaying.
cols is an int argument in the first prototype, whereas it is a constant N in the second one. In both cases, the number of rows is not specified, so it must be implicit, either because it is constant or because the matrix is square.
You will need to write the index computations explicitly in the first case and you can use a[row][col] in the second, which will be simpler, more readable and compile to more efficient code.
Note that since C99, there is a 3rd possibility allowing you to use the array syntax even for a variable number of columns. Here is an example:
#include <stdio.h>
#include <stdlib.h>
void init_matrix(int rows, int cols, int (*a)[cols]) {
int x = 0;
for (int r = 0; r < rows; r++) {
for (int c = 0; c < cols; c++) {
a[r][c] = x++;
}
}
}
void print_matrix(int rows, int cols, const int (*a)[cols]) {
for (int r = 0; r < rows; r++) {
for (int c = 0; c < cols; c++) {
printf("%3d%c", a[r][c], " \n"[c == cols - 1]);
}
}
}
int main() {
int cols = 4, rows = 3;
int (*a)[cols] = malloc(sizeof(*a) * rows);
init_matrix(rows, cols, a);
print_matrix(rows, cols, a);
return 0;
}
Difference between int* a and int (*a)[N] in functions?
While int* a is a pointer to int, int (*b)[N] is a pointer to an array of N ints. These are different types, and are not compatible.
b can only point to an array of N ints while a can point to an int wether it's in an array or not. When you pass an array as argument you are really passing a pointer to its first element, it's commonly said that it decays to a pointer. Another difference is that if you increment b it will point to the next block of N ints whereas if you increment a it will just point to the next int.
I have a program where I want to pass 2d int arrays to functions. Which is the better one to use and does it matter?
It matters, for foo, it hints to a flat array with cols width, of course with some arithmetic you can treat it as a 2D array, bar is a more natural use for a 2D array.
The memory layout will probably be the similar, and using a flat array to store elements in such a way that you can use it as a 2D array is perfectly fine. I personally find it less messy and more clear to use a pointer to array, instead of pointer to int, when I need a 2D array.
Example:
#include <stdio.h>
#include <stdlib.h>
#define N 5
#define M 5
void bar(int (*a)[N]) {
// prints 20, 4 bytes * 5 (can be different deppending on the size of int)
printf("Size of 'a' is %zu\n\n", sizeof *a);
// populate the array
int c = 1;
for (int i = 0; i < N; i++)
for (int j = 0; j < M; j++)
a[i][j] = c++;
for(int i = 0; i < N; i++){
printf("a[%d][0] = %2d\n", i, **a);
// incrementing 'a' will make it point to the next array line
a++;
}
putchar('\n');
}
Output:
Size of a is 20
a[0][0] = 1
a[1][0] = 6
a[2][0] = 11
a[3][0] = 16
a[4][0] = 21
int main() {
int(*a)[N] = malloc(sizeof *a * M);
bar(a);
// prints the complete array
for (int i = 0; i < N; i++) {
for (int j = 0; j < M; j++) {
printf("%2d ", a[i][j]);
}
putchar('\n');
}
free(a);
}
In this code a is a 2D array N x M which is passed to bar to be populated. I added some handy prints and comments for clarification. See it live: https://godbolt.org/z/1EfEE5ed7
Output:
1 2 3 4 5
6 7 8 9 10
11 12 13 14 15
16 17 18 19 20
21 22 23 24 25
With the second function you need to specify the size of the array. Why?
You don't have to specify the entire size of the entire 2D array, but you do have to specify the number of columns, i.e. the size of the sub-array.
The reason why the compiler must know the size of the sub-array is that this information is required for offset calculations.
For example, if you define a 2D array like this
int arr[2][4];
then the array elements will be stored in memory in the following order:
arr[0][0]
arr[0][1]
arr[0][2]
arr[0][3]
arr[1][0]
arr[1][1]
arr[1][2]
arr[1][3]
If the compiler wants to for example access arr[1][2], it will need to know how many columns there are per row, i.e. how big each sub-array is. If the compiler does not know that there are 4 columns per row, then the compiler has no way of knowing where to find arr[1][2]. However, if the compiler knows that there are 4 columns per row, it will know that the 5th element of the 2D array is the start of the second row, so it will know that arr[1][2] is the 7th element of the 2D array.
I can pass int arrays to both of these functions (1d and 2d arrays).
Although accessing a 2D array as a 1D array may work on most compilers, it is undefined behavior according to the ISO C standard. See this question for further information:
One-dimensional access to a multidimensional array: is it well-defined behaviour?
Which is the better one to use and does it matter?
The first one is better in the sense that it allows you to specify the number of columns at run-time, whereas with the second one, the number of columns must be set at compile-time, so you are less flexible.
However, as stated above, depending on your compiler, it may not be safe to access a 2D array as a 1D array. Therefore, it would probably be best to pass 1D arrays to the first function and 2D arrays to the second function.
However, it is not clear how the second function is supposed to know how many rows the 2D array contains, since this information is not passed to the function as an argument. Maybe the function is assuming a fixed number of rows, or maybe it is not intended to be used for 2D arrays at all. The information that you have provided in the question is insufficient to answer this.
I am trying to print a 2D matrix with using [], instead I want to use * like a pointer.
So with a 1 D array I'd do: *(arr+i) for example.
What's the syntax used to replace in matrix[][] ?
Here's the code:
for (i = 0; i < size; i++)
{
for (j = 0; j < (size * 2); j++)
{
printf(" %5d", matrix[i][j]);
}
printf("\n");
}
P.S,
I did try several things like:
*(matrix+i+j);
*(matrix+i)+*(matrix+j);
Of course none of that worked.
Thank you for your help and time!
Use the * two times. Each of * will basically replace one []:
*(*(matrix+i)+j)
You can try this-
*(*(matrix+i)+j) //reduce level of indirection by using *
This may depend on how matrix was allocated or passed to a function.
int A[10][15];
This uses a contiguous block of memory. To address the elements without using array notation use:
A +(i*15)+j // user694733 showed this is wrong
((int *)A)+(i*15)+j // this is horribly ugly but is correct
Note the 15, as each row consists of 15 elements. Better solutions are presented in other answers here.
In the following:
int *A[10];
A is an array of 10 pointers to ints. Assuming each array element has been allocated using malloc, you address the elements without using array notation as:
*(A+i) + j;
that is, you take A, then take the ith element, dereference that and add j as the second index.
--EDIT--
And to be complete:
int foo(int *p)
here a function just receives a pointer to zero or more ints. The pointer points to a contiguous, linear block of memory into which you can place an n-dimensional array. How many dimensions there are and the upper bound of each dimension the function can only know through parameters or global variables.
To address the cells of the n-dimensional array, the programmer must calculate the addresses him/herself, using the above notation.
int foo3(int *m, int dim2, int dim3, int i, int j, int k)
{
int *cell = m + i*dim3*dim2 + j*dim2 + k;
return *cell;
}
In C, because of the framework I use and generate though a compiler, I am required to use global variable length array.
However, I can not know the size of its dimension until runtime (though argv for example).
For this reason, I would like to declare a global variable length array with unknown size and then define its size.
I have done it like that :
int (*a)[]; //global variable length array
int main(){
//defining it's size
a = (int(*)[2]) malloc(sizeof(int)*2*2);
for(int i=0;i<2; i++){
for(int j=0;j<2; j++){
a[i][j] = i*2 + j;
}
}
return 0;
}
However, this does not work : I get the invalid use of array with unspecified bounds error. I suspect it is because even if its size is defined, its original type does not define the size of the larger stride.
Does someone know how to solve this issue ? Using C99 (no C++) and it should be quite standard (working on gcc and icc at least).
EDIT: I may have forget something that matters. I am required to propose an array that is usable through the "static array interface", I mean by that the multiple square bracket (one per dimension).
First a is not an array but a pointer to an array of unspecified length. What you are trying to do is not possible. You can't have a global variable length array.
But with the present scenario you can use this to access the memory allocated to a
for(int i=0;i<2; i++){
int *ptr = *a + 2*i;
for(int j=0;j<2; j++){
ptr[j] = i*2 + j;
}
}
You cannot declare a global multi dimensional VLA, because even if you use pointers, all the dimensions except for the first one must be known at declaration time.
My best attempt would be to use a global void *. In C void * is a special pointer type that can be used to store a pointer to any type, and is often used for opaque pointers.
Here you could do:
void *a; // opaque (global variable length array) pointer
int main() {
//defining it's size
a = malloc(sizeof(int) * 2 * 2); // the global opaque pointer
int(*a22)[2] = a; // a local pointer to correct type
for (int i = 0; i<2; i++) {
for (int j = 0; j<2; j++) {
a22[i][j] = i * 2 + j;
}
}
return 0;
}
When you need to access the global VLA, you assign the value of the opaque global to a local VLA pointer, and can then use it normally. You will probably have to store the dimensions in global variables too...
An example to illustrate:
#include <stdlib.h>
#include<stdio.h>
void simple_function(int s , int array[][s]);
int main(void){
int x;
/*Static 2D Array*/
int array[2][2];
/*Many Methods to Dynamically Allocate 2D Array....for example*/
/* Using Array of pointers*/
int *array1[2];
for(x=0;x<2;x++){array1[x] = calloc (2, sizeof(int));}
/*Using pointer to a pointer */
int **array2 = calloc (2, sizeof(int*));
for(x=0;x<2;x++){array2[x] = calloc (2, sizeof(int));}
/*Using a single pointer*/
int *array3 = calloc (4 , sizeof(int));
/* Codes To Fill The Arrays*/
/*Passing the Arrays to the function, some of them won't work*/
simple_function(2, array); /*Case 1*/
simple_function(2, array1); /*Case 2*/
simple_function(2, array2); /*Case 3*/
simple_function(2, array3); /*Case 4*/
return 0;
}
void simple_function (int s, int array[][s]){
int x,y;
for(x=0;x<s;x++){
for(y=0;y<s; y++){
printf ("Content is %d\n", array[x][y]);
}
}
}
My Question:
Is there a way to write the signature of the simple_function to let it accepts all cases regardless of the method that the user chose? If not, what is the most preferable for the function if I want to make a library?
You've actually declared two different types of objects, as shown below
Your array and array3 are both stored in memory as 4 contiguous ints. There's no additional information, you've simply reserved space for 4 ints, and the C specification requires that they are contiguous.
However, array1 and array2 are actually pointer arrays. Your code reserves memory for an array of two pointers, and each pointer points to an array of two ints. The ints will be arranged in groups of two, but the groups can be scattered anywhere in memory.
From this, it should be clear that the compiler cannot use the same code to access both types of array. For example, let's say that you're trying to access the item at array[x][y]. With a contiguous array, the compiler computes the address of that item like this
address = array + (x * s + y) * sizeof(int)
With a scattered array, the compiler computes the address like this
pointer = the value at {array + x * sizeof(int *)}
address = pointer + y * sizeof(int)
So you need two functions to handle those two cases. For the contiguous array, the function looks like this
void showContiguousArray( int s, int array[][s] )
{
for ( int x=0; x<s; x++ )
for ( int y=0; y<s; y++ )
printf( "array[%d][%d] = %d\n", x, y, array[x][y] );
}
For the scattered array, the function is
void showScatteredArray( int s, int **array )
{
for ( int x=0; x<s; x++ )
for ( int y=0; y<s; y++ )
printf( "array[%d][%d] = %d\n", x, y, array[x][y] );
}
Notice that those functions are identical, except for one thing, the type of the array argument. The compiler needs to know the type in order to generate the correct code.
If the array is declared in the same scope where it's used, then all of these details are hidden, and it seems that you're using the exact same code to access different types of arrays. But that only works because the compiler knows the type of the array from the earlier declaration. But if you want to pass the array to a function, then the type information must be explicitly specified in the function declaration.
Is there a way to write the signature of the simple_function to let it accepts all cases regardless of the method that the user chose?
"All the cases" apparently describes the different declarations array, array1, array2, and array3, the latter three of which are described in code comments as "Methods to Dynamically Allocate 2D Array." But none of the four types are the same as any of the others, and none of the latter three in fact declare 2D arrays nor pointers to such. None of them are even compatible with each other. Of the dynamic ones, only array3 can even usefully be converted to something comparable to array.
A dynamically-allocated 2D array would be referenced via a pointer of this type:
int (*array4)[2];
array4 = calloc(2 * sizeof(*array4));
So, no.
If not, what is the most preferable for the function if I want to make a library?
It depends on your objectives. If your function must be compatible with static 2D arrays, then something of the general form you presented, plus or minus the variable dimension, is the only alternative. If you want to support the pointer-to-pointer form, then that's fine, and usable with declarations like array1's and array2's, but not with array, array3, or array4.
Assuming that you want this for 2D arrays, perhaps this can get you started ...
void simple_function(int s, int t , int* array) {
int i, j;
for (i=0; i<s; i++) {
for (j=0; j<t; j++) {
// accessing your array elements
printf(" %d", *(array + i*t + j));
}
printf("\n");
}
}
int main(void)
{
int array[2][3];
array[0][0] = 1;
array[0][1] = 2;
array[0][2] = 3;
array[1][0] = 11;
array[1][1] = 12;
array[1][2] = 13;
array[2][0] = 21;
array[2][1] = 22;
array[2][2] = 23;
simple_function(3, 3 , array);
return 0;
}
The expression int **array2 is not a 2D array by the way, it is a variable that holds the address of a pointer variable.
I'm trying to do something as followed
float* A = fill_float(); //in other words A is full
float aIn2D[n/p][n] = &A; //the 2d array should be able to alter the 1d
I tried the above but wouldn't compile (something about not being able to make the size variable length?). also tried
float** aIn2D = &A
But in retrospect that was nonsensical as how would the float** magically know I want a row, column distribution of [n/p][n] (i don't think it does since the program crashes right at the first access of aIn2D).
So does anyone know how to do something like float aIn2D[n/p][n] = &A; in c?
edit: One more thing, I for sure know the size from [n/p][n] is going to be the size of the amount of data A is holding.
edit2: A very big aspect is that both arrays point to the same memory location, aIn2D is just a way for me to easily access A in methods that follow.
Assuming n_rows and n_cols are variables, let's say you have an n_rows*n_cols 1D array of floats that you want to treat as an n_rows x n_cols 2D array.
With C99, which supports variable-sized arrays, you actually can do pretty much what you want:
float* A = fill_float();
float (*aIn2D)[n_cols] = (float (*)[n_cols])A;
Otherwise, you can do something like this:
float *A = fill_float();
float **aIn2D = malloc(n_rows*sizeof(float*));
{
int i=0;
for (; i!=n_rows; ++i) {
aIn2D[i] = A + i*n_cols;
}
}
// Use aIn2D[row][col]
free(aIn2D);
If you want to convert 2-D array to 1-D then you should try like this :
float a[MAX];
float dup_a[ROW][COL];
int i,j,k;
for(i = 0 ; i < MAX ; i++)
{
j= i / ROW ; // you can do it by i / COL also
k= i % ROW ; // you can do it by i % COL also
dup_a[j][k] = a[i];
}
Or, you can try this ,
float* A = fill_float();
float (*aIn2D)[n] = &A; // create a pointer to an array