The difference between func and &func in memmory [duplicate] - c

So I figured when making function pointers, you do not need the operator & to get the address of the initial function:
#include <stdio.h>
double foo (double x){
return x*x;
}
int main () {
double (*fun1)(double) = &foo;
double (*fun2)(double) = foo;
printf("%f\n",fun1(10));
printf("%f\n",fun2(10));
printf("fun1 = %p \t &foo = %p\n",fun1, &foo);
printf("fun2 = %p \t foo = %p\n",fun2, foo);
int a[10];
printf(" a = %p \n &a = %p \n",a,&a);
return 0;
}
output:
>./a.out
100.000000
100.000000
fun1 = 0x4004f4 &foo = 0x4004f4
fun2 = 0x4004f4 foo = 0x4004f4
a = 0x7fff26804470
&a = 0x7fff26804470
Then I realized this is also true for arrays, meaning that if you have int a[10] both a and &a point to the same location. Why is that with arrays and functions? Is the address saved in a memory location that has the same address as the value(address) being saved in it?

Given int a[10], both a and &a yield the same address, yes, but their types are different.
a is of type int[10]. When it is implicitly converted to a pointer type, the pointer is of type int* and points to the initial element of the array. &a is of type int (*)[10] (that is, a pointer to an array of ten integers). Because there can be no padding in an array, they both yield pointers with the same value, but the pointers have different types.
Functions are similar to arrays, but not entirely the same. Your function foo is of type double(double). Whenever foo is used in an expression and is not the operand of the unary & operator, it is implicitly converted to a pointer to itself, which is of type double(*)(double).
So, for all practical purposes, the name of a function and a pointer to the same function are interchangeable. There are some subtleties, all of which I discuss in an answer to "Why do all these crazy function pointer definitions all work? What is really going on?" (That question was asked about C++, but the rules for nonmember functions in C++ are the same as for functions in C.)

No, there's no extra storage dedicated to pointing to the function/array.
With most variables variable_name has a meaning other than getting the address of that variable, so you need to use &variable to get the address.
With a function or array, function_name (by itself, not followed by parentheses) doesn't have any other meaning, so there was no problem with interpreting it as taking the address of the function.
Likewise in reverse: a normal pointer needs to be dereferenced explicitly, but a pointer to a function doesn't (again, because there's no other reasonable interpretation), so given a pointer to a function like:
int (*func)(param_list);
The following are equivalent to each other -- both call whatever function func points at:
(*func)(params);
func(params);

fun and &fun are exactly the same (except that sizeof(f) is illegal).
a and &a are the same up to pointer arithmetic: a + 10 == &a + 1, because 10*sizeof(*a) == sizeof(a) (where sizeof(*a) == sizeof(int)).

Basically, since the function name is "known" to be a function, the & is not strictly necessary. This behavior is the same for arrays. Recall that a function itself is not a variable, so it behaves a little differently than you might expect sometimes. If you have the 2nd edition of K&R, you can check out section 5.11 on pointers to functions, or the reference manual at the end,
Section A7.1 Pointer generation: If the type of an expression or
subexpression is "array of T" for some type T, then the value of the
expression is a pointer to the first object in the array, and the type
of the expression is altered to "pointer to T." This conversion does
not take place of the expression is the operand of the unary &
operator, ... Similarly, an expression of type "function returning T,"
except when used as the operand of the & operator, is converted to
"pointer to function returning T."
Section A7.4.2 Address Operator: The unary & operator takes the address
of its operand.... The result is a pointer to the object or function
referred to by the lvalue. If the type of the operand is T, the type
of the result is "pointer to T."
As far as I know, this is the same for C99.

printf("fun1 = %p \t &foo = %p\n",fun1, foo);
Here your are calling foo by passing Function Pointer with pass by value
and
printf("fun2 = %p \t foo = %p\n",fun2, &foo)
Here you are calling &foo by passing function Pointer with pass by reference
in both case your are calling the printf with function pointer only.
Remember foo itself is function pointer value and `not a variable.
Same happens with array.
int arr[10] translates into get continuous block of 10 Integers and address of first element is stored into arr. so arr is also a pointer.

Related

Am I Correctly Understanding Pass By Value and Pass By Reference in C?

In one of my course's tutorial videos, I have encountered a situation where pass by value and pass by reference is occurring. In the example he gives us, he, firstly, admits that the code is written poorly, and then asks us to find out what exactly would be printed. The relevant code is as follows:
void set_array(int array[4]);
void set_int(int x);
int main(void){
int a = 10;
int b[4] = {0, 1, 2, 3);
set_int(a);
set_array(b);
printf("%d %d\n", a, b[0]);
}
void set_array(int array[4]){
array[0] = 22;
}
void set_int(int x){
x = 22;
}
What I want to make sure, after initially coming up with the wrong output, is that I'm understanding why the correct output of "10, 22" is being printed.
The value of 10 is being printed because when the set_int function is being called, its parameter, being a variable, means that any variable can be passed. It is not exclusive to only the value 22 as defined in the set_int function.
The value of 22 is being printed because, when the set_array function is being called, its parameter, being an array, means that only the original value can be passed because it points to a specific memory location where the value 22 is stored.
Have I misunderstood what is happening, and am I missing any crucial points?
By Definition, there is no pass-by-reference in function calls in C. Both your examples use pass by value. However, depending on the usage, the result varies (i.e., we can emulate the behavior of passing by reference).
In the first case, the variable a is passed by value, hence it cannot be changed from the function call.
In the second case, the variable b is passed by value, hence it is also cannot be changed from the function call.
However, in the second case, there is a special phenomena that takes place. The argument which is passed, b is an array. An array, while passed as function argument (among many other usage), decays to a pointer to the first element of the array. So essentially, you're passing a pointer, and that value at the memory address pointed to by the pointer can be modified (but not the pointer itself). That's why, the change from the set_array() function persists in the main().
In another word, the second case is equivalent to
void set_pointer(int *ptr);
void set_int(int x);
int main(void){
int a = 10;
int b[4] = {0, 1, 2, 3);
int * p = &(b[0]); // address of the first element
set_int(a);
set_pointer(p); // pass the pointer
printf("%d %d\n", a, b[0]);
}
void set_array(int *ptr){
*ptr = 22; // operate on pointer
}
void set_int(int x){
x = 22;
}
Array expressions are special in C.
6.3.2.1 Lvalues, arrays, and function designators
...
3 Except when it is the operand of the sizeof operator, the _Alignof 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.
C 2011 online draft
When you call
set_array(b);
the expression b is converted from type "4-element array of int" to "pointer to int" (int *), and the value of the expression is the address of b[0]. Therefore, what set_array receives is a pointer value (&b[0]), not an array.
6.7.6.3 Function declarators (including prototypes)
...
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.
ibid.
Basically, in a function definition, any parameter declared as T a[N] or T a[] shall be interpreted as T *a - IOW, the parameter is treated as a pointer, not an array. Your function definition
void set_array(int array[4]){
array[0] = 22;
}
is treated as though it was written
void set_array(int *array){
array[0] = 22;
}
So arrays kind-of-sort-of-but-not-really get passed by reference in C. What really happens is that a pointer to the first element of the array gets passed by value. The array parameter in set_array designates a distinct object in memory from b, so any changes you make to array itself have no effect on b (IOW, you could assign a new value to array and have it point to a different object, but this assignment doesn't affect b at all). Instead, what you are doing is accessing elements of b through array.
In picture form:
+---+
b: | | b[0] <---+
+---+ |
| | b[1] |
+---+ |
| | b[2] |
+---+ |
| | b[3] |
+---+ |
... |
+---+ |
array: | | ---------+
+---+
One practical consequence of this is that sizeof array yields the size of the pointer type int *, not the size of the array, unlike sizeof b. That means you can't count the number of elements in the array using the sizeof array / sizeof array[0] trick. When you pass an array as an argument to a function, you should also pass the size of the array (that is, the number of elements) as a separate parameter unless the array contains a well-defined sentinel value (like the 0 terminator in strings).
Remember that the expression a[i] is defined as *(a + i) - given a starting address a, offset i elements (not bytes!) from that address and deference the result. If a is an array expression, it is first converted to a pointer expression before this computation is done. That's why you can access elements of b through array - array simply stores the address of the first element of b.
In C, all function arguments are passed by value - the formal argument in the function definition and the actual argument in the function call refer to distinct objects in memory, and the value of the actual argument gets copied to the formal argument. Changes to the formal argument are not reflected in the actual argument.
We fake pass-by-reference semantics by passing a pointer to the actual parameter and writing to the dereferenced pointer:
void foo( T *ptr )
{
*ptr = new_value(); // write a new value to the thing ptr points to
}
void bar( void )
{
T var;
foo( &var ); // have foo write a new value to var
}
IOW, writing to *ptr is the same as writing to var. Writing to ptr, OTOH, has no affect outside of foo.
In a true pass-by-reference system (like, say, Fortran) both the formal argument in the function definition and the actual argument in the function call designate the same object (in the "thing that takes up memory and can store values" sense, not the object-oriented "instance of a class" sense), so in those systems any changes to the formal argument are reflected in the actual argument (leading to a classic question on the Hacker Test, "Have you ever changed the value of 4? Unintentionally? In a language other than Fortran?")

function pointer and memory address in C [duplicate]

This question already has answers here:
Why do function pointer definitions work with any number of ampersands '&' or asterisks '*'?
(5 answers)
Closed 3 years ago.
In the following program, &foo, *foo and foo points to the same memory adress :
#include <stdio.h>
int foo(int arg)
{
printf("arg = %d\n", arg);
return arg;
}
int main()
{
foo(0); // ok
(*foo)(0); // ok
(&foo)(0); // ok
printf("&foo = %lx\n", (size_t)(&foo));
printf("foo = %lx\n", (size_t)(foo));
printf("*foo = %lx\n", (size_t)(*foo));
return 0;
}
the output is :
arg = 0
arg = 0
arg = 0
&foo = 55eeef54c720
foo = 55eeef54c720
*foo = 55eeef54c720
Does anyone can explain this ?
Thank you.
In the terminology of the C standard, any expression that has function type is a function designator. So, when used as an expression, the name of a function is a function designator.
There is nothing you can do with a function designator except take its address. You cannot add a number to a function designator, you cannot compare it to another function designator, and so on. Of course, you can call a function, but this is actually done by address, not by designator, as I will explain in a moment. Since there is nothing you can do with a function except take its address, C does this for you automatically. Per C 2018 6.3.2.1 4:
Except when it is the operand of the sizeof operator, or the unary & operator, a function designator with type "function returning type" is converted to an expression that has type "pointer to function returning type".
The result of this is:
In &foo, the & takes the address of foo, so &foo is the address of foo.
In foo, the function designator is automatically converted to the address of the function, so foo is &foo.
In *foo, the function designator is automatically converted to the address of the function. Then the * operator converts this back to the function, which produces a function designator. Then the automatic conversion happens again, and the function designator is converted back to the address of the function, so the result of *foo is &foo.
When you call a function, using the function ( argument-list... ) notation, the function must actually be a pointer to a function. Thus, you can call foo using (&foo)(arguments...). The automatic conversion simplifies the syntax so you can write foo(arguments...), but the call expression actually requires the address of the function, not the function designator.
Incidentally:
A proper printf specifier for size_t values is %zx, not %lx.
If you include <stdint.h>, it defines a type intended for converting pointers to integers, uintptr_t. This is preferably to converting pointers to size_t.
The function foo is implicitly convertible to a pointer to the function foo.
The unary & applied to a function yields a pointer to the function, just like it yields the address of variable when applied to a variable.
The unary * applied to a function pointer, yields the pointed-to function, just like it yields the pointed-to variable when it is applied to an ordinary pointer to a variable.
So here, foo is the same as &foo which is the same as *foo.
So *foo is same as *(&foo) which is the same as foo.

Why use the & sign to retrieve an integer's memory address, but not a function's address?

I'm currently following along with the Big Nerd Ranch's Objective-C guide, and one of the examples is as follows:
int main(int argc, const char * argv[])
{
int i = 17;
printf("i stores its value at %p\n", &i); return 0;
}
// output => i stores its value at 0xbffff738
int main(int argc, const char * argv[])
{
int i = 17;
printf("i stores its value at %p\n", &i);
printf("this function starts at %p\n", main); return 0;
}
// output => i stores its value at 0xbffff738
// this function starts at 0x100000ed0
I tried using the "&" symbol in front of main, and I get the same result- 0x100000ed0. But when I remove the ampersand from in front of "i", I see only 0x11 instead of 0xbffff738.
Question- why the difference? And why does one work with or without an ampersand, while the other seems to require it in order to produce the expected output?
An expression of function type (including a function name) is implicitly converted to a pointer to the function in most contexts. The exceptions are when it's the argument to a unary sizeof or & operator. sizeof function_name is illegal, but in &function_name the subexpression function_name is not converted to a pointer; the & operator then yields the function's address.
So given that foo is the name of a function, these expressions:
foo
&foo
*foo
**foo
***foo
...
all yield the address of the function.
There are similar rules for array expressions, which are usually converted to the address of the array's first element. There's one additional exception (a string literal used in an initializer for an array object), and &array_name is valid (it yields the address of the array object, which refers to the same address but has a different type than the address of the first element).
Incidentally, the %p format expects an argument of type void*. On many systems, all pointers have the same representation, so you can probably get away with passing any pointer value -- but there's no guarantee that it will work. For maximum safety and portability, you should print a pointer value by casting it to void*:
printf("i stores its value at %p\n", (void*)&i);
And there is no standard format for printing a function pointer value. This:
printf("this function starts at %p\n", (void*)main);
is likely to work, but strictly speaking the behavior of the conversion from int (*)(int, char **) (the type of the address of main) to void* is undefined. See this question for more information.
For 100% portability, you can extract the representation of a function pointer by treating it as an array of unsigned char, but it's probably not necessary.
i is not a pointer type but an integer type. You need the & operator to get its address.
main is a function designator and in an expression is converted to a pointer to a function in the usual conversion rules.
printf("this function starts at %p\n", &main); // OK, & yields a pointer to main
printf("this function starts at %p\n", main); // OK also, usual conversion rules
// yields a pointer to main
Note that the printf call is technically undefined behavior as p conversion specifier requires an argument of type void *.
In C, like array names which are converted to pointers to array's first element when passed to a function, function names are converted to the pointer to that function. In case of
printf("i stores its value at %p\n", (void *)&i);
i is not a pointer type and hence you need to pass a pointer type argument and this would be done by placing & before i in the argument.
in C, function name is handled specially. you can see three of these give the same output:
main
*main
&main
http://ideone.com/jMz0W4
unlike data identifiers, which have type tree system, function identifiers have no.

When are array names constants or pointers?

In a document by Nick Parlante, it says, Array names are constant i.e array base address behaves like a const pointer.
e.g
{
int array[100], i;
array = NULL; //cannot change base address
array = &i; // not possible
}
But at the same time why is this valid:
void foo(int arrayparm[]){
arrayparm = NULL; // says it changes the local pointer
}
Function parameter declarations are different then formal declaration is C, in function declaration:
void foo(int arrayparm[])
^^^^^^^^^ is pointer not array
arrayparm is pointer but not array its type is int*. This is equivalent to:
void foo(int *arrayparm)
In function foo you can modify arrayparm.
Whereas in formal declaration(in side function) e.g.
int array[100];
array is not a pointer but it is a constant, It is type is char[100] and it is not modifiable lvalue.
Arrays decay into pointers in functions. The array name is a non-modifable lvalue. What this means is that, you can do this:
int x=10,y=20;
int *p = &x; // <---- p Now points to x
p = &y; // <---- p Now points to y
But not this:
int arr[10], x=10;
arr = &x; // <----- Error - Array name is a non-modifiable lvalue.
Since arrays decay immediately into pointers, an array is never actually passed to a function. As a convenience, any parameter declarations which "look like" arrays, e.g.
f(a)
char a[];
are treated by the compiler as if they were pointers, since that is what the function will receive if an array is passed:
f(a)
char *a;
This conversion holds only within function formal parameter declarations, nowhere else. If this conversion bothers you, avoid it; many people have concluded that the confusion it causes outweighs the small advantage of having the declaration "look like" the call and/or the uses within the function.
References: K&R I Sec. 5.3 p. 95, Sec. A10.1 p. 205; K&R II Sec. 5.3 p. 100, Sec. A8.6.3 p. 218, Sec. A10.1 p. 226;
When array names are passed as function argument, it "decays" to a pointer. So you can treat it like a normal pointer.
Reference: C FAQ what is meant by the ``equivalence of pointers and arrays'' in C?
Array types are not assignable in C. It was just a design decision. (It is possible to make assignment of array types copy one array over another, like assignment of structs. They just chose not to do this.)
The C99 standard, 6.5.16 paragraph 2:
An assignment operator shall have a modifiable lvalue as its left
operand.
C99 standard, 6.3.2.1 paragraph 1:
... A modifiable lvalue is an lvalue that does not have array type,
...
Plus, even if array types were assignable, NULL is not a value of type int[100].

The value and address of an array are the same, except when passed to a function?

void pass_arr(int arr[]);
void pass_arr_test()
{
int arr[5] = {1,2,3,4,5};
printf( "arr = %p\n"
"&arr = %p\n\n", arr, &arr);
pass_arr(arr);
}
void pass_arr(int arr[])
{
printf( "passed arr = %p\n"
"passed &arr = %p\n\n", arr, &arr);
}
Output:
arr = 0x28ccd0
&arr = 0x28ccd0
passed arr = 0x28ccd0
passed &arr = 0x28ccc0
Can someone explain why the value and adress of arr points to the same adress when evaluated in the block where arr was created, but when passed the value and adress point to two different adresses?
That's because in the function arr is actually a pointer, not an array. Taking the address of a pointer does not yield the same address, the way it does for an array.
Except when it is the operand of the sizeof, _Alignof, or unary & operators, or is a string literal being used to initialize another array in a declaration, an expression of type "N-element array of T" will be converted ("decay") to type "pointer to T", and the value of the expression will be the address of the first element of the array1.
When you call
`pass_arr(arr)`;
the expression arr is converted from type "5-element array of int" to "pointer to int", or int *.
Note that the address of the first element of the array is the address of the array itself; that's why you get the same value when you print the results of arr and &arr int pass_arr_test, but remember that the types are different; the expression arr is converted to type int *, but &arr has type int (*)[5]; this matters for things like pointer arithmetic.
Secondly, in the context of a function prototype, declarations of the form T a[] and T a[N] are interpreted as T *a; a is actually declared as a pointer instead of an array.2
The important thing to remember is that arrays are not pointers. Rather, in most contexts, array expressions are converted to pointers as necessary.
1 - N1570, 6.3.2.1 Lvalues, arrays, and function designators, ¶ 3
2 - N1570, 6.7.6.3 Function declarators (including prototypes), ¶ 7
That is due to pass by value semantics where the arr in pass_arr method is a local pointer variable on the stack whose value is the location of the arr passed from pass_arr_test method. So, arr variable in both pass_arr and pass_arr_test are point to the same location and hence the value is same. Since they are two different pointers, their memory address is different. In case of array definition, arr is just an alias to the start of the array and hence it's location and it's value are the same.

Resources