-
Consider the following sequence of declarations:
z : integer;
procedure p (x:integer) < body >;
Write a < body > for p so that the
following piece of code
z := 1; p(z); write(z)
will have all different outcomes in case of pass by value, pass by reference,
and pass by value-result.
Solution
A possible such body could be:
x := x+1 ; z := z+2
The outcome of the code would be:
- 3 with pass by value,
- 4 with pass by reference, and
- 2 with pass by value-result.
- Consider a procedure declaration with two parameters x and
y of type integer passed by
value-result:
procedure p(value-result x, y : integer); < body >
If we have a language that does not allow call by value-result, but
only call by reference, how can we define the procedure p so that
it has the same effect as the above one?
Hint: To see the difference between call by value-result and call by
reference, consider, for example, the case in which the body consists of the
commands
x:=x+1; y:=y+1
and the call associates x and y
to the same actual parameter.
Another case in which we observe a difference is
when one of the
actual parameters (say, z)
occurs in the body as a non-local (or global) parameter, and
the body contains instructions which modify z.
Solution
procedure p(var x1, y1 : integer);
var x,y : integer;
begin
x := x1;
y := y1;
< body >
x1 := x;
y1 := y
end;
Where x1 and y1
are two fresh variables, not occurring in < body >.
-
Consider the following procedure declaration:
procedure p;
x: integer;
procedure q;
begin x := x+1 end;
procedure r;
x: integer;
begin x := 1; q; write(x) end;
begin
x:= 2;
r
end;
What is the output produced by calling p
in
- A language with static scope
- A language with dynamic scope
Solution
- In a language with static scope the output would be 1
- In a language with dynamic scope the output would be 2
-
Consider the following program in C++:
#include < stdio.h >
int x=0;
void p(int,int);
void main(){
int x = 1;
p(x,x);
}
void p(int y, int z){
x = x+1;
y = y+1;
z = z+1;
printf("%d\n",x+y+z);
}
- What is the value printed? (Remember that C++ has static scope.)
- Suppose that we modify the declaration of p so to pass
the parameters by reference. Namely, we write the declaration as
p(int &y, int &z){...} .
What is the value printed in this case?
Solution
- The value printed is 5 (Since C++ has static scope, the x in the
body of p is the global variable, which has value 1 when the print instruction
is executed.)
- With call-by-reference the value printed is 7:
at the moment in which the print instruction is executed, in fact, x has
still value 1, while y and z point to the x local in main and
have value 3.
-
Consider the following fragment of code in Pascal:
var p,q : ^integer;
begin
new(p);
q := p;
p^ := 1;
q^ := p^ + 1;
write(p^);
dispose(p);
foo;
write(q^)
end
where foo is a procedure call (whose body does not contain occurrences
of either p or q).
- What is the value printed by write(p^)?
- Describe the situation (environment and state) relative to q
after
the execution of dispose(p). You can use a drawing if you want.
- Discuss what can happen when write(q^) is executed.
Solution
- The value printed by write(p^) is 2
- After the execution of dispose(p), q becomes
becomes a dangling reference. More precisely:
q is associated to a location L which contains
the address of the location L' (in the heap) which was previously
pointed by p. With dispose(p), such location
L' has been deallocated, i.e. is considered free for
further allocations. At the moment, L' should still contain the
value 2.
- We have two cases:
- If the execution of foo uses
the same location L'
(which in Pascal can only happen with dynamic allocation,
i.e. if foo executes an instruction of the form
new(r))) then we cannot predict what value is printed
with the instruction write(q^), since the value of L'
might have been changed by foo.
The same could happen in case of parallel processes allowed to access the same
heap and using L'.
- Otherwise, the value printed should be 2.
-
Consider the following procedure declaration in C:
void p() {int x; q = &x; *q = 1;}
where q is a global variable declared as pointer to int and
initialized by q = new int;. What output can we expect to
be produced by the following piece of code:
*q = 0; p(); r(); printf("%d\n",*q);
where r is a procedure which does not mention q.
Solution
We cannot predict the effect of printf("%d\n",*q):
When the procedure p terminates, x is deallocated and the reference
to it (namely q) becomes dangling. Such location could be re-used
for the local variables of r, and its value might have
changed by the time we execute printf("%d\n",*q).