I need to pass a 2D array to a function.
#include <stdio.h>
#define DIMENSION1 (2)
#define DIMENSION2 (3)
void func(float *name[])
{
for( int i=0;i<DIMENSION1;i++){
for( int j=0;j<DIMENSION2;j++){
float element = name[i][j];
printf("name[%d][%d] = %.1f \n", i, j, element);
}
}
}
int main(int argc, char *argv[])
{
float input_array[DIMENSION1][DIMENSION2] =
{
{0.0f, 0.1f, 0.2f},
{1.0f, 1.1f, 1.2f}
};
func(input_array);
return 0;
}
Dimensions vary depending on the use case, and the func should stay the same.
I tried the above int func(float *[]) but compiler complains expected ‘float **’ but argument is of type ‘float (*)[3]’, and also I get the segmentation fault error at runtime when trying to access the array at element = name[i][j].
What would be the proper signature of my function? Or do I need to call the func differently?
You can use the following function prototype:
int func(int dim1, int dim2, float array[dim1][dim2]);
For this you have to pass both dimensions to the function (you need this values anyhow in the function). In your case it can be called with
func(DIMENSION1, DIMENSION2, input_array);
To improve the usability of the function call, you can use the following macro:
#define FUNC_CALL_WITH_ARRAY(array) func(sizeof(array)/sizeof(*(array)), sizeof(*(array))/sizeof(**(array)), array)
Then you can call the function and it will determine the dimensions itself:
FUNC_CALL_WITH_ARRAY(input_array);
Full example:
#include<stdio.h>
#include <stdlib.h>
#include <string.h>
#define FUNC_CALL_WITH_ARRAY(array) func(sizeof(array)/sizeof(*(array)), sizeof(*(array))/sizeof(**(array)), array)
int func(int dim1, int dim2, float array[dim1][dim2])
{
printf("dim1 %d, dim2 %d\n", dim1, dim2);
return 0;
}
#define DIMENSION1 (4)
#define DIMENSION2 (512)
int main(int argc, char *argv[])
{
float input_array[DIMENSION1][DIMENSION2];
FUNC_CALL_WITH_ARRAY(input_array);
float input_array2[7][16];
FUNC_CALL_WITH_ARRAY(input_array2);
}
Will print
dim1 4, dim2 512
dim1 7, dim2 16
Dimensions vary depending on the use case, and the func should stay the same.
Use VLA:
void func (int r, int c, float arr[r][c]) {
//access it like this
for (int i = 0; i < r; ++i) {
for (int j = 0; j < c; ++j) {
printf ("%f\n", arr[i][j]);
}
}
}
// call it like this
func (DIMENSION1, DIMENSION2, input_array);
You can change your function like this;
int func(float (*arr)[DIMENSION2])
{
}
But also you should change your main code like this;
float input[DIMENSION1][DIMENSION2];//I just upload the dimension1 to dimension2
As noted above in the comment, the key problem is that int func(float *name[]) declares name to be an array of pointers to float.
In this sense, the following modification to main() works:
int main(int argc, char *argv[])
{
float input_array[DIMENSION1][DIMENSION2] =
{
{0.0f, 0.1f, 0.2f},
{1.0f, 1.1f, 1.2f}
};
/* Declare an array of pointers, as this is what func requires at input: */
float* in_p[DIMENSION1];
/* ... and initialize this array to point to first elements of input array: */
for( int i=0;i<DIMENSION1;i++)
in_p[i] = input_array[i];
/* ... and send this array of pointers to func: */
func(in_p);
return 0;
}
This is going to present a very old solution, one that works on every C compiler that exists. The idea goes something like this:
I have multiple pieces of information to keep track of
I should keep them together
This leads us to the idea that we can use a composite type to hold all the related information in one place and then treat that object as a single entity in our code.
There is one more pebble in our bowl of sand:
the size of the information varies
Whenever we have varying-sized objects, dynamic memory tends to get involved.
Arrays vs Pointers
C has a way of losing information when you pass an array around. For example, if you declare a function like:
void f( int a[] )
it means exactly the same thing as:
void f( int * a )
C does not care that the size of the array is lost. You now have a pointer. So what do we do? We pass the size of the array also:
void f( int * a, size_t n )
C99 says “I can make this prettier, and keep the array size information, not just decay to a pointer”. Okay then:
void f( size_t dim1, size_t dim2, float array[dim1][dim2] )
We can see that it is pretty, but we still have to pass around the array’s dimensions!
This is reasonable, as the compiler needs to make the function work for any array, and array size information is kept by the compiler, never by executable code.
The other answers here either ignore this point or (helpfully?) suggest you play around with macros — macros that only work on an array object, not a pointer.
This is not an inherently bad thing, but it is a tricky gotcha: you can hide the fact that you are still individually handling multiple pieces of information about a single object,
except now you have to remember whether or not that information is available in the current context.
I consider this more grievous than doing all the hard stuff once, in one spot.
Instead of trying to juggle all that, we will instead use dynamic memory (we are messing with dynamic-size arrays anyway, right?)
to create an object that we can pass around just like we would with any other array.
The old solution presented here is called “the C struct hack”. It is improved in C99 and called “the flexible array member”.
The C struct hack has always worked with all known compilers just fine, even though it is technically undefined behavior.
The UB problem comes in two parts:
writing past the end of any array is unchecked, and therefore dangerous, because the compiler cannot guarantee you aren’t doing something stupid outside of its control
potential memory alignment issues
Neither of these are an actual issue. The ‘hack’ has existed since the beginning (much to Richie’s reported chagrin, IIRC), and is now codified (and renamed) in C99.
How does this magic work, you ask?
Wrap it all up in a struct:
struct array2D
{
int rows, columns;
float values[]; // <-- this is the C99 "flexible array member"
};
typedef struct array2D array2D;
This struct is designed to be dynamically-allocated with the required size. The more memory we allocate, the larger the values member array is.
Let’s write a function to allocate and initialize it properly:
array2D * create2D( int rows, int columns )
{
array2D * result = calloc( sizeof(array2D) + sizeof(float) * rows * columns, 1 ); // The one and only hard part
if (result)
{
result->rows = rows;
result->columns = columns;
}
return result;
}
Now we can create a dynamic array object, one that knows its own size, to pass around:
array2D * myarray = create2D( 3, 4 );
printf( "my array has %d rows and %d columns.\n", myarray->rows, myarray->columns );
free( myarray ); // don’t forget to clean up when we’re done with it
The only thing left is the ability to access the array as if it were two-dimensional.
The following function returns a pointer to the desired element:
float * index2D( array2D * a, int row, int column )
{
return a->values + row * a->columns + column; // == &(a->values[row][column])
}
Using it is easy, if not quite as pretty as the standard array notation.
But we are messing with a compound object here, not a simple array, and it goes with the territory.
*index2D( myarray, 1, 3 ) = M_PI; // == myarray[ 1 ][ 3 ] = M_PI
If you find that intolerable, you can use the suggested variation:
float * getRow2D( array2D * a, int row )
{
return a->values + row * a->columns; // == a->values[row]
}
This will get you “a row”, which you can array-index with the usual syntax:
getRow2D( myarray, 1 )[ 3 ] = M_PI; // == myarray[ 1 ][ 3 ] = M_PI
You can use either if you wish to pass a row of your array to a function expecting only a 1D array of floats:
void some_function( float * xs, int n );
some_function( index2D( myarray, 1, 0 ), myarray->columns );
some_function( getRow2D( myarray, 1 ), myarray->columns );
At this point you have already seen how easy it is to pass our dynamic 2D array type around:
void make_identity_matrix( array2D * M )
{
for (int row = 0; row < M->rows; row += 1)
for (int col = 0; col < M->columns; col += 1)
{
if (row == col)
*index2D( M, row, col ) = 1.0;
else
*index2D( M, row, col ) = 0.0;
}
}
Shallow vs Deep
As with any array in C, passing it around really only passes a reference (via the pointer to the array, or in our case, via the pointer to the array2D struct).
Anything you do to the array in a function modifies the source array.
If you want a true “deep” copy of the array, and not just a reference to it, you still have to do it the hard way.
You can (and should) write a function to help.
This is no different than you would have to do with any other array in C, no matter how you declare or obtain it.
array2D * copy2D( array2D * source )
{
array2D * result = create2D( source->rows, source->columns );
if (result)
{
for (int row = 0; row < source->rows; row += 1)
for (int col = 0; col < source->cols; col += 1)
*index2D( result, row, col ) = *index2D( source, row, col );
}
return result;
}
Honestly, that nested for loop could be replaced with a memcpy(), but you would have to do the hard stuff again and calculate the array size:
array2D * copy2D( array2D * source )
{
array2D * result = create2D( source->rows, source->columns );
if (result)
{
memcpy( result->values, source->values, sizeof(float) * source->rows * source->columns );
}
return result;
}
And you would have to free() the deep copy, just as you would any other array2D that you create.
This works the same as any other dynamically-allocated resource, array or not, in C:
array2D * a = create2D( 3, 4 ); // 'a' is a NEW array
array2D * b = copy2D( a ); // 'b' is a NEW array (copied from 'a')
array2D * c = a; // 'c' is an alias for 'a', not a copy
...
free( b ); // done with 'b'
free( a ); // done with 'a', also known as 'c'
That c reference thing is exactly how pointer and array arguments to functions work in C, so this should not be something surprising or new.
void myfunc( array2D * a ) // 'a' is an alias, not a copy
Hopefully you can see how easy it is to handle complex objects like variable-size arrays that keep their own size in C, with only a minor amount of work in one or two spots to manage such an object. This idea is called encapsulation (though without the data hiding aspect), and is one of the fundamental concepts behind OOP (and C++). Just because we’re using C doesn’t mean we can’t apply some of these concepts!
Finally, if you find the VLAs used in other answers to be more palatable or, more importantly, more correct or useful for your problem, then use them instead! In the end, what matters is that you find a solution that works and that satisfies your requirements.
Related
The code below is producing a compiler warning: return from incompatible pointer type. The type I'm returning seems to be the issue but I cant seem to fix this warning.
I have tried changing the type of hands to int *. Also have tried returning &hands.
int * dealDeck(int numPlayers, int numCards, int cardDeck[])
{
static int hands[MAX_PLAYERS][MAX_CARDS]={0};
int start = 0;
int end = numCards;
int player, hand, j;
int card;
for(player = 0; player < numPlayers; player++)
{
for(hand = start, j=0; hand < end; hand++,j++)
{
card = cardDeck[hand];
hands[player][j] = card;
}
start = end;
end += numCards;
}
return hands;
}
This function should return a pointer to the array "hands". This array is then passed to another function which will print out its elements.
The hands variable is not an int * this is a int **
So you need to return a int **
This is a 2d array.
First of all, you have declared return type of int *, which would mean, that you are trying to return an array, while you want to return a 2-dimensional array. The proper type for this would usually be int **, but that won't cut it here. You opted to go with static, fixed size array. That means, that you need to return pointer to some structures of size MAX_CARDS * sizeof(int) (and proper type, which is the real problem here). AFAIK, there is no way to specify that return type in C*.
There are many alternatives though. You could keep the static approach, if you specify only up to 1 size (static int *hands[MAX_PLAYERS] or static int **hands), but then you need to dynamically allocate the inner arrays.
The sane way to do it is usually "call by reference", where you define the array normally before calling the function and you pass it as a parameter to the function. The function then directly modifies the outside variables. While it will help massively, with the maintainability of your code, I was surprised to find out, that it doesn't get rid of the warning. That means, that the best solution is probably to dynamically allocate the array, before calling the function and then pass it as an argument to the function, so it can access it. This also solves the question of whether the array needs to be initialized, and whether = {0} is well readable way to do it (for multidimensional array) , since you'll have to initialize it "manually".
Example:
#include <stdio.h>
#include <stdlib.h>
#define PLAYERS 10
#define DECKS 20
void foo(int **bar)
{
bar[0][0] = 777;
printf("%d", bar[0][0]);
/*
* no point in returning the array you were already given
* but for the purposes of curiosity you could change the type from
* void to int ** and "return bar;"
*/
}
int main()
{
int **arr;
arr = malloc(sizeof(int *) * PLAYERS);
for (size_t d = 0; d < DECKS; d++) {
/* calloc() here if you need the zero initialization */
arr[d] = malloc(sizeof(int) * DECKS);
}
foo(arr);
return 0;
}
*some compilers call such type like int (*)[20], but that isn't valid C syntax
I new to C, and I just can't figure out how to modify a 2D array in a function.
Here's the code I tried:
void init_matrix(int **M) {
M[0][0] = 1;
}
int main(void) {
int M[3][3];
init_matrix(M, 3);
return 0;
}
(Please note that this code is voluntarily stripped down in order to focus on the issue, I need my function to be able to work on arrays of a globally unknown size (though it could be a parameter of the function))
When I try to run this, it just gets stuck... The debugger says it's a problem of right to write in this memory slot.
How would you write the init_matrix function in the C spirit ?
Why can't I write in my matrix ?
I would like to use as few "advanced" concepts and function as possible.
Thanks in advance =)
An array is not a pointer. You need to give the dimensions of the array when you pass it as a function parameter.
void init_matrix(size_t x, size_t y, int matrix[x][y])
{
for (size_t i = 0 ; i < x ; ++i)
{
for (size_t j = 0 ; j < y ; ++j)
matrix[i][j] = 1;
}
}
int main(void)
{
int matrix[5][3];
init_matrix(5, 3, matrix);
return (0);
}
The function init_matrix() takes as parameters the dimensions, then the array (this order is important here). The "double loop" is a classic for running through a "2D memory area" like our array.
(Note that you can forget the first dimension,
void init_matrix(size_t x, size_t y, int matrix[][y])
also works)
I'm getting this error:
incompatible pointer types returning 'int [4][2]' from a function with result type 'int *'
When I try to do this
int* getValid(int blank[2]){
int row = blank[0];
int col = blank[1];
static int valid[4][2];
valid[0][0] = row;
valid[0][1] = col-1;
valid[1][0] = row;
valid[1][1] = col+1;
valid[2][0] = row-1;
valid[2][1] = col;
valid[3][0] = row+1;
valid[3][1] = col;
return valid;
}
I'm trying to return a 2D array that I generate inside the function.
I'm mostly code in Python so arrays in C are kicking my butt..
You cannot pass an array to/from a function in C. But you can pass a pointer. And that can point to an array.
So, you need a function like:
#define COLS 2
int (*getValid(int blank[2]))[COLS]
{
static int valid[4][COLS];
...
return valid;
}
Mind the parenthesis. I also use COLS for the innter dimension's length. This avoids magic numbers, i.e. repeating constants throughout your code. Use that macro for all declarations the array is involved, including the definition.
This is a "function without arguments returning a pointer to an 1D array with COLS ints". For details about arrays and pointers in C, please see a good C book and do some research on your own. Just keep in mind that while they are different types, they have a lot in common in practical use (language mechanisms behind are more difficult to understand).
Simply said, if you use return valid with the above declaration of the function, the name of the array is converted to a pointer to the first element. Which is exactly what you shall return.
The caller need to use the same pointer type (pointer to 1D array) for the result:
int (*arr)[COLS] = getValid(...);
The elements are accessed like for the original array:
arr[row][col]
Additional information: You should not use a static array in the function, unless you want to safe state between calls. Better allocate the array dynamically with malloc:
int (*arr)[COLS];
arr = malloc(sizeof(*arr) * 4); // 4 rows of the inner array
Don't forget to check if malloc failed and take appropriate measures.
Also don't forget to release the dynamically allocated array once you're done with it (but not earlier):
free(arr);
In fact, you must let an n-dimension array decay to a pointer to a n-1 dimension array. And as you use a static array, it is safe to return its address.
The only tricky thing would be to declare a function returning a pointer to an array of size 2, but a typedef can really help here:
typedef int Arr2[2];
Arr2* getValid(int blank[2]){
int row = blank[0];
int col = blank[1];
static int valid[4][2];
valid[0][0] = row;
valid[0][1] = col-1;
valid[1][0] = row;
valid[1][1] = col+1;
valid[2][0] = row-1;
valid[2][1] = col;
valid[3][0] = row+1;
valid[3][1] = col;
return valid;
}
And you can safely use it like that:
Arr2 * arr = getValid(blank);
for (i=0; i<4; i++) {
for (j=0; j<2; j++) {
printf(" %d", arr[i][j]);
}
putc('\n', stdout);
}
Compiles and runs fine without any warning.
But beware: it is safe only because valid is declared with static storage. Never return a pointer to an automatic array! (use dynamic arrays (allocated with malloc if you do not want static storage)
In C arrays are second class citizens. In order to pass them around you would need to wrap in a structure.
I.e.:
struct t_array42int{int o[4][2];} getValid(int *blank){
int row = blank[0];
int col = blank[1];
static struct t_array42int valid_container;
int (*valid)[2] = valid_container.o;
valid[0][0] = row;
valid[0][1] = col-1;
valid[1][0] = row;
valid[1][1] = col+1;
valid[2][0] = row-1;
valid[2][1] = col;
valid[3][0] = row+1;
valid[3][1] = col;
return valid_container;
}
Then you can store your function return value like:
struct t_array42int tmp = getValid(something);
Of-course there are ways to simplify this process of "wrapping" but those are often not standard or too obfuscated.
The disadvantage of using structures is that structure types aren't compared by their members layout but instead (normally) by their names. So something like this:
struct { int o[2]; } a;
struct { int o[2]; } b;
a = b; //Error
Is illegal.
You should write:
struct t_array2int { int o[2]; } a;
struct t_array2int b;
a = b; //OK
Instead.
You could also return a pointer to your array instead because it's storage is static (i.e. it won't cease to exist after returning from function):
int (*getValid(int *blank))[2]{
int row = blank[0];
int col = blank[1];
static int valid[4][2];
valid[0][0] = row;
valid[0][1] = col-1;
valid[1][0] = row;
valid[1][1] = col+1;
valid[2][0] = row-1;
valid[2][1] = col;
valid[3][0] = row+1;
valid[3][1] = col;
return valid;
}
The function prototype:
int (*getValid(int *blank))[2]
Means that if you call your function getValid with a single argument of type int * - getValid(something) and dereference it, *getValid(something) you'll get an array that can't be accessed like (*getValid(something))[2] and so have maximum 2 elements of type int.
Simple instance of the above example will be:
int (*tmp)[2] = getValid(something);
And I also suggest to write your array parameters with their real type (which can never be an array - the compiler is only fooling you into thinking that arrays can be passed by value). I.e.: void f(int a[N]) is adjusted to void f(int *a). And int * is not the same as int [N].
For a newcomer I suggest you remember that arrays are not the same as pointers but are mistreated as such very badly. Also I suggest you to never write functions with array parameters. And if you want to use arrays in a different way then to get pointer to their first element to use structures instead - much safer.
The main thing with array parameter is that:
void f(int a[2])
{
sizeof(a) == sizeof(int *); //evaluates to 1
sizeof(a) != sizeof(int [2]); //evaluates to 1
}
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 6 years ago.
Improve this question
I am trying to write a function that makes ordenations over any numeric array given to it.
The problem is that C needs to know the data type to iterate through the array properly, because of its "pointer nature".
Is there any way that I can pass any array without knowing the type? Maybe using the void type?
void ordenation (void *array, ...) {}
Here's how I understand your question, please reply below if that's not it. You are trying to create a function in C that can accept arrays of multiple numeric types (float, int, etc.).
This is called function overloading. It is possible to do it in C11 via the _Generic operator. See function overloading in C
Another option would be to create functions with a different name, all with a different parameter list. So:
void ordenation_i(int *array);
void ordenation_f(float *array);
Another way would be using the void* type. That would mean that you can pass any pointer to it and it may not be what you are looking for. You will have to cast the void* back to a pointer to something else, like a float. If that operation fails, you may have problems.
void ordenation(void *array){
float* array_casted = (float*) array;
// Do stuff
}
The problem in this code is now that the array can only be used as a float array.
Finally, you could also just use a C++ compiler. It should compile any C code and you get function overloading by default.
void ordenation(int array[]){
//do stuff
}
void ordenation(float array[]){
//do stuff
}
You can absolutely safely pass a pointer to any object to a function like this using void *. The problem, as others have pointed out, is that you have to do something with that object once you're in that function, and you'll need to know the type to do that, so even if you don't need the type to pass a pointer to the array, you're going to need it in some fashion to get any actual work done.
You can do it with C11 generics, as another answer states, but another possibility is to pass not only a pointer to the array, but a pointer also to the code you want to execute on it, using a function pointer.
For instance, the following code will add two to each element of any numeric array (I've implemented it only for int, long and double, but it's trivial to implement for the remaining standard numeric types). The add_two() function itself never has any idea what type of array it's getting. But to achieve this, you have to also pass it a pointer to a function which does know:
#include <stdio.h>
void add_two(void * array, size_t sz, void (*add_func)(void *, size_t));
void add_two_int(void * array, size_t idx);
void add_two_long(void * array, size_t idx);
void add_two_double(void * array, size_t idx);
int main(void)
{
int n[] = {1, 2, 3, 4, 5};
add_two(n, 5, add_two_int);
for ( size_t i = 0; i < 5; ++i ) {
printf("%zu: %d\n", i, n[i]);
}
long l[] = {1L, 2L, 3L, 4L, 5L};
add_two(l, 5, add_two_long);
for ( size_t i = 0; i < 5; ++i ) {
printf("%zu: %ld\n", i, l[i]);
}
double d[] = {1.0, 2.0, 3.0, 4.0, 5.0};
add_two(d, 5, add_two_double);
for ( size_t i = 0; i < 5; ++i ) {
printf("%zu: %f\n", i, d[i]);
}
return 0;
}
void add_two(void * array, size_t sz, void (*add_func)(void *, size_t))
{
for ( size_t i = 0; i < sz; ++i ) {
add_func(array, i);
}
}
void add_two_int(void * array, size_t idx)
{
int * n = array;
n[idx] += 2;
}
void add_two_long(void * array, size_t idx)
{
long * l = array;
l[idx] += 2;
}
void add_two_double(void * array, size_t idx)
{
double * d = array;
d[idx] += 2;
}
with output:
paul#horus:~/src/sandbox$ ./genarray
0: 3
1: 4
2: 5
3: 6
4: 7
0: 3
1: 4
2: 5
3: 6
4: 7
0: 3.000000
1: 4.000000
2: 5.000000
3: 6.000000
4: 7.000000
paul#horus:~/src/sandbox$
Of course, in this simple example there's not much in the way of real benefit to writing the add_two() function compared to just writing add_two_int() and friends and using them directly. But in a more complex example where you wanted, say, to have something like add_two() in a library, then this is a way for you to be able to deal with arbitrary and new types without having to modify add_two() or rebuild and redeploy your library.
Also, I've named the function add_two(), but it obviously just performs whatever operation you supply to it on each element in turn. So you could write the function subtract_two_int(void * array, size_t idx), for instance, pass it to add_two(), and it'll actually subtract two from each element, despite the name.
You can make the function void ordenation (void *array) and pass arrays of arbitrary data types into the function as long as you cast the input array like this ordenation ((void*)array) when calling the function. You should probably add a second input to denote the datatype of the corresponding array if you want to be able to use the array in your function. (I'm assuming the point of this is because C does not allow for function overloading?)
I need the equivalent of the Matlab find function (reference) in C for arrays:
ind = find(X) locates all nonzero elements of array X, and returns the
linear indices of those elements in vector ind. If X is a row vector,
then ind is a row vector; otherwise, ind is a column vector. If X
contains no nonzero elements or is an empty array, then ind is an
empty array.
A trivial untested example:
#include <stdlib.h>
#include <time.h>
int main()
{
/* Initialize variables */
int x[25];
int y[25];
/* initialize random seed: */
srand ( time(NULL) );
/* Fill arrays with stuff */
for (i=0;i<25;i++)
{
x[i] = rand();
y[i] = rand();
}
/* Find */
ind = find((x-y) > 0); // Need to figure out how to do this
}
}
Now the kicker is I can't use Boost or C++ containers like vector due to project constraints.
If you are restricted to "vanilla C" (which seems to be the case, from your question) there's nothing like that built-in, you have to write your own version of such function.
But from what I see from your example you need something different than a find function, you want to find the elements differing into x and y. If you strive for flexibility it could be a good idea to write a generic function that checks the given predicate (passed as a function pointer) on two arrays. On the other hand, since in C we have only function pointers (and not functors) performance may suffer.
This should do something close to what you want - returns number of non-zero elements that it has placed in outArray for you. Not quite the same calling signature, but should do what you want. Untested :)
size_t find(int *inArray, int *outArray, size_t arraySize)
{
size_t numElements = 0;
for(int i=0; i<arraySize; i++)
{
if(inArray[i])
{
outArray[numElements++] = inArray[i];
}
}
return numElements;
}