You can pass argument in different ways in C (Captain Obvious, yes).
By value. Then it is copied to stack. So function has local copy of variable in function frame. Any changes to argument do not change passed value. It is like "read only" mode
Pass by pointer. Then copy of address of this variable is passed (so yes, it is still passed by value, but you pass value of address, not of whole argument). So this is like "read and write" mode. As you can access to passed variable through its address, you can change value of this variable outside function.
But! You still can not modify pointer.
So if you want to modify pointer, then you should pass pointer to pointer. That is like "read-write modify" mode:
If that was just pointer then there would be a memory leak:
because here you assign new address to local copy of address, and this argument would be destroyed after function completion.
UPD. For example, we have
inside function memory is allocated and pointer is assigned to local variable. Caller still keeps old value. After function call we lose address of memory so it can not be released.
Short conclusion: there is a simple rule - if need to change argument, pass pointer to it. So, if want to change pointer, pass pointer to pointer. If want to change double pointer, pass pointer to pointer to pointer.
Passing argument by pointer is also much faster, because you don't need to copy all value on the stack (of course, if value is bigger than pointer to this value, otherwise passing by pointer for read-only is pointless). But it is dangerous, because it could be modified inside function. So you can secure argument defining it with const keyword
This is really helpful when you work with 3rd party libraries: function signature tells you whether function can modify your argument or not. Though const is optional it is appropriate to write const keyword every time it is possible
Passing array. Usually, one also sends array size (hence, size_t) as argument. You pass array as pointer.
Sometimes you can find code where developer sends pointer to object instead of array, for example
In this case array of one element and pointer to element behave alike (though, they are not the same).
When calling a function, the exact mechanism for passing arguments (assigning arguments to parameters) depends on the evaluation strategy and how it is implemented. Some common ways of passing arguments to a function are:
- by value
- by reference
- by object
This is not a theoretical article about passing arguments and doesn’t contain rigorous definitions. I just will try to show clearly how the above mechanisms work on some specific languages widely used: C, C++, Python and Perl.
In C, a variable declaration doesn’t create anything, it just ensures that, at runtime, there will be a chunk of memory in the stack big enough to hold the variable value. Keeping that in mind let’s look at the following simple code:
In the above example we have two variable declarations, one for and one more for . They point to different chunks of memory. When the function is called its arguments are evaluated and a copy of their value is assigned to the function parameters (so contains a byte-to-byte copy of ). This is called to pass by value. When doing it there is no way to change the arguments from inside the function simply because one has no access to them. The only way to return a value to the caller is via the function’s return value.
Obviously that is memory inefficient when working with large values or nontrivial types. And it doesn’t allow to change in-place variables defined in the caller. C solves the problem by passing (by value) a pointer. In this case the passed value is a memory address i.e.; just a few bytes, so passing the argument is cheap in terms of memory. Although the original pointer and the passed pointer are different entities, they still point to the same memory address so the function can change the pointed data in-place:
C++ supports passing-by-value. However it doesn’t use pointers to deal with the problems of passing a large amount of data or changing values in-place. Instead it uses references. A C++ reference allows you to create a new name for a variable. The reference doesn’t contain a copy of the variable but behind the scenes it keeps around its address. So you can use the reference to read or change the original value stored in that variable:
int first = 1;
int second = 2;
After the swap will be 2 and will be 1. Notice that when we call the function we use regular variables, not references. But, in the function definition, the parameters are references. As a result when the function is called it receives an implicit reference to the variables used as arguments instead of a copy of them. This is called to pass by reference. It allows the function to access the original arguments, no a copy of them. And changes to those values inside the function will be seen outside the function.
Perl always passes by reference, but not in the same form that C++. The Perl syntax for defining functions doesn’t include a explicit signature so the programmer cannot declare a given parameter as being a reference as she does in C++. Perl passes by reference using an aliasing mechanism: when a function is called, all incoming arguments are flattened into a single list which is then aliased to the implicit variable @_. In this way the function gets implicit references to the arguments:
my $first = 1;
my $second = 2;
After the swap will be 2 and will be 1. Once again, notice that passing by reference doesn’t mean that we use Perl references as arguments, Perl references are another mechanism provided by Perl for modifying values in-place. The important thing is that when the function is called it receives implicit references to the arguments. Therefore we are passing by reference. Also notice that the flattening of arguments can be tricky (although this quirk has nothing to do with the fact that Perl passes by reference. If you are interested, you can find nice details about flattening here ).
To the end to simulate pass-by-value one needs to do explicit copies of the arguments inside the function:
print $name; # output "Chuck"
Things are different in Python. All Python values are objects (so they are first-class entities) that can be tagged with one or more names or can have no name at all. Variable names are just names (you can see it graphically here). As a result talking about pass-by-value or pass-by-reference makes non sense in Python (unless one consider that CPython is implemented in C. But I will stay at Python level in this section).
So how does Python pass arguments to a function? It passes by object. Let’s see what does it means with a couple of examples::
obj1 = 3
++++obj2 = 5
obj1 == 5 # Evaluates to false
We get the same result as passing by value. It is not an unexpected result if one remember what we have said about object names at the beginning of this section. The object named is passed itself to the function. When doing so a new tag, , is added to it. Now the object has two names, and . The effect of the assignment inside the function is to move the name to a new object whose value is 5. When the function ends the object named goes away and the passed object remains untouched and can still be accessed with the name.
In the following example we pass a mutable object to a function in order to simulate a pass by reference:
list1 = 
list1 # Evaluates to [1, 2]
Now we get the same result as passing by reference i.e; the argument is changed in-place. The object named is passed to the function and a new tag, , is attached to it. In this case the new name is never reassigned to a new value. Instead, a method call modifies the object in-place. When the function ends the tag goes away but the modified object is still accessible via its tag.
- C always passes by-value. Functions can use pointer arguments to change caller variables in-place.
- C++ supports both, pass-by-value and pass-by-reference.
- Perl always passes by-reference. Functions can do local copies of its arguments in order to simulate passing by-value.
- Python passes by-object. Functions can simulate passing by-value and passing by-reference.
Categories: Programming LanguagesTags: C, passing arguments, Perl, Python