北航2021程序语言原理试题及总结

试题

1 C语言程序阅读

#include<bits/stdc++.h>
using namespace std;
int f(int* i) {
  static int x = 0;
  x++;
  printf("%d -1, *i= %d\n", x, *i++);
  printf("%d -2, *i= %d\n", x, *i++);
  return *i;
}
int main() {
  int x[3] = { 1,2,3 };
  x[0] = f(x) + f(x) + x[x[0]];
  printf("x[0]=%d\n", x[0]);
}


输出是

1 -1, *i= 1
1 -2, *i= 2
2 -1, *i= 1
2 -2, *i= 2
x[0]=8

(这输出也太奇怪了吧局部变量x增加了,x[0]没有变,所以求值策略是什么?感觉要看汇编代码)

(后来知道这个++优先级更高。。。太蠢了)

2 Scheme设计

实现trim,去掉列表的最后一个元素。相当于 vector<int>v;v.pop_back()


(define (my-trim lst )
  (cond ((null? lst)    ; if the list is empty
         'error)          ; error
        ((equal? (cdr lst) '()) 
          '())
        (else            ; if the list is non-empty
         (cons (car lst)     ; cons the first element in the list
               (my-trim (cdr lst) ))))) ; with the result of advancing the recursion

3 指称语义

*I1=*I2
var *I1=&I2
let var *I1=&I2 in C

(照着I=E和*I=E的语义瞎写的。有没有人来告诉我ppt最后两行是错的,当时就应该问老师的QAQ)

4 哲学家用餐问题

一个用synchonized实现的哲学家问题,问会出现什么问题,怎么改进,我正好找到了源码博客[1],和里面的教学思路一致(国内的java并发实现真的找不到标准代码)。

public class Philosopher implements Runnable {

  // The forks on either side of this Philosopher
  private Object leftFork;
  private Object rightFork;
  //引用调用,指向同一个对象,所以可以锁住
  public Philosopher(Object leftFork, Object rightFork) {
    this.leftFork = leftFork;
    this.rightFork = rightFork;
  }

  private void doAction(String action) throws InterruptedException {
    System.out.println(
        Thread.currentThread().getName() + " " + action);
    Thread.sleep(((int) (Math.random() * 100)));
  }

  @Override
  public void run() {
    try {
      while (true) {

        // thinking
        doAction(System.nanoTime() + ": Thinking");
        synchronized (leftFork) {
          doAction(
              System.nanoTime()
                  + ": Picked up left fork");
          synchronized (rightFork) {
            // eating
            doAction(
                System.nanoTime()
                    + ": Picked up right fork - eating");

            doAction(
                System.nanoTime()
                    + ": Put down right fork");
          }

          // Back to thinking
          doAction(
              System.nanoTime()
                  + ": Put down left fork. Back to thinking");
        }
      }
    } catch (InterruptedException e) {
      Thread.currentThread().interrupt();
      return;
    }
  }

  public static void main(String[] args) throws Exception {

    final Philosopher[] philosophers = new Philosopher[5];
    Object[] forks = new Object[philosophers.length];

    for (int i = 0; i < forks.length; i++) {
      forks[i] = new Object();
    }

    for (int i = 0; i < philosophers.length; i++) {
      Object leftFork = forks[i];
      Object rightFork = forks[(i + 1) % forks.length];

      if (i == philosophers.length - 1) {

        // The last philosopher picks up the right fork first
        philosophers[i] = new Philosopher(rightFork, leftFork);
      } else {
        philosophers[i] = new Philosopher(leftFork, rightFork);
      }

      Thread t = new Thread(philosophers[i], "Philosopher " + (i + 1));
      t.start();
    }
  }
}

class DiningPhilosophers {

}

应该就是这里改的

5 JAVA多态 终极版

类似作业里的题 大概长这样,但是里面还试图对内部类进行多态(定义了内部类,private内部类变量,内部类extend父类的内部类,子类通过set内部类实例到父类里)。个人理解内部类无法多态。类似这种

public class Foo {

  public void method1() {

​    System.out.println("foo 1");

  }

  public void method2() {

​    System.out.println("foo 2");

  }

  public String toString() {

​    return "foo";

  }

}



public class Baz extends Foo {

  public void method1() {

​    System.out.println("baz 1");

  }

  public String toString() {

​    return "baz";

  }

}



public class Mumble extends Baz {

  public void method2() {

​    System.out.println("mumble 2");

  }

}



public static void main(String[] args){

  Foo[] pity = {new Baz(), new Bar(), new Mumble(), new Foo()};

  for (int i = 0; i < pity.length;i++) {

​    System.out.println(pity[i]);

​    pity[i].method1();

​    pity[i].method2();

​    System.out.println();

  } 

}


method foo bar Mumble baz
method1 foo 1 baz 1
method2 foo 2 bar 2 numble 2
toString foo baz

感想

近年考试比较简单,同学也是这么觉得。课程大作业可以没有代码实现,总之还是算能水过的核心课之一。

但是要真的掌握,内容太多了,每一章都能作为一节课。

作用域、闭包、堆栈帧、参数传递、prolog、语法、lambda演算都没考(基本也不是重点,但基础不好的我看了好久)。

我今天复习的时候真的折磨。java并发的内容是真的多、又不懂java,又不懂并发。


  1. The Dining Philosophers Problem in Java | Baeldung ↩︎

成功的路并不拥挤,因为大部分人都在颓(笑)
原文地址:https://www.cnblogs.com/SuuT/p/15738340.html