Array as a parameter without a length - c

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.

Related

Passing pointer array to function in C

I am having trouble passing a pointer array to a function. I will post a simple example that still doesn't work for me. Could you please tell me what I am doing wrong?
#include <stdio.h>
#include <stdlib.h>
int transformare(int *v[1])
{
*v[1] = 10;
return 0;
}
int main()
{
int v[1];
printf("n = ");
scanf("%d", &v[1]);
transformare(&v);
printf("%d", v[1]);
return 0;
}
You have two problems:
Array indexes are zero-based. That is, an array of N elements have indexes from 0 to N - 1 (inclusive)
The declaration int *v[1] declares v as an array of one pointer to int, not as a pointer to an array of one int. That would be int (*v)[1]. Which is also the type of &v from the main function.
The solution to the second problem (using the correct type) then leads to a third problem, as it means that *v[0] is incorrect due to operator precedence. You need to use parentheses here too, as in (*v)[0].
However the second (and the following third) problem is moot, since you don't need to pass arrays "by reference".
Arrays naturally decays to pointers to their first element. When using plain v when a pointer to int is expected, the compiler will automatically translate it as &v[0].
That means you could declare the function to simply take an int * as argument, and simply pass plain v as the argument.
First, please note that indizes are 0-based in C, i.e. the first (and - in your case only) element is v[0].
Concerning passing it, just define the parameter as pointer to int, i.e. int*. A variable of type int[1] will decay to a pointer to int when passed to a function (so there is no need to write transformare(&v), its transformare(v).
int transformare(int *v)
{
v[0] = 10;
return 0;
}
int main()
{
int v[1];
printf("n = ");
scanf("%d", &v[0]);
transformare(v);
printf("%d", v[0]);
return 0;
}

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.

Passing array as parameter

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.

Passing dynamically allocated array as a parameter in C

So... I have a dynamically allocated array on my main:
int main()
{
int *array;
int len;
array = (int *) malloc(len * sizeof(int));
...
return EXIT_SUCCESS;
}
I also wanna build a function that does something with this dynamically allocated array.
So far my function is:
void myFunction(int array[], ...)
{
array[position] = value;
}
If I declare it as:
void myFunction(int *array, ...);
Will I still be able to do:
array[position] = value;
Or I will have to do:
*array[position] = value;
...?
Also, if I am working with a dynamically allocated matrix, which one is the correct way to declare the function prototype:
void myFunction(int matrix[][], ...);
Or
void myFunction(int **matrix, ...);
...?
If I declare it as:
void myFunction(int *array, ...);
Will I still be able to do:
array[position] = value;
Yes - this is legal syntax.
Also, if I am working with a dynamically allocated matrix, which one
is correct to declare the function prototype:
void myFunction(int matrix[][], ...);
Or
void myFunction(int **matrix, ...);
...?
If you're working with more than one dimension, you'll have to declare the size of all but the first dimension in the function declaration, like so:
void myFunction(int matrix[][100], ...);
This syntax won't do what you think it does:
void myFunction(int **matrix, ...);
matrix[i][j] = ...
This declares a parameter named matrix that is a pointer to a pointer to int; attempting to dereference using matrix[i][j] will likely cause a segmentation fault.
This is one of the many difficulties of working with a multi-dimensional array in C.
Here is a helpful SO question addressing this topic:
Define a matrix and pass it to a function in C
Yes, please use array[position], even if the parameter type is int *array. The alternative you gave (*array[position]) is actually invalid in this case since the [] operator takes precedence over the * operator, making it equivalent to *(array[position]) which is trying to dereference the value of a[position], not it's address.
It gets a little more complicated for multi-dimensional arrays but you can do it:
int m = 10, n = 5;
int matrixOnStack[m][n];
matrixOnStack[0][0] = 0; // OK
matrixOnStack[m-1][n-1] = 0; // OK
// matrixOnStack[10][5] = 0; // Not OK. Compiler may not complain
// but nearby data structures might.
int (*matrixInHeap)[n] = malloc(sizeof(int[m][n]));
matrixInHeap[0][0] = 0; // OK
matrixInHeap[m-1][n-1] = 0; // OK
// matrixInHeap[10][5] = 0; // Not OK. coloring outside the lines again.
The way the matrixInHeap declaration should be interpreted is that the 'thing' pointed to by matrixInHeap is an array of n int values, so sizeof(*matrixInHeap) == n * sizeof(int), or the size of an entire row in the matrix. matrixInHeap[2][4] works because matrixInHeap[2] is advancing the address matrixInHeap by 2 * sizeof(*matrixInHeap), which skips two full rows of n integers, resulting in the address of the 3rd row, and then the final [4] selects the fifth element from the third row. (remember that array indices start at 0 and not 1)
You can use the same type when pointing to normal multidimensional c-arrays, (assuming you already know the size):
int (*matrixPointer)[n] = matrixOnStack || matrixInHeap;
Now lets say you want to have a function that takes one of these variably sized matrices as a parameter. When the variables were declared earlier the type had some information about the size (both dimensions in the stack example, and the last dimension n in the heap example). So the parameter type in the function definition is going to need that n value, which we can actually do, as long as we include it as a separate parameter, defining the function like this:
void fillWithZeros(int m, int n, int (*matrix)[n]) {
for (int i = 0; i < m; ++i)
for (int j = 0; j < n; ++j)
matrix[i][j] = 0;
}
If we don't need the m value inside the function, we could leave it out entirely, just as long as we keep n:
bool isZeroAtLocation(int n, int (*matrix)[n], int i, int j) {
return matrix[i][j] == 0;
}
And then we just include the size when calling the functions:
fillWithZeros(m, n, matrixPointer);
assert(isZeroAtLocation(n, matrixPointer, 0, 0));
It may feel a little like we're doing the compilers work for it, especially in cases where we don't use n inside the function body at all (or only as a parameter to similar functions), but at least it works.
One last point regarding readability: using malloc(sizeof(int[len])) is equivalent to malloc(len * sizeof(int)) (and anybody who tells you otherwise doesn't understand structure padding in c) but the first way of writing it makes it obvious to the reader that we are talking about an array. The same goes for malloc(sizeof(int[m][n])) and malloc(m * n * sizeof(int)).
Will I still be able to do:
array[position] = value;
Yes, because the index operator p[i] is 100% identical to *(ptr + i). You can in fact write 5[array] instead of array[5] and it will still work. In C arrays are actually just pointers. The only thing that makes an array definition different from a pointer is, that if you take a sizeof of a "true" array identifier, it gives you the actual storage size allocates, while taking the sizeof of a pointer will just give you the size of the pointer, which is usually the system's integer size (can be different though).
Also, if I am working with a dynamically allocated matrix, which one is the correct way to declare the function prototype: (…)
Neither of them because those are arrays of pointers to arrays, which can be non-contigous. For performance reasons you want matrices to be contiguous. So you just write
void foo(int matrix[])
and internally calculate the right offset, like
matrix[width*j + i]
Note that writing this using the bracket syntax looks weird. Also take note that if you take the sizeof of an pointer or an "array of unspecified length" function parameter you'll get the size of a pointer.
No, you'd just keep using array[position] = value.
In the end, there's no real difference whether you're declaring a parameter as int *something or int something[]. Both will work, because an array definition is just some hidden pointer math.
However, there's is one difference regarding how code can be understood:
int array[] always denotes an array (it might be just one element long though).
int *pointer however could be a pointer to a single integer or a whole array of integers.
As far as addressing/representation goes: pointer == array == &array[0]
If you're working with multiple dimensions, things are a little bit different, because C forces you declare the last dimension, if you're defining multidimensional arrays explicitly:
int **myStuff1; // valid
int *myStuff2[]; // valid
int myStuff3[][]; // invalid
int myStuff4[][5]; // valid

I'm trying to make 2d array, pass it to function and then update the modified array in main

The compiler shows:
Warning: passing argument 1 of 'fun' from incompatible
pointer type; note: expected 'int ()[5]' but argument
is of type 'int (*)[5][5]'
Code:
#include<stdio.h>
void fun(int * b[][5])
{
int x=11,y=90;
printf("here");
*b[1][3] = x;
*b[3][1] = y;
*b[2][2] = x + ++y;
}
int main()
{
int a[5][5];
a[1][3] = 12;
a[3][1] = 145;
fun(&a);
printf("%d %d %d",a[1][3],a[3][1],a[2][2]);
}
You do not need the asterisk in your function parameters, and you don't need to dereference the array b in your function. Arrays are passed by reference (so get rid of the ampersand in foo(&a) as well), because C treats them as pointers to the first element in the sequence.
Multidimensional arrays are treated as arrays of pointers to the start of smaller sub-arrays, i.e. arrays-of-arrays. Same explanation as above applies.
Your code should look like this in the end:
void fun(int b[][5]) // can also be (int (*b)[5]), i.e. array of 5 pointers
{
int x=11,y=90;
b[1][3] = x;
b[3][1] = y;
b[2][2] = x + ++y;
}
int main()
{ // ...
fun(a);
// ...
}
int a[5][5]; //is an 2d int array
When arrays are passed to a function, what really gets passed is a pointer to the arrays first element.
So calling the fun() function with fun(a) will actually pass the pointer to the a first element, in this case an int array of size 5. The function fun() will receive a pointer to an int array of size 5, that is to say int (*b)[5]. Note that int *b[5] is not the same and is an array of size 5 containing int pointers.
Your fun function can either have:
void fun(int b[][5])
or
void fun(int (*b)[5])
The first way to do it says that the function will receive a 2d array of ints, but since we know that what actually will be sent to the function is a pointer to the first element of the array a, the compiler will quietly compile the function as if the parameter were a pointer, since it's a pointer that it will receive.
The second way to do it explicitly shows what type it will receive, a pointer to an array of size 5.

Resources