int i; int count = 0; char * fred (char c, int i) { static int mark = 0; char * result = (char *) malloc (i + 2); count += i; { int k; for (k = 0; k < i; k++) result [k] = c; } result [i++] = 0; result [i] = ++mark; return result; } int main (void) { char * string; i = 5; string = fred ('a', i); printf ("%s, %d, %d\n", string, string [i+1], count); string = fred ('b', i); printf ("%s, %d, %d\n", string, string [i+1], count); return 0; }
We start with just the built-in names, at level 0.
char | |
int |
Global declarations are at level 1.
int i;
char | |
int | |
i |
int count = 0;
char | |
int | |
i | |
count |
Declarations within functions are (initially) at level 2. The eventual position of fred in the compiled code is currently unknown. The new declaration for i, as a parameter, temporarily overrides the previous declaration (global variable).
char * fred (char c, int i)
{
char | ||
int | ||
i | ||
count | ||
fred | ||
c |
static int mark = 0;
char | ||
int | ||
i | ||
count | ||
fred | ||
c | ||
mark |
char * result = (char *) malloc (i + 2);
char | ||
int | ||
i | ||
count | ||
fred | ||
c | ||
mark | ||
result | ||
malloc |
We don't have a declaration for malloc, so we have to try to construct something for it.
count += i;
At this point, for example, when we look up i, we find information
describing it as a parameter of fred, rather than a global variable.
Also, when we look up count, we discover that it is a variable,
so it can be assigned to, and it and i are integers, so we know what
sort of addition to perform.
The inner block starts a new level, level 3.
{
int k;
char | ||
int | ||
i | ||
count | ||
fred | ||
c | ||
mark | ||
result | ||
malloc | ||
k |
for (k = 0; k < i; k++)
result [k] = c;
}
char | ||
int | ||
i | ||
count | ||
fred | ||
c | ||
mark | ||
result | ||
malloc | ||
k |
As we exit level 3, the variable k is no longer visible, so we detach the corresponding property from the name-list. However, we retain the name-list entry for k, as it may occur again lower down.
result [i++] = 0;
result [i] = ++mark;
return result;
}
char | |
int | |
i | |
count | |
fred | |
c | |
mark | |
result | |
malloc | |
k |
As we exit level 2, we discard the declarations made inside it (c, i, mark, result). In particular, we have to reconnect i to its original declaration as a global variable. We don't completely discard the entries for the parameters, as we need them to check calls to fred lower down.
int main (void)
{
char | |||
int | |||
i | |||
count | |||
fred | |||
c | |||
mark | |||
result | |||
malloc | |||
k | |||
main |
char * string;
char | |||
int | |||
i | |||
count | |||
fred | |||
c | |||
mark | |||
result | |||
malloc | |||
k | |||
main | |||
string |
i = 5;
At this point, for example, when we look up i, we find information
describing it as a global variable, rather than a parameter of fred.
string = fred ('a', i);
printf ("%s, %d, %d\
n", string, string [i+1], count);
char | |||
int | |||
i | |||
count | |||
fred | |||
c | |||
mark | |||
result | |||
malloc | |||
k | |||
main | |||
string | |||
printf |
string = fred ('b', i);
printf ("%s, %d, %d\
n", string, string [i+1], count);
return 0;
}
char | |||
int | |||
i | |||
count | |||
fred | |||
c | |||
mark | |||
result | |||
malloc | |||
k | |||
main | |||
string | |||
printf |
int i int count 0 char*() fred () char c int i {} st.int mark 0 char* result (char*) malloc + i 2 += count i {} int k for = k 0 < k i post++ k = [] result k c = [] result post++ i 0 = [] result i pre++ mark return result int() main () void {} char* string = i 5 = string fred 'a' i printf "%s, %d, %d\en" string [] string + i 1 count = string fred 'b' i printf "%s, %d, %d\en" string [] string + i 1 count return 0