1. Show the lifetimes of the variables in the following C program and indicate which are statically vs. dynamically allocated.
int m;
void S () {
float z;
z = 1.0;
}
void R (int n) {
if (n 0)
R(n-1);
S();
}
int main() {
m = 3;
R(1);
return 1;
}Note that R will be activated twice, recursively.
Solution:
enter execution - m is a static variable
enter R - n born
enter R recursively - n (version 2) born
enter S - z born
exit S - z dies
exit recursive call to R - n (version 2) dies
enter S - z born
exit S - z dies
exit R - n dies
exit program - m dies2. In the following C program skeleton, identify all the name spaces by stating to which name space each name belongs. Also indicate the scope of each name. Note, C has static scoping.
int x, y, z;
int foo() {
{
int x;
}
}
foo2(int x) {
int y;
}
main() {
int y;
}
Solution:
There is a global name space. Nested within that are name spaces for foo, foo2, and main. Note that the name space for foo2 includes x. int x, y, z; x y z
| | |
int foo() { | | | foo
{ - | | | x (local)
int x; | | | |
| | | |
} | | | |
} - | | | - local var goes away
| | | |
foo2(int x) { - | | | foo2 x (local)
int y; - | | | | y (local)
| | | | |
} - | | | - - local vars go away
- | | | |
main() { | | | | | main
int y; | - | | | | y (local)
| | | | | |
} - - - - - - - all scopes end3.Can you explain what is wrong with the following Pascal program in terms of name-spaces and scopes? What about if Pascal had dynamic scoping?
program scope;
procedure foo()
begin
end;
procedure foo()
begin
end;
begin
foo();
end;
Solution:
foo is defined twice in the same name space, and the rules for Pascal state that that is not allowed. If Pascal had dynamic scoping, it would not make any difference because dynamic scoping has to do with the environment in which an expression is evaluated.4. In terms of name spaces and scopes, is the difference between variable x and variable y in the following Pascal program?
program scope;
var x: integer;
procedure foo()
begin
end;
var y: integer;
begin
foo();
end;
Solution:
The scope of x includes foo, but that of y does not.
5. Identify all the kinds of declarations in the following C program.
int x;
typedef int shortInt;
int foo(int z, int *q) {
int y;
return z + *q;
}
void main() { }
Solution:
This is a new-variable declaration.int x;
This is a type declaration (it renames an existing type).
typedef int shortInt;
This is a function declaration (and two new-variable declarations for the parameters).
int foo(int z, int *q)
This is a new-variable declaration.
int y;
This is a function declaration.
void main()
Recall: A declaration of a function or variable could be said to set up an association or binding between the declared identifier and the entity it will denote. An environment is the term used to denote a set of bindings. Each expression and command is interpreted in a particular environment, and all identifiers occurring in the expression or command must have bindings in that environment. Usually at most one binding per identifier is allowed in any environment.
6. Using the following C program discuss what bindings exist in the environments (global environment, main environment, foo environment) at various points in the code. Note that C has static binding or scoping.
int x;
char hello;
int foo(int z, int q) {
int y;
return z + q;
}
void main() {
int y[30];
char *str;
str = "hello";
y[1] = foo(23, 34);
str = "good-bye";
}
Solution:
At the global environment, x and hello are bound to statically allocated variables, while main and foo are bound to function abstractions. In the main environment, y is bound to a dynamically allocated variable, as is str. The environment foo is activated by the call within main. That environment consists of the global environment, main's environment, and the additional bindings for z, q, and y.
7. Explain specifically why GOTO is considered harmful.
Solution:
Because it can lead to ``spaghetti code''. With undisciplined use of gotos, you can branch from anywhere in a program to anywhere in a program. So programmers can physically separate portions of a program that should be kept close together (i.e., parts of an if-then-else structure). Ultimately, the use of gotos makes programs harder to read and maintain.8. Does C have multiple assignment? Does it have collateral assignment?
Solution:
C has multiple assignment. It does not have collateral assignment.9. Assume that the collateral operator is ``,'' and that the sequential operator is ``;''. Rewrite the following program using the collateral operators whenever you can (hint: look for read/write conflicts).
x = 4;
y = 23;
z = x + y;
printf("%d", z);
x = foo(x, y, z);
Solution:
x = 4, y = 23;
z = x + y;
printf("%d", z), x = foo(x, y, z); /* Assuming foo is side effect free!*/10. Discuss an important problem with the following code. Run the program and check the output of the program
#include<stdio.h>
int *foo() {
int x;
x = 2;
return &x;
}
int foo1(){
int y=675;
int z=90;
return y;
}
void main() {
int *x, *foo();
x = foo();
foo1();
printf("%d", *x);
}
Solution:
Dangling reference, foo() returns a pointer to the stack frame which is popped when the function is terminated. A new function foo1 is called. The address pointed to by x now contains different values.11. Why is a language that only supports allocation of static storage items limiting?
Solution:
It cannot support recursion or nested function calls since both require allocation of dynamic stack storage objects.12. In many programming languages strings are defined to be arrays of characters. Compare the consequences of this when a string variable is:
Consider string operations such as assignment, concatenation, and comparison.
Solution:
1. static array - We can do assignment between arrays that are the same size. But assignments from arrays of different sizes are tricky since we will have to ``pad'' or ``truncate'' the strings. We cannot concatenate two strings since that requires creating a bigger string. Comparison between arrays of the same size is easy since we can compare character by character. Again, we must be careful if the arrays are of different sizes and use a padding character (such as a blank space) during comparison. However, with static arrays, it is possible to do compile-time checks to make sure the arrays are of the same size and to disallow operations between arrays of different sizes.
2. dynamic array - The amount of space to allocate for a dynamic array is not decided until run-time. These will behave much the same as static arrays for strings, except that the compile-time check can no longer be performed (since we don't know until run-time how big a string will be).
3. flexible array - Assignment of any size string to any other size string is easy since strings do not have to be of any fixed size. Similarly it is no problem to concatenate and dynamically create larger strings. We may still have to pad with a blank character during comparison of unequal size strings.
So overall flexible arrays provide a more flexible implementation of strings, but these must be balanced with efficiency and ease of implementation. Perl and Icon use flexible array strings, but Pascal has a simpler and more efficient run-time storage manager, so it uses static arrays.