In C++ various options are possible to pass arguments to functions (pass by value, reference, pointer, reference to const, pointer to const, ...).
I was wondering what the Fortran analogue would be for all these options. This analogue would be from a concept point of view, and not an interoperability point of view.
As far as I know, Fortran passes its arguments by reference, with some exceptions to this rule (non-contiguous arrays). With this in mind, are the following conversions correct, or are there better attributes that can be given?
void f(X x); // Pass by value
This is a mere copy of the original value that is passed
SUBROUTINE f(x)
TYPE(X), VALUE :: x
...
END SUBROUTINE f
void f(X &x); // Pass by reference
Here x is a reference whose value is updated. As pass by reference is the "default" in Fortran, I see two possible options remaining: the argument an INTENT(OUT) or INTENT(INOUT)
SUBROUTINE f(x)
TYPE(X), INTENT([IN]OUT) :: x
...
END SUBROUTINE f
void f(X const &x); // Pass by reference-to-const
Here x is a reference whose value cannot be updated.
SUBROUTINE f(x)
TYPE(X), INTENT(IN) :: x
...
END SUBROUTINE f
void f(X *p); // Pass by pointer
This is a mere copy of a pointer that is passed. However, this would imply that the attributes POINTER and VALUE should be combined, but this is not allowed in Fortran. The only alternative I can imagine is
SUBROUTINE f(x)
TYPE(X), INTENT(INOUT) :: x
TYPE(X), POINTER :: p => x
...
END SUBROUTINE f
void f(X const *p); // Pass by pointer-to-const
Here p is a pointer pointing to a const which is copied over. This is, however, the same problem as with f(X *p)
SUBROUTINE f(x)
TYPE(X), INTENT(IN) :: x
TYPE(X), POINTER :: p => x
...
END SUBROUTINE f
void f(X * const p); // Pass by const-pointer
Here p is a pointer that cannot change, but the object it points to can. Again p is a copy and not a reference
SUBROUTINE f(x)
TYPE(X), INTENT(INOUT) :: x
TYPE(X), POINTER, PARAMETER :: p => x
...
END SUBROUTINE f
void f(X const * const p); // Pass by const-pointer
Here p is a pointer that cannot change and neither can the object it points to. Again p is a copy and not a reference
SUBROUTINE f(x)
TYPE(X), INTENT(IN) :: x
TYPE(X), POINTER, PARAMETER :: p => x
...
END SUBROUTINE f
void f(X * & p); // Pass by reference-to-pointer
This is a reference to a pointer, both p and the object it points to can change.
SUBROUTINE f(p)
TYPE(X), POINTER, INTENT([IN]OUT) :: p
...
END SUBROUTINE f
void f(X const * & p); // Pass by reference-to-pointer-to-const
Here p references a pointer to a constant object.
There seems to be no analogue here.
void f(X * const & p); // Pass by reference-to-const-pointer
Here p is a reference to a pointer that cannot change, but the object it points to can.
SUBROUTINE f(p)
TYPE(X), POINTER, INTENT(IN) :: p
...
END SUBROUTINE f
void f(X const * const & p); // Pass by reference-to-const-pointer-to-const
Here p is a reference to a pointer that cannot change, and neither can the object it points to. Is there an analogue here?
Related
How the above declaration of function pointers work in C/C++. I first encountered this declaration while making use of the signal.h file in c programming.
This is a function pointer decalaration
void (*var_name)(int)
In this example, var_name is a pointer to a function taking one argument, integer, and that returns void. It's as if you're declaring a function called "*var_name", which takes an int and returns void; now, if *var_name is a function, then var_name must be a pointer to a function
http://cyan-lang.org/jose/courses/06-2/lc/Ponteiros-para-Funcoes.htm
It's in Portuguese, Example:
in C, we can declare a pointer to function with the syntax
void (* f) ();
In this case, f is a pointer to a function with no parameters and that returns void. F can point to a compatible function:
F = maximum;
Maximum is a function declared as
void max () {
Puts ("Hi, I'm the max");
}
Maximum can be called from f using any of the syntax below.
(* F) (); / * Maximum call * /
F (); / * Maximum call * /
I came across a strange function pointer,
void * (*f1(void(*f2)(void)))(int ) ;
What does the f1 represent here ?
T (*f(U))(V)
declares f as a function which takes a U and returns a pointer to a function from V to T (i.e. a T (*)(V)).
So f1 is a function that takes a void (*)(void) and returns a void* (*)(int).
Naming the types makes it more readable:
typedef void (*parameter)();
typedef void* (*result)(int);
result f1(parameter f2);
(The name "f2" serves no purpose except for helping the human reading the code interpret it.)
For example, if F is a reference to an integer, where the reference is not permitted to be pointed to a new object once it is initially pointed to one.
Can I write to declaration like: const int & F?
I am confused about reference and pointer, because they both represent the address of something, but we always write parameter use reference as: const & F, I understand that this is to reduce the copy and does not allow others to change it, but are there any other meanings? and why do we need "const" after a function declaration like: int F(int z) const; this const makes the return type const or everything in the function const?
One more example,
void F(int* p)
{
p+=3;
}
int z=8;
F(&z);
std::cout<<z<<std::endl;
What is the output for z since z is a reference, and I pass it as a pointer who points to an integer.Increasing p by 3 just makes the address different and does not change its value?
Just a first pass at some answers - if anything is unclear please comment and I'll try to elaborate.
int a = 3;
declares an integer, a, with the initial value 3, but you are allowed to change it. For example, later you can do
a = 5; // (*)
and a will have the value 5. If you want to prevent this, you can instead write
const int a = 3;
which will make the assignment (*) illegal - the compiler will issue an error.
If you create a reference to an integer, you are basically creating an alias:
int& b = a;
, despite appearances, does not create a new integer b. Instead, it declares b as an alias for a. If a had the value 3 before, so will b, if you write b = 6 and print the value of a, you will get 6 as well. Just as for a, you can make the assignment b = 6 illegal by declaring it as const:
const int& b = a;
means that b is still an alias for a, but it will not be used to assign a different value to a. It will only be used to read the value of a. Note that a itself still may or may not be constant - if you declared it as non-const you can still write a = 6 and b will also be 6.
As for the question about the pointers: the snippet
void F(int* p) {
p += 3;
}
int z = 8;
F(&z);
does not do what you expected. You pass the address of z into the function F, so inside F, the pointer p will point to z. However, what you are doing then, is adding 3 to the value of p, i.e. to the address that p points to. So you will change to pointer to point at some (semi)random memory address. Luckily, it's just a copy, and it will be discarded. What you probably wanted to do, is increment the value of the integer that p points to, which would be *p += 3. You could have prevented this mistake by making the argument a int* const, meaning: the value of p (i.e. address pointed to) cannot be changed, but the value it points to (i.e. the value of z, in this case) can. This would have made *p += 3 legal but not the "erroneous" (unintended) p += 3. Other versions would be const int* p which would make p += 3 legal but not *p += 3, and const int* const` which would have allowed neither.
Actually, the way you have written F is dangerous: suppose that you expand the function and later you write (correctly) *p += 3. You think that you are updating the value of z whose address you passed in, while actually you are updating the value of a more-or-less random memory address. In fact, when I tried compiling the following:
// WARNING WARNING WARNING
// DANGEROUS CODE - This will probably produce a segfault - don't run it!
void F(int* p) {
p += 3; // I thought I wrote *p += 3
// ... Lots of other code in between, I forgot I accidentally changed p
*p += 3; // NOOOOOOOOOOO!
}
int main()
{
int z=8;
F(&z);
std::cout << z;
return 0;
}
I got a segmentation fault, because I'm writing at an address where I haven't allocated a variable (for all I know I could have just screwed up my boot sector).
Finally, about const after a function declaration: it makes the this pointer a const pointer - basically the compiler emits const A* this instead of just A* this. Conceptually, it states your intention that the function will not change the state of the class, which usually means it won't change any of the (internal) variables. For example, it would make the following code illegal:
class A {
int a;
void f() const {
a = 3; // f is const, so it cannot change a!
}
};
A a;
a.f();
Of course, if the function returns something, this value can have its own type, for example
void f();
int f();
int& f();
const int f();
const int& f();
are functions that return nothing, a (copy of) an integer, a (reference to) an integer, a constant (copy of) an integer, and a constant reference of an integer. If in addition f is guaranteed not to change any class fields, you can also add const after the brackets:
void f() const;
int f() const;
int& f() const;
const int f() const;
const int& f() const;
The way I remember the difference between references and pointers is that a reference must exist and the reference cannot change.
A pointer can be changed, and usually needs to be checked against NULL or tested to verify it points to a valid object.
Also, an object passed by reference can be treated syntactically like it was declared in the function. Pointers must use deferencing syntax.
Hope that helps.
You are confusing things.
First of all int z=8; F(&z); here z IS NOT a reference.
So let me start with the basics:
when found in a type declaration the symbol & denotes a reference, but in any other context, the symbol & means address of.
Similar, in a type declaration * has the meaning of declaring a pointer, anywhere else it it the dereferencing operator, denoting you use the value at an address.
For instance:
int *p : p is a pointer of type int.
x = *p : x is assigned the value found at address p.
int &r = a : r is reference of type int, and r refers the variable a.
p = &a : p is assigned the address of variable a.
Another question you have: the const at the end of a function, like int f(int x) const. This can be used only on non-static class methods and specifies that the function does not modify the object. It has nothing to do with the return value.
what is this syntax for double x[]?
Is it a C way to declare an array?
If I have a function like
void evaluate(double x[], double *f)
{
// evaluate
}
Can I pass a parameter x with any length?
A parameter of array type behaves exactly like it is a pointer. You can not truly pass an array as a function argument. However, this syntax gives the illusion that you can for the sake of readability. So your function is equivalent to:
void evaluate(double *x, double *f)
{
// evaluate
}
From §8.3.5/5 of ISO/IEC 14882:2011:
After determining the type of each parameter, any parameter of type “array of T” or “function returning T” is adjusted to be “pointer to T” or “pointer to function returning T,” respectively.
An expression that denotes an array will decay to a pointer to its first element, so you can still do this:
void evaluate(double x[]);
int array[] = {1, 2, 3, 4, 5};
evaluate(array); // The array decays to a pointer to its first element
From §4.2:
An lvalue or rvalue of type “array of N T” or “array of unknown bound of T” can be converted to a prvalue of type “pointer to T”. The result is a pointer to the first element of the array.
So yes, you can indeed pass an array of any length. In reality, you are just passing a pointer to the first element. You will, however, need to pass the length of the array as well, if you need it.
Arrays can be confusing, because in most contexts the name of an array decays into a pointer to its first element. So:
double x[3]; // x is an array of 3 doubles
void f(double x[3]); // f takes a pointer to double
f(x); // calls f with the address of x[0]
The reason for having the array type decay into a pointer for f is so that you don't have to have a separate function for every array size:
double x[3];
double y[4];
void f(double x[3], int size) {
for (int i = 0; i < size; ++i)
std::cout << x[i] << ' ';
std::cout << '\n';
}
f(x, 3);
f(y, 4);
It works the same way if the argument is double*x, double x[], double x[3], double x[17], double x[]; in all of these cases, x is treated as double*.
Inside the parameter list of a function, double x[] is same as double *x.
can I pass a parameter x with any length?
Yes, you can pass. But there's no way to know the length of the array x in the function evaluate. So you probably want to pass the length as well.
C FAQ, Section 6.4
Since arrays decay immediately into pointers, an array is never actually passed to a function. You can pretend that a function receives an array as a parameter, and illustrate it by declaring the corresponding parameter as an array:
void f(char a[])
{ ... }
Interpreted literally, this declaration would have no use, so the compiler turns around and pretends that you'd written a pointer declaration, since that's what the function will in fact receive:
void f(char *a)
{ ... }
There's nothing particularly wrong with talking about a function as if it ``receives'' an array, if the function is traditionally used to operate on arrays, or if the parameter is naturally treated within the function as an array.
This conversion of array-like declarators into pointers holds only within function formal parameter declarations, nowhere else. If the conversion bothers you, you're under no compulsion to make use of it; many programmers have concluded that the confusion it causes outweighs the small advantage of having the declaration ``look like'' the call or the uses within the function. (Note that the conversion happens only once; something like char a2[][] won't work. See questions 6.18 and 6.19.)
In other words, in a function parameter declaration, an array with unspecified length is the same as a pointer.
void evaluate(double x[], double *f)
{
// evaluate
}
is actually equivalent to:
void evaluate(double *x, double *f)
{
// evaluate
}
in C and C++.
It means the type of the x parameter is double * in both cases.
The argument x to your function is an array of unspecified length. That means that you can pass any array of type double to it, no matter the size. You can also pass a pointer to a double as argument.
There is one caveats though: You can't use the sizeof operator on the array x, as it doesn't have a size.
yes in c the array is declared like that
good read
Char array declaration and initialization in C
Simple C array declaration / assignment question
I'm looking few exercise from university about C++ and I found out this exercise:
#include <iostream>
using namespace std;
int& f(int*&);
int& f(int*& x) {
*x = 5;
return *x;
}
int main() {
int y = 1, x;
int* z = &y;
x= f(z);
cout << y << " " << x <<endl;
}
I was wondering: does <any type>*& has any real sense? Isn't f(int*& x) the same as f(int x)? Aren't you passing the pointer to the L-value of the variable?
f(int*& x) is not the same as f(int x). In the first case x is a reference to an integer pointer whereas in the second case x is just an integer.
Lets start from the basics:
When you write f(int &x) means that x is a reference to an integer and you can change the value of x in the function and the change will be reflected in the calling function.
Similarly, when you write f(int*& x), it means that x is reference to an integer pointer and when you change the address that x points to, the change will also be reflected in the calling function.
With int* &x you are passing the same pointer(by reference). Otherwise with only int* x you are passing a copy of the pointer and then you can't change the original one in the function. &x makes x an alias of the original parameter.
It's a reference to a pointer to an int. The function is then able to change the pointer if it wants to. In your example it doesn't make sense, but it obviously does have a use.
nope: *& here doesn't mean "dereference addressof". It means: "pass a pointer byref".
int& f(int*& x) {
*x = 5; // note: changes the pointee, not the pointer
return *x;
}
In this example, you don't gain anything by passing the pointer by reference, since you're not changing the pointer. Passing a pointer by reference is only needed when you intend to change the pointer:
void f(int*& x) {
x = new int(42); // note: changes the pointer
}
I think you are confusing sybols when they are used as operators or declarators.
If you use * when declaring variable, that means veriable is a pointer. When you use * as operator, that is dereference operator.
int *& name
simply means you are taking pointer to int by reference. **The * and & do not cancel each other out.**
If you had line of code like this:
var = *& var2;
then yes, it would be same as:
var = var2;