I need help finding the appropriate way to provide values to my function in C which can be seen below:
void matrixMultiply(int *A[], int *B[])
I have the following function that needs 2 pointer to arrays, and those pointers point to two 2d arrays. I have the following main function, but I just can't seem to figure out a way to pass my arrays to the function.
int main()
{
int arr[2][2] = {
{ 1, 2 },
{ 5, 6 }
};
int(*p)[2];
p = &arr;
int arr2[2][1] = {
{ 11 },
{ 55 }
};
int(*l)[1];
l = arr2;
for (int i = 0; i < 4; i++) // I don't know if I need this but I used it before when I was experimenting with the form p[i].
{
matrixMultiply(p, l); // p and l are the pointers to the two 2d arrays I have
}
return 0;
}
This is the updated code:
int main()
{
int arr[2][2] = {
{ 1, 2 },
{ 5, 6 }
};
int(**p);
p = &arr;
int arr2[2][1] = {
{ 11 },
{ 55 }
};
int(**l);
l = arr2;
for (int i = 0; i < 4; i++) // I don't know if I need this but I used it before when I was experimenting with the form p[i].
{
matrixMultiply(p, l); // p and l are the pointers to the two 2d arrays I have
}
return 0;
}
new errors:
C:\WINDOWS\system32\cmd.exe /C ""C:/Program Files/mingw-w64/x86_64-8.1.0-posix-seh-rt_v6-rev0/mingw64/bin/mingw32-make.exe" -j12 SHELL=cmd.exe -e -f Makefile"
C:/Users/Owner/Desktop/Codes/aee22eeCodes/main.c: In function 'main':
C:/Users/Owner/Desktop/Codes/aee22eeCodes/main.c:49:16: warning: passing argument 1 of 'matmul' from incompatible pointer type [-Wincompatible-pointer-types]
matmul(&arr, &arr2); // p and l are the pointers to the two 2d arrays I have
^~~~
C:/Users/Owner/Desktop/Codes/aee22eeCodes/main.c:12:18: note: expected 'int **' but argument is of type 'int (*)[2][2]'
void matmul(int *A[], int *B[])
~~~~~^~~
C:/Users/Owner/Desktop/Codes/aee22eeCodes/main.c:49:22: warning: passing argument 2 of 'matmul' from incompatible pointer type [-Wincompatible-pointer-types]
matmul(&arr, &arr2); // p and l are the pointers to the two 2d arrays I have
^~~~~
C:/Users/Owner/Desktop/Codes/aee22eeCodes/main.c:12:28: note: expected 'int **' but argument is of type 'int (*)[2][1]'
void matmul(int *A[], int *B[])
~~~~~^~~
====0 errors, 4 warnings====
This answer is a snippet of my full answer here.
Here are 4 techniques and when to use each. If your array sizes are fixed and known at compile-time, your prototype and call should look like this:
void matrixMultiply(int (*a)[2][2], int (*b)[2][1]);
matrixMultiply(&arr, &arr2);
...but I don't have enough information from you, so here are the 4 techniques and when to use each. You can follow these examples to create the right answer for your particular situation.
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])
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
void printArray2(int (*a)[3][2])
{
// See my function definition here:
// https://stackoverflow.com/a/67814330/4561887
}
// 2. Basic usage
// NB: `&` is REQUIRED! See my answer for why: https://stackoverflow.com/a/51527502/4561887
printArray2(&arr);
// 3. Usage via a pointer
// `int (*a)[3][2]` is an explicit ptr to a 3x2 array of `int`. This array pointer does NOT
// naturally decay to a simpler type.
int (*p2)[3][2] = &arr; // must use `&` and MUST USE THESE PARENTHESIS!
printArray2(p2);
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
void printArray3(int a[][2], size_t num_rows)
{
// See my function definition here:
// https://stackoverflow.com/a/67814330/456188
}
// 2. Basic usage
printArray3(arr, NUM_ROWS(arr));
// 3. Usage via a pointer
// `int a[][2]` naturally decays to `int* [2]`
int (*p3)[2] = arr; // MUST USE THESE PARENTHESIS!
printArray3(p3, NUM_ROWS(arr));
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 generally my go-to approach for multidimensional arrays):
// 1. Function definition
void printArray4(int *a, size_t num_rows, size_t num_cols)
{
// See my function definition here:
// https://stackoverflow.com/a/67814330/456188
}
// 2. Basic usage
printArray4((int *)arr, NUM_ROWS(arr), NUM_COLS(arr));
// OR: alternative call technique:
printArray4(&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];
printArray4(p4_1, NUM_ROWS(arr), NUM_COLS(arr));
printArray4(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
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
void printArray5(int* a[], size_t num_rows, size_t num_cols)
{
// See my function definition here:
// https://stackoverflow.com/a/67814330/456188
}
// 2. Basic usage
printArray5(all_rows, ARRAY_LEN(all_rows), ARRAY_LEN(row1));
// 3. Usage via a pointer
// `int* a[]` naturally decays to `int**`
int **p5 = all_rows;
printArray5(p5, ARRAY_LEN(all_rows), ARRAY_LEN(row1));
See my full answer here for the full function definitions for each function above, more details, example output, and full, runnable code: How to pass a multidimensional array to a function in C and C++
Related
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.
This question already has answers here:
C sizeof a passed array [duplicate]
(7 answers)
Closed 4 years ago.
In the program below the length of the array ar is correct in main but in temp it shows the length of the pointer to ar which on my computer is 2 (in units of sizeof(int)).
#include <stdio.h>
void temp(int ar[]) // this could also be declared as `int *ar`
{
printf("%d\n", (int) sizeof(ar)/sizeof(int));
}
int main(void)
{
int ar[]={1,2,3};
printf("%d\n", (int) sizeof(ar)/sizeof(int));
temp(ar);
return 0;
}
I wanted to know how I should define the function so the length of the array is read correctly in the function.
There is no 'built-in' way to determine the length inside the function. However you pass arr, sizeof(arr) will always return the pointer size. So the best way is to pass the number of elements as a seperate argument. Alternatively you could have a special value like 0 or -1 that indicates the end (like it is \0 in strings, which are just char []).
But then of course the 'logical' array size was sizeof(arr)/sizeof(int) - 1
Don't use a function, use a macro for this:
//Adapted from K&R, p.135 of edition 2.
#define arrayLength(array) (sizeof((array))/sizeof((array)[0]))
int main(void)
{
int ar[]={1,2,3};
printf("%d\n", arrayLength(ar));
return 0;
}
You still cannot use this macro inside a function like your temp where the array is passed as a parameter for the reasons others have mentioned.
Alternative if you want to pass one data type around is to define a type that has both an array and capacity:
typedef struct
{
int *values;
int capacity;
} intArray;
void temp(intArray array)
{
printf("%d\n", array.capacity);
}
int main(void)
{
int ar[]= {1, 2, 3};
intArray arr;
arr.values = ar;
arr.capacity = arrayLength(ar);
temp(arr);
return 0;
}
This takes longer to set up, but is useful if you find your self passing it around many many functions.
As others have said the obvious solution is to pass the length of array as parameter, also you can store this value at the begin of array
#include <stdio.h>
void temp(int *ar)
{
printf("%d\n", ar[-1]);
}
int main(void)
{
int ar[]= {0, 1, 2, 3};
ar[0] = sizeof(ar) / sizeof(ar[0]) - 1;
printf("%d\n", ar[0]);
temp(ar + 1);
return 0;
}
When you write size(ar) then you're passing a pointer and not an array.
The size of a pointer and an int is 4 or 8 - depending on ABI (Or, as #H2CO3 mentioned - something completely different), so you're getting sizeof(int *)/sizeof int (4/4=1 for 32-bit machines and 8/4=2 for 64-bit machines), which is 1 or 2 (Or.. something different).
Remember, in C when pass an array as an argument to a function, you're passing a pointer to an array.If you want to pass the size of the array, you should pass it as a separated argument.
I don't think you could do this using a function. It will always return length of the pointer rather than the length of the whole array.
You need to wrap the array up into a struct:
#include<stdio.h>
struct foo {int arr[5];};
struct bar {double arr[10];};
void temp(struct foo f, struct bar g)
{
printf("%d\n",(sizeof f.arr)/(sizeof f.arr[0]));
printf("%d\n",(sizeof g.arr)/(sizeof g.arr[0]));
}
void main(void)
{
struct foo tmp1 = {{1,2,3,4,5}};
struct bar tmp2;
temp(tmp1,tmp2);
return;
}
Inside the function ar is a pointer so the sizeof operator will return the length of a pointer. The only way to compute it is to make ar global and or change its name. The easiest way to determine the length is size(array_name)/(size_of(int). The other thing you can do is pass this computation into the function.
I need to change the properties of the structure within a function, so I could do a calculation with the properties and set new values,but when i try to change the value of a structure i am getting the following error: cannot convert 'data specs (*) [2]' to 'data specs' for argument '1' to 'void changeValues (data specs)' changeValues (& stats);
Does anyone know how to fix it?
typedef struct
{
char nome;
int vida;
int dano;
int x;
int y;
} dadospecas;
void changeValues(dadospecas *a[]){
a[1]->vida = 5;
printf("%i", a[1]->vida);
}
int main() {
dadospecas stats[2];
stats[1].nome = 'W';
stats[1].vida = 3;
stats[1].dano = 1;
stats[1].x = 4;
stats[1].y = 1;
stats[2].nome = 'F';
stats[2].vida = 33;
stats[2].dano = 11;
stats[2].x = 44;
stats[2].y = 14;
changeValues(&stats);
return 0;
}
In addition to the great answer by #Stuart, you seem to be a little confused on how to handle sending values to your function to be changed, (here you are changing the vida member only). As noted in the other answer, on access, an array is converted to a pointer to its first element. C11 Standard - 6.3.2.1 Other Operands - Lvalues, arrays, and function designators(p3).
To make your function useful (as it is it hardcodes the entire operation), you should provide parameters for a pointer to dadospecas, the index to change and the new value to assign to the vida member. The caller is responsible for ensuring the index to change is within bounds (you can pass the number of elements as an additional index if desired)
If you put those pieces together and change the name of the function to reflect the fact you are only changing the vida member, you could do:
/* pass a pointer to the array as your parameter (inlcude index and value) */
void changeVida (dadospecas *a, int index, int newvida)
{
a[index].vida = newvida;
}
A short example showing the use, and fixing your indexing problem, could be written as:
#include <stdio.h>
#define NSTRUCT 2 /* if you need a constant, #define one (or more) */
typedef struct {
char nome;
int vida,
dano,
x,
y;
} dadospecas;
/* pass a pointer to the array as your parameter (inlcude index and value) */
void changeVida (dadospecas *a, int index, int newvida)
{
a[index].vida = newvida;
}
int main (void)
{
dadospecas stats[NSTRUCT] = {{'W', 3, 1, 4, 1}, {'F', 33, 11, 44, 14}};
for (int i = 0; i < NSTRUCT; i++) { /* loop over each struct */
changeVida (stats, i, stats[i].vida + 5); /* increment vida by 5 */
printf ("stats[%d].vida = %d\n", i, stats[i].vida); /* output new vida */
}
}
Example Use/Output
Where the example simply adds 5 to the existing value of the vida member:
$ ./bin/dadospecas
stats[0].vida = 8
stats[1].vida = 38
If You Pass The Address of stats
While there is no need to pass the address of stats, there is nothing to prevent you from doing it -- it is perfectly fine -- just unnecessary. For sake of argument, let's say you did. Continuing from my comment, in main stats is an array of type dadospecas [2], so when you take the address your type is pointer to array of dadospecas [2]. The formal type is dadospecas (*)[2]
So passing the pointer your function parameter would become: dadospecas (*a)[2].
Within your function to operate on your array, you would first need to dereference the parameter to allow you to operate on the elements of the array, e.g. (*a)[index] and finally to change the vida member you would have:
(*a)[index].vida = newvida;
The changes to the example above to pass the address of stats would be:
/* pass a pointer to array[NSTRUCT] as your parameter (inlcude index and value) */
void changeVida (dadospecas (*a)[NSTRUCT], int index, int newvida)
{
(*a)[index].vida = newvida;
}
int main (void)
{
dadospecas stats[NSTRUCT] = {{'W', 3, 1, 4, 1}, {'F', 33, 11, 44, 14}};
for (int i = 0; i < NSTRUCT; i++) { /* loop over each struct */
changeVida (&stats, i, stats[i].vida + 5); /* increment vida by 5 */
printf ("stats[%d].vida = %d\n", i, stats[i].vida); /* output new vida */
}
}
(same output)
It is simply a matter of keeping the levels of pointer indirection straight and observing C operator precedence.
Look things over and let me know if you have further questions.
I think there are two things you don't understand about arrays in C.
Arrays are indexed starting from 0 and not 1.
The first element of your stats array is stats[0] and the second is stats[1]. You need to change the assignments in your main function, and in your changeValues function if you want it to change the first element of the array.
Arrays are const pointers (i.e. pointers that have a fixed value).
The stats array is really a const pointer to dadospecas. It's a const pointer meaning you can't change the value of stats. You can change the values contained by (i.e. pointed to) by stats.
If you want to define a function that will modify the contents of an array, you don't need to pass a pointer to the array, you can just pass the array.
Your changeValues function should be defined like this:
void changeValues(dadospecas *a){
//put code here.
}
or
void changeValues(dadospecas a[]){
//put code here.
}
In either case, your main function would call changeValues like this
changeValues(stats);
By the way, if you want to check that changeValues has modified the vida member of the first element of stats, I would remove the printf call from the changeValues function and replace it with
printf("%i", stats[0].vida);
in your main function (after the call to changeValues of course).
I am trying to write a function that prints out the elements in an array. However when I work with the arrays that are passed, I don't know how to iterate over the array.
void
print_array(int* b)
{
int sizeof_b = sizeof(b) / sizeof(b[0]);
int i;
for (i = 0; i < sizeof_b; i++)
{
printf("%d", b[i]);
}
}
What is the best way to do iterate over the passed array?
You need to also pass the size of the array to the function.
When you pass in the array to your function, you are really passing in the address of the first element in that array. So the pointer is only pointing to the first element once inside your function.
Since memory in the array is continuous though, you can still use pointer arithmetic such as (b+1) to point to the second element or equivalently b[1]
void print_array(int* b, int num_elements)
{
for (int i = 0; i < num_elements; i++)
{
printf("%d", b[i]);
}
}
This trick only works with arrays not pointers:
sizeof(b) / sizeof(b[0])
... and arrays are not the same as pointers.
Why don't you use function templates for this (C++)?
template<class T, int N> void f(T (&r)[N]){
}
int main(){
int buf[10];
f(buf);
}
EDIT 2:
The qn now appears to have C tag and the C++ tag is removed.
For C, you have to pass the length (number of elements)of the array.
For C++, you can pass the length, BUT, if you have access to C++0x, BETTER is to use std::array. See here and here. It carries the length, and provides check for out-of-bound if you access elements using the at() member function.
In C99, you can require that an array an array has at least n elements thusly:
void print_array(int b[static n]);
6.7.5.3.7: A declaration of a parameter as ‘‘array of type’’ shall be adjusted to ‘‘qualified pointer to
type’’, where the type qualifiers (if any) are those specified within the [ and ] of the
array type derivation. If the keyword static also appears within the [ and ] of the
array type derivation, then for each call to the function, the value of the corresponding
actual argument shall provide access to the first element of an array with at least as many
elements as specified by the size expression.
In GCC you can pass the size of an array implicitly like this:
void print_array(int n, int b[n]);
You could try this...
#include <cstdio>
void
print_array(int b[], size_t N)
{
for (int i = 0; i < N; ++i)
printf("%d ", b[i]);
printf("\n");
}
template <size_t N>
inline void
print_array(int (&b)[N])
{
// could have loop here, but inline forwarding to
// single function eliminates code bloat...
print_array(b, N);
}
int main()
{
int a[] = { 1, 2 };
int b[] = { };
int c[] = { 1, 2, 3, 4, 5 };
print_array(a);
// print_array(b);
print_array(c);
}
...interestingly b doesn't work...
array_size.cc: In function `int main()':
array_size.cc:19: error: no matching function for call to `print_array(int[0u])'
JoshD points out in comments below the issue re 0 sized arrays (a GCC extension), and the size inference above.
In c++ you can also use a some type of list class implemented as an array with a size method or as a struct with a size member(in c or c++).
Use variable to pass the size of array.
int sizeof_b = sizeof(b) / sizeof(b[0]); does nothing but getting the pre-declared array size, which is known, and you could have passed it as an argument; for instance, void print_array(int*b, int size). size could be the user-defined size too.
int sizeof_b = sizeof(b) / sizeof(b[0]); will cause redundant iteration when the number of elements is less than the pre-declared array-size.
The question has already some good answers, for example the second one. However there is a lack of explanation so I would like to extend the sample and explain it:
Using template and template parameters and in this case None-Type Template parameters makes it possible to get the size of a fixed array with any type.
Assume you have such a function template:
template<typename T, int S>
int getSizeOfArray(T (&arr)[S]) {
return S;
}
The template is clearly for any type(here T) and a fixed integer(S).
The function as you see takes a reference to an array of S objects of type T, as you know in C++ you cannot pass arrays to functions by value but by reference so the function has to take a reference.
Now if u use it like this:
int i_arr[] = { 3, 8, 90, -1 };
std::cout << "number f elements in Array: " << getSizeOfArray(i_arr) << std::endl;
The compiler will implicitly instantiate the template function and detect the arguments, so the S here is 4 which is returned and printed to output.
I am trying to write a function that prints out the elements in an array. However when I work with the arrays that are passed, I don't know how to iterate over the array.
void
print_array(int* b)
{
int sizeof_b = sizeof(b) / sizeof(b[0]);
int i;
for (i = 0; i < sizeof_b; i++)
{
printf("%d", b[i]);
}
}
What is the best way to do iterate over the passed array?
You need to also pass the size of the array to the function.
When you pass in the array to your function, you are really passing in the address of the first element in that array. So the pointer is only pointing to the first element once inside your function.
Since memory in the array is continuous though, you can still use pointer arithmetic such as (b+1) to point to the second element or equivalently b[1]
void print_array(int* b, int num_elements)
{
for (int i = 0; i < num_elements; i++)
{
printf("%d", b[i]);
}
}
This trick only works with arrays not pointers:
sizeof(b) / sizeof(b[0])
... and arrays are not the same as pointers.
Why don't you use function templates for this (C++)?
template<class T, int N> void f(T (&r)[N]){
}
int main(){
int buf[10];
f(buf);
}
EDIT 2:
The qn now appears to have C tag and the C++ tag is removed.
For C, you have to pass the length (number of elements)of the array.
For C++, you can pass the length, BUT, if you have access to C++0x, BETTER is to use std::array. See here and here. It carries the length, and provides check for out-of-bound if you access elements using the at() member function.
In C99, you can require that an array an array has at least n elements thusly:
void print_array(int b[static n]);
6.7.5.3.7: A declaration of a parameter as ‘‘array of type’’ shall be adjusted to ‘‘qualified pointer to
type’’, where the type qualifiers (if any) are those specified within the [ and ] of the
array type derivation. If the keyword static also appears within the [ and ] of the
array type derivation, then for each call to the function, the value of the corresponding
actual argument shall provide access to the first element of an array with at least as many
elements as specified by the size expression.
In GCC you can pass the size of an array implicitly like this:
void print_array(int n, int b[n]);
You could try this...
#include <cstdio>
void
print_array(int b[], size_t N)
{
for (int i = 0; i < N; ++i)
printf("%d ", b[i]);
printf("\n");
}
template <size_t N>
inline void
print_array(int (&b)[N])
{
// could have loop here, but inline forwarding to
// single function eliminates code bloat...
print_array(b, N);
}
int main()
{
int a[] = { 1, 2 };
int b[] = { };
int c[] = { 1, 2, 3, 4, 5 };
print_array(a);
// print_array(b);
print_array(c);
}
...interestingly b doesn't work...
array_size.cc: In function `int main()':
array_size.cc:19: error: no matching function for call to `print_array(int[0u])'
JoshD points out in comments below the issue re 0 sized arrays (a GCC extension), and the size inference above.
In c++ you can also use a some type of list class implemented as an array with a size method or as a struct with a size member(in c or c++).
Use variable to pass the size of array.
int sizeof_b = sizeof(b) / sizeof(b[0]); does nothing but getting the pre-declared array size, which is known, and you could have passed it as an argument; for instance, void print_array(int*b, int size). size could be the user-defined size too.
int sizeof_b = sizeof(b) / sizeof(b[0]); will cause redundant iteration when the number of elements is less than the pre-declared array-size.
The question has already some good answers, for example the second one. However there is a lack of explanation so I would like to extend the sample and explain it:
Using template and template parameters and in this case None-Type Template parameters makes it possible to get the size of a fixed array with any type.
Assume you have such a function template:
template<typename T, int S>
int getSizeOfArray(T (&arr)[S]) {
return S;
}
The template is clearly for any type(here T) and a fixed integer(S).
The function as you see takes a reference to an array of S objects of type T, as you know in C++ you cannot pass arrays to functions by value but by reference so the function has to take a reference.
Now if u use it like this:
int i_arr[] = { 3, 8, 90, -1 };
std::cout << "number f elements in Array: " << getSizeOfArray(i_arr) << std::endl;
The compiler will implicitly instantiate the template function and detect the arguments, so the S here is 4 which is returned and printed to output.