image_up_163930832493ac7028.jpg

#include <stdio.h>
int k;
int a[3];
void swap(int x,int y)
{
    x=x+y;
	y=x-y;
	X=X-y;
}
void main()
{
    k=1;
	a[0]=2;
	a[1]=1;
	a[2]=0;
	swap(k,a[k]);
	printf("k=%d,a[0]=%d,a[1]=%d,a[2]=%d\n" ,k,a[0],a[1],a[2]);
	swap(a[k],a[k]);
	printf("k=%d,a[0]=%d,a[1]=%d,a[2]=%d\n" ,k,a[0],a[1],a[2]);
}

答:

我们看 swap 的实现。

x = x + y; // 
y = x - y; // y = (x + y) - y = x
x = x - y; // x = (x + y) - (x) = y

在 main 的前四行,初始化 k = 1, a = {2, 1, 0}

(1)如果按照传值调用,运行结果:

// swap(1, a[1]), a[1] = 1
//   x = 1 + 1 = 2
//   a[1] = 2 - a[1] = 1
//   x = 2 - 1 = 1
k = 1, a[0] = 2, a[1] = 1, a[2] = 0
// swap(1, 1), a[1] = 1 
k = 1, a[0] = 2, a[1] = 1, a[2] = 0

(2)如果按照引用调用

// swap(k, a[1]), a[1] = 1, k = 1
//   k = 1 + 1 = 2
//   a[1] = k - a[1] = 2 - 1 = 1
//   k = k - a[1] = 2 - 1 = 1
k = 1, a[0] = 2, a[1] = 1, a[2] = 0
// swap(a[k], a[k]), a[1] = 1, k = 1
//   a[1] = a[1] + a[1] = 2
//   a[1] = a[1] - a[1] = 0
//   a[1] = a[1] - a[1] = 0
k = 1, a[0] = 2, a[1] = 0, a[2] = 0

(3)如果复制恢复,

// swap(k, a[1]), a[1] = 1, k = 1
//   k = 1 + 1 = 2
//   a[1] = k - a[1] = 2 - 1 = 1
//   k = k - a[1] = 2 - 1 = 1
k = 1, a[0] = 2, a[1] = 1, a[2] = 0
// swap(a[k], a[k]), a[1] = 1, k = 1
//   a[1] = a[1] + a[1] = 2
//   a[1] = a[1] - a[1] = 1
//   a[1] = a[1] - a[1] = 1
k = 1, a[0] = 2, a[1] = 1, a[2] = 0

(4)传名调用,相当于宏替换

// swap(k, a[k]), a[k] = 1, k = 1
//   k = k + a[k] = 2
//   a[k] = k - a[k] == a[2] = 2 - a[2] = 2
//   k = k - a[k] == k = 2 - 2 = 0
k = 0, a[0] = 2, a[1] = 1, a[2] = 2
// swap(a[k], a[k]), k = 0
//   a[k] = a[k] + a[k] = 4
//   a[k] = a[k] - a[k] = 0
//   a[k] = a[k] - a[k] = 0
k = 0, a[0] = 0, a[1] = 1, a[2] = 2

image-20211212211804349

image-20211212211811928

答:

(1)传值,则无副作用,输出 2

(2)引用,则

// tmp = 5
// p(tmp, a, a)
//     a = a + 1 = 3
//     a = a + 5 = 8
8

(3)复制恢复,则

// tmp = 5
// p(tmp, a, a) // a = 2
//     a = a + 1 = 3
//     a = a + 5 = 7
7

(4)传名,则替换

// a = a + 1 = 3
// a = a + a + b = 3 + 3 + 3 = 9
9

image-20211212213112933

(1)(2)

活动树:

main
	c   // m = 0
		r // m of r = 7
    		b(f) // m of b = 3
    			f(2) // 0 + 2 = 5

输出 5

(3)

控制链都是指向活动树的父节点。

访问链:

  • 对普通函数而言,访问链指向其调用方活动
  • 对于闭包函数而言,访问链指向其声明上下文
== main ==

== c ==
control_link = main
access_link = main

== r ==
control_link = c
access_link = c

== b(f) ==
control_link = r
access_link = main

== f(2) ==
control_link = b(f)
access_link = c