理解写得不好的代码,第二年的CS历年论文

Understanding poorly written code, 2nd year CS past paper

本文关键字:CS 第二年 代码      更新时间:2023-10-16

问题是描述代码做什么,函数做什么。

以下代码是第二年 C 和 C++ 模块的过去试卷的一部分。任务是描述以下代码段的作用。我已经完全按照呈现的方式编写了代码,并添加了一些我自己添加的注释。

int g(int * y, unsigned size, int z) {
    int tmp = y[0];
    // what type is unsigned size? Int I presume. Why would you add an int to an array of ints?
    int * b = y + size; 
    y[0] = z;
    // I have the most difficulty understanding the following.
    while (1) if (*(--b)==z){y[0] = tmp; return b - y;};
    // are the following 3 lines ever even reached?
    y[0] = tmp;
    if (tmp == z) return 0;
    else return -1;
}
// what type is unsigned size?

这是一个叫做size unsigned int。您可以像在普通指针算术中一样将其添加到指针中 - 将此指针前进到数组的最末尾。

while (1) if (*(--b)==z){y[0] = tmp; return b - y;};

好的,我们有

  • while(1) = while(true),或"永远循环"
  • *(--b)递减 b 之前并从数组的该索引中读取值
  • 如果我们找到了 z,请将第一个元素替换为我们从中读取的值并返回 b-y - 我们所在的数组索引的指针算术

即,我们向后扫描数组以找到z的最后一个实例并返回我们找到它的索引。我们总是会在数组中找到z,因为我们把它作为第一个元素放在那里,即如果z不在数组中,那么我们返回 0。

// are the following 3 lines ever even reached?

不,我不这么认为。

什么类型是无符号大小

unsignedunsigned int的缩写。

为什么要在整数数组中添加 int?

指针和数组不是一回事。您显示的代码使用的是指针,而不是数组。在int * b = y + size;行之后,b 是一个指针,指向y指向的条目size条目。例如,如果size 2b将指向第三个条目。ASCII-art:

+---------+
| entry 0 |<--- `y` points here
| entry 1 |
| entry 2 |<--- `b` points here if `size` is `2`
| entry 3 |
| entry 4 |
+---------+

我最难理解以下内容。

while (1) if (*(--b)==z){y[0] = tmp; return b - y;};

循环查看内存中由y指向的条目,从条目开始然后由 size 标识。如果条目== z,它将y[0]设置为 tmp 并返回找到该条目的索引(通过使用指针算术,b - y返回b指向的位置和y开头之间的条目数。由于--b递减指针,因此循环在内存中向后工作。

甚至到达过以下 3 条线吗?

不。当找到第一个匹配的条目时,return将退出函数,该条目可能在开头(因为y[0]设置为早期z)。但是,正如 Ted Hoff 在评论中指出的那样,如果在进入时0 size循环将开始并继续超过开始(y指向的位置),这最终可能导致程序因内存访问违规而失败。

这段代码做的第一件事就是证明作者不称职。但我认为这是作业的一部分:理解编写的代码由无能的人。

对于初学者:

  • unsigned是有效的C++类型,unsigned int的收缩。 它通常最好避免,除非你做位操作。

  • 代码中没有数组;您正在向指针。 奇怪的是,[]不是数组索引,而是
    定义,以便a[b]完全等同于 *(a+b) 。 (至少对于内置类型。 你可能想找一本关于C的书来解释这;在C++中,我们一般使用std::vector,正是为了避免所有这种关于指针算术的困惑。

至于您难以理解的部分:首先,让我们以理智的方式写它:

while ( true ) {
    -- b;
    if ( *b == z ) {
        y[0] = tmp;
        return b - y;
    }
}

关于唯一应该引起问题的事情是返回语句:这是指针减法;在这种情况下,由于y是数组的第一个元素(从代码的其余部分来看),b - y计算 b 指向的元素的索引。

在这里使用指针将是纯粹的混淆,除了习语在 C 语言中无处不在,并且在 C++ 中与迭代器一起延续。

你是对的,循环后的代码永远无法执行;离开循环的唯一方法是通过return

编写循环的一种更简洁的方法是:

int i = size;
while ( i != 0 && y[i - 1] != z ) {
    -- i;
}
y[0] = tmp;
return i;