下面的答案仅供参考!
1. 有哪些存储分配策略?并叙述何时用何种存储分配策略?
答:存储分配策略分为静态分配策略和动态分配策略两大类,而动态分配策略又可分为栈式动态分配策略和堆式动态分配策略两类。
在一个的具体的编译系统中,究竟采用哪种存储分配策略,主要应根据程序语言关于名称的作用域和生存期的定义规则。如果编译时能够确定一个程序运行时所需要的全部数据空间的大小(如 FORTRAN 语言),那么,在编译时就可安排好目标程序运行时的全部数据空间,这时可采用静态分配策略。
反之,则需要采用动态分配策略。至于采用栈式动态分配策略还是堆式动态分配策略,需要根据存储空间动态申请的特性决定。如果存储空间动态申请与释放服从“先请后还,后请先还”的原则,且程序的名字服从分程序结构所限定的作用范围(如 ALGOL语言),则可采用栈式动态分配策略。如果存储空间动态申请与释放没有约束关系,则必须采用堆式动态分配策略。
*2. 假定有如下一个FORTRAN程序段的说明句序列
SUBROUTINE EXAMPLE(X, Y)
INTEGER A, B(20), C(10, 15), D, E
COMPLEX F, G
COMMON /CBK/D, E, F
EQUIVALENCE (G, B(2)), (D, B(1))
请给出数据区EXAMPLE和CBK中各符号名的相对地址。
*3. 出现在公用区中等价环元素的地址分配方法和非公用区中等价环元素的地址分配方法有什么不同?为什么?
公用区中等价环元素的地址分配是:当沿公用链依次给对公用区元素分配地址时,若遇到等价环中的元素,则立即把公用区当前待分配的地址分配给当前遇到的等价元素,而不必顾及其相对数是否为等价环中的最小者。这样分配的结果可能导致等价环中的元素与公用区中其它非等价环元素等价。
非公用区中等价环元素的地址分配方法是:每当遇到等价环中的元素时,不是将局部数据区当前待分配地址直接分配给所遇到的等价环元素,而是将其分配给从这个等价环中找到的相对数最小的等价元素,然后再按等价环其它的等价元素的相对数与最小相对数的差数,予以分配相应的地址。这样就不致使局部数据区非等价元素与等价环元素等价,也不会使两个不同的等价环元素等价。
下面的例子充分说明了两者的不同。
FORTRAN说明语句序列1:
REAL A(5)
COMMON /C/B(3),K,T
EQUIVALENCE (K,A(2))
FORTRAN说明语句序列2:
REAL B(3),K,T,A(5)
EQUIVALENCE (K,A(2))
例子中都是变量K与数组A的第2个元素是等价的。第1种情形中,K后的变量T的地址会紧排在变量K之后。第2种情形中,变量T的地址必须要等到分配完数组A 的地址后才能分配变量K的地址。其存储分配如图所示。
4. 下面是一个Pascal程序
program PP(input, output)
VAR k:integer;
FUNCTION F(n:integer): integer
begin
if n<=0 then F:=1
else F:=n*F(n-1);
end;
begin
K:=F(10);
…
end.
当第二次(递归地)进入F后,DISPLAY的内容是什么?当时整个运行栈的内容是什么?
由于过程F在主过程中定义,因此,过程F的 Display表中的内容有两项,分别为主过程活动记录首地址和过程F本身的最新活动记录首地址。当程序第次(递归地)进入F后, Display表的内容及当时整个运行栈的内容如图所示。(假设主过程活动记录的首地址为I+0)
5. 对如下的Pascal程序,画出程序执行到(1)和(2)点时的运行栈。
progarm Tr(input, output);
VAR i:integer; d:integer;
procedure A(k:real);
VAR p:char;
procedure B;
VAR c:char;
Begin
…(1)…
end; {B}
procedure C;
VAR t:real;
Begin
…(2)…
end; {C}
Begin
……
B;
C;
……
end; {A}
Begin {main}
…
A(d);
…
end.
答:子过程B和子过程C是子过程A内部并列定义的两个子过程,他们之间不存在定义的嵌套关系。程序执行到(1)和(2)点时运行栈状态分别如图(a)和图(b)所示。(假设主过程活动记录的首地址为I+0)。
(a)程序执行到(1)点时的运行栈;(b)程序执行到(2)点时的运行栈
6. 有如下示意的Pascal源程序
program main;
VAR a, b, c:integer;
procedure X(i, j:integer);
VAR d, e:real;
procedure Y;
VAR f, g:real;
Begin
…
End; {Y}
procedure Z(k:integer);
VAR h, I, j:real;
Begin
……
end; {Z}
Begin
……
10:Y;
……
11:Z;
……
end; {X}
Begin
……
X(a, b);
……
end. {main}
并已知在运行时刻,以过程为单位对程序中的变量进行动态存储分配。当运行主程序而调用过程语句X时,试分别给出以下时刻的运行栈的内容和Display的内容。
(a) 已开始而尚未执行完毕标号为10的语句;
(b) 已开始而尚未执行完毕标号为11的语句。
(1)程序已开始而尚未执行完毕标号为10的语句时,运行栈的内容和Display表的内容如图(a)所示。(假设主过程活动记录的首地址为I+0)
(2)程序已开始而尚未执行完毕标号为11的语句时,运行栈的内容和 Display表的内容如图(b)所示。(假设主过程活动记录的首地址为I+0)
(a)程序执行到标号为10的语句时的运行栈;(b)程序执行到标号为11的语句时的运行栈
7. 假定有一个语言,在每个过程内部既可以引用局部于该过程的变量,也可以引用主程序中的全局量,但过程调用既不允许递归也不允许嵌套,这些限制导致了非常简单的运行存储组织,为什么?
答:该语言的限制导致了非常简单的运行存储组织的原因,可以从运行存储组织复杂性的来源进行分析,主要包括:
(1)过程是否允许递归?由于不允许递归,则只需要考虑过程单一的数据特性。
(2)当控制从一个过程的活动返回时,对局部名称的值如何处理?同样由于过程不允许递归,则过程的活动是单一的,不会出现过程的多个活动,只考虑单一的局部名称的处理即可。
(3)过程是否允许引用非局部名称?如果每个过程内部既可以引用局部于该过程的变量,也可以引用主程序中的全局变量,可见该语言的过程引用是非常简单的,只要在过程的数据区中增加一个主程序全局变量区的首址就能满足其引用要求。所以不管该语言的动态分配需求如何,过程的局部数据区的处理是非常简单的。
9. 对于下面的程序:
procedure P(X,Y,Z);
begin
Y:=Y+1;
Z:=Z+X;
end P;
begin
A:=2;
B:=3;
P(A+B,A,A);
print A
end
若参数传递的办法分别为(1)传名,(2)传地址,(3)得结果,以及(4)传值,试问,程序执行时所输出的A分别是什么?
不同的参数传递方式下程序执行时A的结果如下:
(1)传名:A=9;
(2)传地址:A=8;
(3)得结果:A=7;
(4)传值:A=2。