Passing address of array as a function parameter - c

Recently, I was debugging one of my programs and found a mistake that I've constantly make, but it was not shown as a warning during compilation, so I've just assume everything was in place and was OK. I a bit confused on what's happening in the code below:
void foo(char b[2]);
char a[2] = {1, 2};
foo(a); // I always assumed that this would pass the entire array to be
// duplicate in stack, guess I was wrong all this while
// Instead the address of the array was passed
void foo(char b[2])
{
// Value of b[0], b[1]?
// Does this mean : 1) b[0] == &a[0]?
// or 2) b[0] == &a[0+2]?
// Compiler didn't complain, so I assume this is a valid syntax
}

When you pass an array as a parameter to a function it decays into a pointer, this is defined in the C standard in 6.7.1:
On entry to the function the value of each argument expression shall be converted to the type
of its corresponding parameter, as if by assignment to the parameter. Array expressions and
function designators as arguments are converted to pointers before the call. A declaration of a
parameter as “array of type” shall be adjusted to “pointer to type,”
This essentially means that in your function declaration it's equivalent to use
void foo(char b[2]); or
void foo(char b[]); or
void foo(char *b)
`

It is valid syntax, and yes, when passing an array the memory address of the first element is copied, but when you dereference the address, you are modifying the original array.

This is the same as the following:
// The array "char b[2]" "decays" to a pointer "char *b"
void foo(char *b)
{
// b[0] == a[0]
// also, b == a (two addresses, both the same)
}
You can read up on how arrays and pointers in C behave very similarly (but not exactly the same). Arrays decay to pointers if they're function arguments (but not anywhere else). The real gotcha here is that on a 64-bit system, sizeof(b) == 8 and sizeof(a) == 2, which is somewhat surprising unless you know about arrays decaying into pointers.

When you declare an array as a function parameter, it is treated as if it were a pointer. Your foo is completely identical to
void foo(char *b)
{
...
}
Arrays decay to pointers. In other words, in some uses (e.g. sizeof(a)) a is an array, but in others where a pointer is expected, the name a means the address of a[0].

b[0] = &a[0] if you do foo(a) as the argument.
If you pass foo((a+1)) then b[0] = &a[1] (you shouldn't do that though since b[1] would be undefined) and so on.

I should make a correction: the address of the array is not passed - it's the address of the array's first element. The simplest way of putting it is:
In C, the value of an array is a pointer to its first element.
If you work with arrays of arrays, you need to supply information about the sizes of arrays after the first dereference:
// either the following or: void foo(char param[][30][20])
void foo(char (*param)[30][20])
{
// ...
}
int main(void)
{
// bar is an array of 10 arrays of 30 arrays of 20 chars.
// its value's TYPE is 'pointer to an array of 30 arrays of 20 chars,
// which is what foo above requires.
char bar[10][30][20];
foo(bar);
}

Related

How does passing an array to another C function work?

This is causing me a great deal of confusion.
If I have the following array:
int arr[6];
// I then fill indices 0-5 with ints
And I want to pass that to a function that uses the array as a parameter, what does the function header look like?
Would it be void saveArray(int *arr) or void saveArray (int arr)? And then how would I call the function? saveArray(arr) or saveArray(&arr)?
As I understand it, while that initial array is not a pointer, it effectively acts as one as it decays into a pointer to the first element. So my intuition it that I should pass it like saveArray(arr) and the header should be void saveArray(int *arr). Would that be right?
Why do I want a pointer to the initial array and not just the array itself? What does &arr even represent?
In C, parameters passed in functions can only be passed by value.
In addition to that, in C you can't pass an array as a parameter to a function. However, you can pass by value a pointer to the first cell of the array.
Thus, your function's prototype would be:
void saveArray(int *arr)
which you'd call by
saveArray(arr);
Why do I want a pointer to the initial array and not just the array
itself?
That's because you cannot pass an array to a function. An array is not a first-class object in C unlike int, float, struct etc. This means an array is not copied to the function parameter. What actually gets passed is a pointer to the first element of the array. Therefore, the function parameter should be a pointer to the array element type. Also, you have to pass the length of the array to function as well since that information cannot be had in the function from the pointer that is passed to it.
An array is a different type than a pointer. There are some cases when it decays or is implicitly converted to a pointer to its first element. Therefore, your function should have the prototype
void saveArray(int *arr, int len);
// or
void saveArray(int arr[], int len);
// in main, for example
int arr[6];
saveArray(arr, sizeof arr);
// equivalent to
saveArray(&arr[0], sizeof arr);
What does &arr even represent?
The address of operator & evaluates the address of its operand which must be an lvalue. Here arr is of type int[6], i.e., an array of 6 integers. Therefore &arr is of type int (*)[6], i.e., a pointer to an array of 6 integers. Please note that the value &arr is equal to the base address of the array but its type is not int *. It is a different type and has different pointer arithmetic. This is, in fact, one of the cases where an array does not decay into a pointer to its first element.
Yes
void saveArray(int *arr)
But for it to be useful, pass the array length too.
void saveArray(int *arr, int len)
Otherwise how will you know how long it is?
Call then like so:
saveArray(arr, 6);
The question "Would it be void saveArray(int *arr) or void saveArray (int arr)?" has already been answered. I am going to answer the question "What does &arr even represent?"
In your case, &arr has the same numerical value as &arr[0]. However, if you did something a bit different,
int* arr = malloc(sizeof(int)*6);
Then the numerical value of &arr will be different than that of &arr[0] even though you will be able to call saveArray(arr) without any difference in meaning for both cases.
In the first case, both &arr and &arr[0] are addresses on the stack.
In the second case, &arr is an address on the stack while &arr[0] is an address in the heap.
Hope that helps.
If you use this prototype:
void saveArray(int *arr)
you loose information about the array length (e.g. number of elements).
Unless your function is supposed to operate on arrays with fixed length (e.g. some functions doing 3D math calculations may just consider 3D vectors, with fixed size of 3 double elements), you should specify the array length (e.g. element count) as an additional parameter:
void saveArray(int * arr, int count);
If your function just observes the content of the input array and does not modify it, you can use const to make your code const-correct and more precise:
void saveArray(const int * arr, int count);
Sometimes size_t is used as a type to specify length/count parameters:
void saveArray(const int * arr, size_t count);
About the other option you listed in your question:
void saveArray(int arr)
That is wrong, since in this case arr is just a single integer (not an array).
Instead, in the first (correct) case of passing [const] int*, you passed the address of the first item in the array, and since the array elements are stored in contiguous memory locations, just the address of the first item and the item count define the whole array.
At the call site, you can call your function like this:
int arr[<<some size here>>];
...
saveArray(arr, <<same size as above>>);
Or if you already have a pointer (e.g. since you allocated the array using malloc()), you can just specify the pointer itself:
int* arr;
arr = malloc( numberOfElements * sizeof(int) );
...
saveArray(arr, numberOfElements);

difference between &array[0] and &array when passed to a C function

Is there a difference between &array[0] and &array when passed to a C Function. This array is a void* array which currently takes integer as data.
Added the test code
#include <iostream>
#include <conio.h>
using namespace std;
int read_buffer[10] = {0,0,0,0,0,0,0,0,0,0};
int write_buffer[10] = {0,1,2,3,4,5,6,7,8,9};
void WriteBlock(void* SrcPtr)
{
//WriteBlock will use SrcPtr and store the data to a common memory block which ReadBlock will access.
}
void ReadBlock(void* DstPtr)
{
//ReadBlock function will fetch data from readBuffer and put the data back into the *DstPtr.
}
void main()
{
WriteBlock((int*)&write_buffer);
//Is there a difference between these two below calls.
ReadBlock(&read_buffer[0]);
ReadBlock(&read_buffer);
}
Yes, there's a big difference, and it depends on context.
Consider this:-
char arrayA[10];
char *arrayB;
&arrayA[0] and &arrayB[0] both have type char *.
But &arrayA has type char (*)[10] while &arrayB has type char ** - the address of the pointer.
For arrayA, these point to the same address - but for arrayB, they do not! There's a common C misconception that "pointers and arrays are the same". This is a great example of where they are absoluelty not,
See this : http://ideone.com/OcbuXZ
Assuming array is declared
void *array[N];
then the expressions &array[0] and &array will yield the same value (the address of the first element of the array is the same as the address of the array itself), but will have different types.
Expression Type
---------- ----
&array void *(*)[10] -- pointer to 10-element array of `void *`
&array[0] void ** -- pointer to pointer to void
Your function prototype will need to match up with whichever expression you pass. If you call the function as
func(&array);
then the function prototype needs to be
void func(void *(*arrp)[10]) {...}
If you call the function as
func(&array[0]);
then the function prototype needs to be
void func(void **arrp) {...}
although in that case you should pass the size of the array as a separate parameter.
Now, assuming array is declared
void **array = malloc(sizeof *array * N);
then the expressions &array and &array[0] will yield different values and different types.
Expression Type
---------- ----
&array void ***
&array[0] void **
&array will give you the address of the array variable itself, which is different from the address of the heap memory that's been allocated for the array. Again, your function prototype will need to match up with the type of the expression you use.
If array is really an array, then
&array[0] is the pointer to element 0 of array[]
&array is the pointer to the entire array[]
So, these two expressions are of different types. And that's the main difference that may cause your code to fail to compile if you pass the wrong one of the two.
At the low level, however, the two pointers are going to hold the same address.
Yes there is a big different
&array[0]==>void**
AND
&array==>void***
This won't compile, you are using a void * and try to get the first element of it. But what size does it have? The compiler doesn't know. Using int * may compile, if you are not trying something like this:
int main (void) {
int *arr = malloc( 10 );
arr = &arr[0]; // this is ok
arr = &arr; // wrong data type
}
&array returns an int **, &array[0] returns int *. These are different data types.

C Programming - Pass-by-Reference

In the C program below, I don't understand why buf[0] = 'A' after I call foo. Isn't foo doing pass-by-value?
#include <stdio.h>
#include <stdlib.h>
void foo(char buf[])
{
buf[0] = 'A';
}
int main(int argc, char *argv[])
{
char buf[10];
buf[0] = 'B';
printf("before foo | buf[0] = %c\n", buf[0]);
foo(buf);
printf("after foo | buf[0] = %c\n", buf[0]);
system("PAUSE");
return 0;
}
output:
before foo | buf[0] = 'B'
after foo | buf[0] = 'A'
void foo(char buf[])
is the same as
void foo(char* buf)
When you call it, foo(buf), you pass a pointer by value, so a copy of the pointer is made.
The copy of the pointer points to the same object as the original pointer (or, in this case, to the initial element of the array).
C does not have pass by reference semantics in the sense that C++ has pass by reference semantics. Everything in C is passed by value. Pointers are used to get pass by reference semantics.
an array is just a fancy way to use a pointer. When you pass buf to the function, you're passing a pointer by value, but when you dereference the pointer, you're still referencing the string it points to.
Array as function parameter is equivalent to a pointer, so the declaration
void foo( char buf[] );
is the same as
void foo( char* buf );
The array argument is then decayed to the pointer to its first element.
Arrays are treated differently than other types; you cannot pass an array "by value" in C.
Online C99 standard (draft n1256), section 6.3.2.1, "Lvalues, arrays, and function designators", paragraph 3:
Except when it is the operand of the sizeof operator or the unary & operator, or is a
string literal used to initialize an array, an expression that has type ‘‘array of type’’ is
converted to an expression with type ‘‘pointer to type’’ that points to the initial element of
the array object and is not an lvalue. If the array object has register storage class, the
behavior is undefined.
In the call
foo(buf);
the array expression buf is not the operand of sizeof or &, nor is it a string literal being used to initialize an array, so it is implicitly converted ("decays") from type "10-element array of char" to "pointer to char", and the address of the first element is passed to foo. Therefore, anything you do to buf in foo() will be reflected in the buf array in main(). Because of how array subscripting is defined, you can use a subscript operator on a pointer type so it looks like you're working with an array type, but you're not.
In the context of a function parameter declaration, T a[] and T a[N] are synonymous with T *a, but this is only case where that is true.
*char buf[] actually means char ** so you are passing by pointer/reference.
That gives you that buf is a pointer, both in the main() and foo() function.
Because you are passing a pointer to buf (by value). So the content being pointed by buf is changed.
With pointers it's different; you are passing by value, but what you are passing is the value of the pointer, which is not the same as the value of the array.
So, the value of the pointer doesn't change, but you're modifying what it's pointing to.
arrays and pointers are (almost) the same thing.
int* foo = malloc(...)
foo[2] is the same as *(foo+2*sizeof(int))
anecdote: you wrote
int main(int argc, char *argv[])
it is also legal (will compile and work the same) to write
int main(int argc, char **argv)
and also
int main(int argc, char argv[][])
they are effectively the same. its slightly more complicated than that, because an array knows how many elements it has, and a pointer doesn't. but they are used the same.
in order to pass that by value, the function would need to know the size of the argument. In this case you are just passing a pointer.
You are passing by reference here. In this example, you can solve the problem by passing a single char at the index of the array desired.
If you want to preserve the contents of the original array, you could copy the string to temporary storage in the function.
edit: What would happen if you wrapped your char array in a structure and passed the struct? I believe that might work too, although I don't know what kind of overhead that might create at the compiler level.
please note one thing,
declaration
void foo(char buf[])
says, that will be using [ ] notation. Not which element of array you will use.
if you would like to point that, you want to get some specific value, then you should declare this function as
void foo(char buf[X]); //where X would be a constant.
Of course it is not possible, because it would be useless (function for operating at n-th element of array?). You don't have to write down information which element of array you want to get. Everything what you need is simple declaration:
voi foo(char value);
so...
void foo(char buf[])
is a declaration which says which notation you want to use ( [ ] - part ), and it also contains pointer to some data.
Moreover... what would you expect... you sent to function foo a name of array
foo(buf);
which is equivalent to &buf[0]. So... this is a pointer.
Arrays in C are not passed by value. They are not even legitimate function parameters. Instead, the compiler sees that you're trying to pass an array and demotes it to pointer. It does this silently because it's evil. It also likes to kick puppies.
Using arrays in function parameters is a nice way to signal to your API users that this thing should be a block of memory segmented into n-byte sized chunks, but don't expect compilers to care if you spell char *foo char foo[] or char foo[12] in function parameters. They won't.

(gcc) Multi-Dim Array or Double Pointer for Warning-free Compile

I have a function, which is called sometimes with regular, sometimes dynamic arrays.
If I define the function as
function_name(int[10][10] a)
and send int** as a parameter, I get a warning. Opposite, if I declare
function_name(int** a)
and send int[][] as a parameter (after casting) I cannot access to array elements inside function.
What is the correctest way?
When an array is passed to a function, it "decays" to a pointer to its first element. So, given:
T a[10];
f(a);
In the call f(a), a is actually &a[0], i.e., a pointer, and the type is T * (the type of &a[0]).
When you have an array of arrays, the same rule applies:
T a[10][5];
f(a);
a decays to a pointer again, equal to &a[0]. a[0] is of type "array [5] of T". So, &a[0] is of type "pointer to array [5] of T", i.e., if you were to declare a pointer p to set equal to &a[0], you would do:
T (*p)[5]; /* parentheses because [] binds tighter than * */
p = &a[0];
Given the above, and assuming your array is declared in the calling code as int a[10][10];, you should declare your function as:
function_name(int (*a)[10]);
For more, see this.
There is a syntax error in function_name(int[10][10] a)—you need to specify the array size after the "variable" name: function_name(int a[10][10]). In fact, the above is equivalent to function_name(int (*a)[10]), because of the "decaying" mentioned above.
Edit: ah, I think I understand now. You cannot declare a function that takes both a "two dimensional" array and a pointer-to-pointer, for the reasons mentioned above (the "decaying" to pointer happens only once). A pointer to pointer may not point to contiguous data, and may have different number of elements in each "row". An array of arrays doesn't cannot have those properties. They are fundamentally different.
int ** and int [][] are not the same.
The former is pointer to pointer to int whereas second one is 2-d array of int.
int[][] decays to int (*)[] when you pass it as argument to function.
void func(int arr[][10]) { //decays to `int (*arr)[10]`
printf("%d correct", arr[1][9]); //10th element of 2nd row
//printf("%d correct", (*(arr + 1))[9]); //same as above
}
int main() {
int (*arr)[10]; //pointer to array of ints
arr = malloc(sizeof(int (*)[]) * 2); //2 rows & malloc will do implicit cast.
arr[1][9] = 19;
func(arr);
return 0;
}

Pointers, arrays and passing pointers to methods

Confused with the problem here. New to C, as made obvious by the below example:
#include <stdlib.h>
#include <stdio.h>
void pass_char_ref(unsigned char*);
int main()
{
unsigned char bar[6];
pass_char_ref(&bar);
printf("str: %s", bar);
return 0;
}
void pass_char_ref(unsigned char *foo)
{
foo = "hello";
}
To my understanding, bar is an unsigned character array with an element size of 6 set away in static storage. I simply want to pass bar by reference to pass_char_ref() and set the character array in that function, then print it back in main().
You need to copy the string into the array:
void pass_char_ref(unsigned char *foo)
{
strcpy( foo, "hello" );
}
Then when you call the function, simply use the array's name:
pass_char_ref( bar );
Also, the array is not in "static storage"; it is an automatic object, created on the stack, with a lifetime of the containing function's call.
Two things:
You don't need to pass &bar; just pass bar.
When you pass an array like this, the address of its first (0th) element is passed to the function as a pointer. So, call pass_char_ref like this:
pass_char_ref(bar);
When you call pass_char_ref like this, the array name "decays" into a pointer to the array's first element. There's more on this in this tutorial, but the short story is that you can use an array's name in expressions as a synonym for &array_name[0].
Pointers are passed by value. You have:
void pass_char_ref(unsigned char *foo)
{
foo = "hello";
}
In some other languages, arguments are passed by reference, so formal parameters are essentially aliases for the arguments. In such a language, you could assign "hello" to foo and it would change the contents of bar.
Since this is C, foo is a copy of the pointer that's passed in. So, foo = "hello"; doesn't actually affect bar; it sets the local value (foo) to point to the const string "hello".
To get something like pass by reference in C, you have to pass pointers by value, then modify what they point to. e.g.:
#include <string.h>
void pass_char_ref(unsigned char *foo)
{
strcpy(foo, "hello");
}
This will copy the string "hello" to the memory location pointed to by foo. Since you passed in the address of bar, the strcpy will write to bar.
For more info on strcpy, you can look at its man page.
In C, arrays are accessed using similar mechanics to pointers, but they're very different in how the definitions work - an array definition actually causes the space for the array to be allocated. A pointer definition will cause enough storage to be allocated to refer (or "point") to some other part of memory.
unsigned char bar[6];
creates storage for 6 unsigned characters. The C array semantics say that, when you pass an array to another function, instead of creating a copy of the array on the stack, a pointer to the first element in the array is given as the parameter to the function instead. This means that
void pass_char_ref(unsigned char *foo)
is not taking an array as an argument, but a pointer to the array. Updating the pointer value (as in foo = "hello";, which overwrites the pointer's value with the address of the compiled-in string "hello") does not affect the original array. You modify the original array by dereferencing the pointer, and overwriting the memory location it points to. This is something that the strcpy routine does internally, and this is why people are suggesting you use
void pass_char_ref(unsigned char *foo)
{
strcpy(foo, "hello");
}
instead. You could also say (for sake of exposition):
void pass_char_ref(unsigned char *foo)
{
foo[0] = 'h';
foo[1] = 'e';
foo[2] = 'l';
foo[3] = 'l';
foo[4] = 'o';
foo[5] = 0;
}
and it would behave correctly, too. (this is similar to how strcpy will behave internally.)
HTH
Please see here to an explanation of pointers and pass by reference to a question by another SO poster. Also, here is another thorough explanation of the differences between character pointers and character arrays.
Your code is incorrect as in ANSI C standard, you cannot pass an array to a function and pass it by reference - other data-types other than char are capable of doing that. Furthermore, the code is incorrect,
void pass_char_ref(unsigned char *foo)
{
foo = "hello";
}
You cannot assign a pointer in this fashion to a string literal as pointers use the lvalue and rvalue assignment semantics (left value and right value respectively). A string literal is not an rvalue hence it will fail. Incidentally, in the second link that I have given which explains the differences between pointers and arrays, I mentioned an excellent book which will explain a lot about pointers on that second link.
This code will probably make more sense in what you are trying to achieve
void pass_char_ref(unsigned char *foo)
{
strcpy(foo, "hello");
}
In your main() it would be like this
int main()
{
unsigned char bar[6];
pass_char_ref(bar);
printf("str: %s", bar);
return 0;
}
Don't forget to add another line to the top of your code #include <string.h>.
Hope this helps,
Best regards,
Tom.
Since bar[] is an array, when you write bar, then you are using a pointer to the first element of this array. So, instead of:
pass_char_ref(&bar);
you should write:
pass_char_ref(bar);
Time again for the usual spiel --
When an expression of array type appears in most contexts, its type is implicitly converted from "N-element array of T" to "pointer to T" and its value is set to point to the first element of the array. The exceptions to this rule are when the array expression is the operand of either the sizeof or & operators, or when the array is a string litereal being used as an initializer in a declaration.
So what does all that mean in the context of your code?
The type of the expression bar is "6-element array of unsigned char" (unsigned char [6]); in most cases, the type would be implicitly converted to "pointer to unsigned char" (unsigned char *). However, when you call pass_char_ref, you call it as
pass_char_ref(&bar);
The & operator prevents the implicit conversion from taking place, and the type of the expression &bar is "pointer to 6-element array of unsigned char" (unsigned char (*)[6]), which obviously doesn't match the prototype
void pass_char_ref(unsigned char *foo) {...}
In this particular case, the right answer is to ditch the & in the function call and call it as
pass_char_ref(bar);
Now for the second issue. In C, you cannot assign string values using the = operator the way you can in C++ and other languages. In C, a string is an array of char with a terminating 0, and you cannot use = to assign the contents of one array to another. You must use a library function like strcpy, which expects parameters of type char *:
void pass_char_ref(unsigned char *foo)
{
strcpy((char *)foo, "hello");
}
Here's a table of array expressions, their corresponding types, and any implicit conversions, assuming a 1-d array of type T (T a[N]):
Expression Type Implicitly converted to
---------- ---- -----------------------
a T [N] T *
&a T (*)[N]
a[0] T
&a[0] T *
Note that the expressions a, &a, and &a[0] all give the same value (the address of the first element in the array), but the types are all different.
The use of the address of operator (&) on arrays is no longer allowed. I agree that it makes more sense to do &bar rather than bar, but since arrays are ALWAYS passed by reference, the use of & is redundant, and with the advent of C++ the standards committee made it illegal.
so just resist the urge to put & before bar and you will be fine.
Edit: after a conversation with Roger, I retract the word illegal. It's legal, just not useful.

Resources