Passing array as parameter - c

I want to pass an array as a parameter to another function:
int i;
int main()
{
int a[5] = {1, 2, 3, 4, 5};
printf("Main:\n");
for(i=0; i<sizeof(a)/sizeof(int); i++)
{
printf("%i\n", a[i]);
}
func(a);
return;
}
void func(int a[])
{
printf("Func:\n");
for(i=0; i<sizeof(a)/sizeof(int); i++)
{
printf("%i\n", a[i]);
}
}
The loop in the main function prints all 5 values:
Main:
1
2
3
4
5
But the loop in the function func only prints 2 values:
Func:
1
2
Why this strange behaviour?

I want to pass an array as a parameter to another function:
This is a common pitfall. Arrays do not bring along their length, as they do in other languages. A C "array" is just a bunch of contiguous values, so sizeof will not (necessarily) return the length of the array.
What actually happens is that the function gets passed a pointer to the area of memory where the array is stored (and therefore, to the first element of the array), but no information about that area's size. To "pass an array with size", you must do something to provide the extra information:
explicitly pass also its length as an extra parameter. Safer: you can pass uninitialized arrays.
use a special "terminating" value on the array. More compact: you pass only one parameter, the pointer to the array.
(suggested implicitly by #CisNOTthatGOODbutISOisTHATBAD's comment): pass a pointer to a struct holding a pointer to the memory and a size_t length in elements (or in bytes). This has the advantage of allowing to store yet more metadata about the array.
For arrays of integral type, you could even store the length in the first (zeroth) element of the array. This can sometimes be useful when porting from languages that have 'measured' arrays and indexes starting from 1. In all other cases, go for method #1. Faster, safer, and in my opinion clearer.
Strings are arrays of characters that employ a variation of method #2: they are terminated by a special value (zero).
Using method #1, your function would become:
void func(size_t n, int a[])
{
printf("Func:\n");
for (i=0; i < n; i++)
{
printf("%i\n", a[i]);
}
}
(it is equivalent to void func(size_t n, int *a) ).

Declaring a function with a parameter of array type is equivalent to declaring it with a parameter of pointer type, i.e. your function is equivalent to:
void func(int *a)
As such, the computation of sizeof(a) inside func computes the size of an int *, not the size of the original array (5 * sizeof(int)).
Since the size of an int * on your platform is apparently twice the size of an int, you see two values printed inside the function in contrast to the five printed outside it (where sizeof(a) correctly computes the size of the array).
This is all related to the fact that when you pass an array to a function, what you're actually doing is passing a pointer to its first element.
Note in passing that this is a FAQ of the comp.lang.c newsgroup:
http://c-faq.com/~scs/cgi-bin/faqcat.cgi?sec=aryptr#aryparmsize

I would change the code to this:
int i;
const int N = 5;
int main()
{
int a[N] = {1, 2, 3, 4, 5};
printf("Main:\n");
for(i=0; i<N; i++)
{
printf("%i\n", a[i]);
}
func(a);
return;
}
void func(int a[])
{
printf("Func:\n");
for(i=0; i<N; i++)
{
printf("%i\n", a[i]);
}
}
Parameter N is constant and define size of array.
I think it is better way, then 2 parameters in function.

Related

Array as a parameter without a length

I have a couple of questions about this code (I don't know what it does, it's from an exam).
What does it mean when the array is passed like this: nums[]? And what does nums + 1 mean? If nums is an array, what does it mean to add 1 to it?
int f(int nums[], int n){
if(n > 1) {
if(nums[0] < nums[1]) {
return 1 + f(nums + 1, n - 1);
}
else {
return f(nums + 1, n - 1);
}
}
else return 0;
}
In C arrays cannot be passed by value to a function.
If you write something like
int a[4] = {1, 2, 3, 4};
// ....
int result = f(a, 4);
// ^ The array "decays" to a pointer
What the function receives as parameters (passed by value) are a pointer to the first element of the array a and the size of the array (hopefully the correct one).
In the declaration of such a function, some use (and recommend) the notation showed in the question as a "documentation" of the fact that we want to pass an array, but it may be misleading, if the coder forgets that said parameter is just a pointer.
Given the use (purely accademic, it makes no sense to implement that algorithm as a recursive function), I'd find more descriptive the *:
int f(const int *nums, size_t n) {
// ^^^^^ ^
}
And what does nums + 1 mean?
The result of num + 1 is a pointer which points to the element immediately after the one pointed by num.
The recursive calls just traverse the array, one element at the time (note that the "size" is decreased accordingly), counting the times that two subsequent element are in increasing order. Would you be able to rewrite that function, without the recursive calls, using a loop?
int nums[] is an array of ints. The [] denote that it's an array. The int denotes that the array contains ints.
num + 1 points to the second position in the array, so the call basically calls the same function but passing the whole array minus the first element.
Maybe looking at the function from the side of the function prototype you will see more sense of this:
int f(int[], int n);
Here f() is declared to return an int and use two arguments: the first is an address of an array of int, the second is an int.
Since inside f() you may want to know how many int's are in the vector, it is common to the second argument to be number of elements in the array. Just as an example. Any similarity with the pair
int argc, char** argv
is because it is the same thing: the system builds a list of the arguments passed on the command line and constructs the argv array. And passes argc as the number of arguments in the array.
C does pointer arithmetic, in a sense that if x points to an int (x+1) points to the x plus the sizeof() an int. This is fantastic in order to abstract things like memory, registers and hardware.
In this way, when you call f() again passing 1 + the original argument you are just calling f() and passing the array beginning at the next position.
Back to your example, consider f() just
int f(int nums[], int n)
{
printf("First int is %d\n", nums[0]);
return 0;
}
where f() just writes down the first int of the block, and the code
int f(int[], int n);
int main(int arg, char** argv)
{
const int one[4] = { 1,2,3,4 };
const int other[2] = { 3,4 };
f(one, 4);
f(other, 2);
f(other + 1, 3'000);
return 0;
};
it shows
First int is 1
First int is 3
First int is 4
And you see that in the 3rd call f() gets the array other starting at 4, the second element.

The difference between pointer in 2D and 1D array

I practiced today some C code, especially array with return function and pointers.
And I found some code which were really confusing and want to know why it is.
So I have first a function which print all elements out of the array.
void function(int *arr)
{
...
printf("%d, arr[i]);
}
Now in main I have a 2D array and a 1D array.
int array2D[2][2] = {{1,2}, {3,4}};
int array1D[3] = {1,2,3};
function(*array2D); // Why do I need here the derefernce pointer
function(array1D); // why I don't need here the deference pointer
And in another case:
void disp( int *num)
{
printf("%d ", *num);
}
int main()
{
int arr[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 0};
for (int i=0; i<10; i++)
{
/* Passing addresses of array elements*/
disp(&arr[i]); // why i need here & and above in the function not
}
}
This is really confusing me right now. Can someone explain me this?
The first line
function(*array2D);
is equivalent to
function(array2D[0]);
So you are passing the first array [1,2]. In C an array decays into a pointer
when it is passed to a function.
However, your function function1 should also get the number of
elements of the array.
void function(int *arr, size_t len)
{
size_t i;
for(i = 0; i < len; ++i)
printf("%d\n", arr[i]);
}
Then you can call it2
int array2D[2][2] = { { 1,2} ,{3,4}};
int array1D[3] = {1,2,3};
function(*array2D, sizeof *array2D / sizeof **array2D);
function(array1D, sizeof array1D / sizeof *array1D);
disp (&arr[i]); // why i need here & and above in the function not
Because arr[i] would give you the value stored at the position i, disp
expects a pointer, so you use the &-operator which returns the address of the
array at the position i, which is also equivalent to arr + i.
1Don't call your functions function. Technically that is valid name, but it
would be better if you give your function more explicit names so that just by
reading the name, you know what the functions does.
2Note that sizeof array / sizeof *array only works with arrays. If you have a
function and you expect an array, you will get only a pointer to the array.
In this case you also would need to pass the length of the array.
We're used to the fact that int mike[10] decays to int *, which points to the first thing in the array. So it seems like int sam[5][10] might also decay to int * pointing to the first element of the array. But int sam[5][10] is not a "two-dimensional array of int" that decays to an int pointer, it's an array of five arrays of ten integers. The first thing in sam is the first of the five arrays, so sam decays to a pointer to an array of ten integers, which type is written int (*)[10], though it rarely is written.
So your array2D decays to a different type than integer pointer, which is why your call function(array2D); creates a type mismatch. But your call function(*array2D); does work because (as noted above) *array2D is the same as array2D[0], which is an array of integers, and does decay to int *.
For your second case, arr is an array, but arr[i] is an int, since it is just one position in the array. The ampersand operator makes a pointer of what it operates, so &arr[i] is a pointer, and the call works.

Incompatible parameter types?

I want to use another function to print the contents of an array.
When I run the code I get "IntelliSense: argument of type "int (*)[3][3]" is incompatible with parameter of type "int *(*)[3]"
This is my function:
void display(int *p[N_ROWS][N_COLS]) {
int i, j;
for (i = 0; i < N_ROWS; i++) {
for (j = 0; j <N _COLS; j++) {
printf("%i", p[i][j]);
}
}
}
I defined N_ROWS and N_COLS
and in my main function I declare my array and then call the function
{
int Array[N_ROWS][N_COLS] = { {1,2,3},{4,5,6},{7,8,9} };
display(&Array);
}
Aren't both my parameters type int(*)[3][3] or am I missing something?
Your prototype for display is incorrect, as well as your call syntax: you define display to take a 2D array of pointers to int, whereas you just want a 2D array if int, as you pass a pointer to the array in main where you just want to pass the array, decaying as a pointer to its first element.
Here is a simpler version:
void display(int p[N_ROWS][N_COLS]) {
int i, j;
for (i = 0; i < N_ROWS; i++) {
for (j = 0; j < N_COLS; j++) {
printf("%i", p[i][j]);
}
}
}
Note however that p above can have any number of rows, N_ROWS is ignored in the prototype, equivalent to void display(int (*p)[N_COLS]).
Note also that your printf will output the matrix values without any separation. This might not be your intent.
And from main:
{
int Array[N_ROWS][N_COLS] = { {1,2,3},{4,5,6},{7,8,9} };
display(Array);
}
Much of this has already been explained in comments to your question.
Your definition of display:
void display(int*p[N_ROWS][N_COLS])
{
This says p will be an array N_ROWS of array N_COLS of pointers to int.
When you call display:
int Array [N_ROWS][N_COLS] = { {1,2,3},{4,5,6},{7,8,9} };
display(&Array);
You are passing in the address of Array, thus it is a pointer to an array N_ROWS of array N_COLS of int.
To make the definition of display match the way you are calling it:
void display(int (*p)[N_ROWS][N_COLS])
{
The parentheses make the * associate with p first. Since p is a pointer to an array of array of int, getting to the int requires an extra dereference:
printf("%i\n", (*p)[i][j]);
Defining display to take a pointer to an array means that the size of the array is bound to the type parameter, and thus display knows exactly the dimensions of the array.
An alternative means would be to define display to take the dimension of the array as a second parameter.
void display(int p[][N_COLS], int n_rows)
{
In this case the p parameter is a pointer to an array N_COLS of int. An array of T when used in most expressions will decay to a value of type pointer to T equal to the address of its first element. Thus, you could call this second version of display like this:
int Array [N_ROWS][N_COLS] = { {1,2,3},{4,5,6},{7,8,9} };
display(Array, N_ROWS);
The advantage of this second approach is that display can work with arrays that have fewer or more than N_ROWS. The disadvantage is that it is up to the caller to pass in the right number of rows.
You might think that the following declaration would give you complete type safety:
void display(int p[N_ROWS][N_COLS])
{
But, the array syntax in C for function parameters cause the size information for p to be ignored, and becomes equivalent to int p[][N_COLS], which in turn is treated as int (*p)[N_COLS].

How to get the array size in a function without any additional arguments

main()
{
int arr[] = {1, 2, 3, 4};
function(arr);
}
int function(int a[])
{
}
Here I want to get the length of the array which was not initialized. The main function in my case is which I do not have any idea..assume I am getting the array elements from some other program.
Arrays decay to pointers when used as arguments to a function:
int function(int a[]);
and
int function(int *a);
are the same.
This means that you cannot know how many elements are in an array that is passed to your function unless you have a separate parameter that indicates the length of the array.
You can find out how many elements there are in arr in main() by sizeof(arr)/sizeof(arr[0]).
However, you cannot use this method in that function(). Because in this case a is a pointer to int, you need to pass the length of a as an extra argument to function(), like this:
int function(int a[], int len) {
You can't.
The function just receives a pointer (an address to a location in memory).
You have two options: pass the lenght of the array as an extra argument to the function (as other suggested)...
...or establish a convention (if possibile) where a certain value on the array represent the last element (so you can get the length by counting elements until the end-of-array item).
That's what happens with C strings. A C string is an array of chars where a character with value of 0 indicates the end of the string.
#include<stdio.h>
int ArraySize (int *);
main ()
{
int array[] = {1,2,3};
printf("The size of the array is%d \n", ArraySize(array));
}
int ArraySize (int *a)
{
for (int i=0; a[i]!='\0'; i++);
return i;
}

Pass an array to a function by value

Below is a snippet from the book C Programming Just the FAQs. Isn't this wrong as Arrays can never be passed by value?
VIII.6: How can you pass an array to a function by value?
Answer: An array can be passed to a function by value by declaring in
the called function the array name
with square brackets ([ and ])
attached to the end. When calling the
function, simply pass the address of
the array (that is, the array’s name)
to the called function. For instance,
the following program passes the array
x[] to the function named
byval_func() by value:
The int[] parameter tells the
compiler that the byval_func()
function will take one argument—an
array of integers. When the
byval_func() function is called, you
pass the address of the array to
byval_func():
byval_func(x);
Because the array is being passed by
value, an exact copy of the array is
made and placed on the stack. The
called function then receives this
copy of the array and can print it.
Because the array passed to
byval_func() is a copy of the
original array, modifying the array
within the byval_func() function has
no effect on the original array.
Because the array is being passed by value, an exact copy of the array is made and placed on the stack.
This is incorrect: the array itself is not being copied, only a copy of the pointer to its address is passed to the callee (placed on the stack). (Regardless of whether you declare the parameter as int[] or int*, it decays into a pointer.) This allows you to modify the contents of the array from within the called function. Thus, this
Because the array passed to byval_func() is a copy of the original array, modifying the array within the byval_func() function has no effect on the original array.
is plain wrong (kudos to #Jonathan Leffler for his comment below). However, reassigning the pointer inside the function will not change the pointer to the original array outside the function.
Burn that book. If you want a real C FAQ that wasn't written by a beginner programmer, use this one: http://c-faq.com/aryptr/index.html.
Syntax-wise, strictly speaking you cannot pass an array by value in C.
void func (int* x); /* this is a pointer */
void func (int x[]); /* this is a pointer */
void func (int x[10]); /* this is a pointer */
However, for the record there is a dirty trick in C that does allow you to pass an array by value in C. Don't try this at home! Because despite this trick, there is still never a reason to pass an array by value.
typedef struct
{
int my_array[10];
} Array_by_val;
void func (Array_by_val x);
Isn't this wrong as arrays can never be passed by value?
Exactly. You cannot pass an array by value in C.
I took a look at the quoted part of the book and the source of this confusion or mistake is pretty fast found.
The author did not know about that *i is equivalent to i[] when provided as a parameter to a function. The latter form was invented to explicitly illustrate the reader of the code, that i points to an array, which is a great source of confusion, as well-shown by this question.
What I think is funny, that the author of the particular part of the book or at least one of the other parts (because the book has 5 authors in total) or one of the 7 proofreaders did not mentioned at least the sentence:
"When the byval_func() function is called, you pass the address of the array to byval_func():"
With at least that, they should had noticed that there is a conflict.
Since you passing an address, it is only an address. There is nothing magically happen which turns an address into a whole new array.
But back to the question itself:
You can not pass an array as it is by value in C, as you already seem to know yourself. But you can do three (there might be more, but that is my acutal status of it) things, which might be an alternative depending on the unique case, so let´s start.
Encapsulate an array in a structure (as mentioned by other answers):
#include <stdio.h>
struct a_s {
int a[20];
};
void foo (struct a_s a)
{
size_t length = sizeof a.a / sizeof *a.a;
for(size_t i = 0; i < length; i++)
{
printf("%d\n",a.a[i]);
}
}
int main()
{
struct a_s array;
size_t length = sizeof array.a / sizeof *array.a;
for(size_t i = 0; i < length; i++)
{
array.a[i] = 15;
}
foo(array);
}
Pass by pointer but also add a parameter for determine the size of the array. In the called function there is made a new array with that size information and assigned with the values from the array in the caller:
#include <stdio.h>
void foo (int *array, size_t length)
{
int b[length];
for(size_t i = 0; i < length; i++)
{
b[i] = array[i];
printf("%d\n",b[i]);
}
}
int main()
{
int a[10] = {0,1,2,3,4,5,6,7,8,9};
foo(a,(sizeof a / sizeof *a));
}
Avoid to define local arrays and just use one array with global scope:
#include <stdio.h>
int a[10];
size_t length = sizeof a / sizeof *a;
void foo (void)
{
for(size_t i = 0; i < length; i++)
{
printf("%d\n",a[i]);
}
}
int main()
{
for(size_t i = 0; i < length; i++)
{
a[i] = 25;
}
foo();
}
In C and C++ it is NOT possible to pass a complete block of memory by value as a parameter to a function, but we are allowed to pass its address. In practice this has almost the same effect and it is a much faster and more efficient operation.
To be safe, you can pass the array size or put const qualifier before the pointer to make sure the callee won't change it.
Yuo can work it around by wrapping the array into the struct
#include <stdint.h>
#include <stdio.h>
struct wrap
{
int x[1000];
};
struct wrap foo(struct wrap x)
{
struct wrap y;
for(int index = 0; index < 1000; index ++)
y.x[index] = x.x[index] * x.x[index];
return y;
}
int main ()
{
struct wrap y;
for(int index = 0; index < 1000; index ++)
y.x[index] = rand();
y = foo(y);
for(int index = 0; index < 1000; index ++)
{
printf("%d %s", y.x[index], !(index % 30) ? "\n" : "");
}
}
#include<stdio.h>
void fun(int a[],int n);
int main()
{
int a[5]={1,2,3,4,5};
fun(a,5);
}
void fun(int a[],int n)
{
int i;
for(i=0;i<=n-1;i++)
printf("value=%d\n",a[i]);
}
By this method we can pass the array by value, but actually the array is accessing through the its base address which actually copying in the stack.

Resources