理解写得不好的代码,第二年的CS历年论文
Understanding poorly written code, 2nd year CS past paper
问题是描述代码做什么,函数做什么。
以下代码是第二年 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?
不,我不这么认为。
什么类型是无符号大小
unsigned
是unsigned int
的缩写。
为什么要在整数数组中添加 int?
指针和数组不是一回事。您显示的代码使用的是指针,而不是数组。在int * b = y + size;
行之后,b
是一个指针,指向y
指向的条目size
条目。例如,如果size
2
,b
将指向第三个条目。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;
- CMake项目Boost库错误:Boost/config/compiler/gcc.hpp:165:10:致命错误:cs
- 如何从给定字符串中删除第二次和第三次出现的$
- 打印第二列时的2d字符矢量打印空间
- FLTK 2.0构建和演示,适用于VS2019的2011年左右的代码库
- 我有两个类需要在同一 cpp 文件中相互引用,但第一个类无法识别第二个类类型的对象
- 等待整个 omp 块完成,然后再调用第二个函数
- 嵌套的 for 循环不循环通过第二个数组
- Opengl 3.1 GLSL 140 在 C++ 年输出白色在片段着色器中
- 内存错误低于在C++年实现埃拉托色尼筛分时的预期
- 我想在C++中读取一些多个字符,但它永远不会读取第二个字符
- 如何在创建自定义迭代器时获得 std::p air 的第一个和第二个?
- WinAPI 在单击第一个对话框上的按钮控件并销毁第一个对话框后创建第二个对话框
- 如何在不C++排序的情况下找到给定向量中的第一、第二和第三高值?
- 使用 SWIG 更改生成的 CS 函数中的返回类型
- 将第二个 GATT 服务添加到 Movesense 容器
- 如何在 c++ 中根据第二个元素按降序对列表进行排序
- 对的排序向量 (std::vector<pair<int, int>>) 按对的第一个元素搜索并更新第二个元素值
- 比较 2 个向量并从第二个向量中删除在第一个 - c++ 中找不到的元素
- getopt_long_only第二次调用时返回 -1
- 理解写得不好的代码,第二年的CS历年论文