Понимание плохо написанного кода, второй год CS прошлой работы
Вопрос заключается в том, чтобы описать, что делает код, что делает функция.
Следующий код является частью прошлых экзаменационных документов для модуля 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;
}
Ответы
Ответ 1
// what type is unsigned size?
Это a unsigned int
называется size
. Вы добавляете его к указателю, как в обычной арифметике указателя - продвигайте этот указатель до самого конца массива.
while (1) if (*(--b)==z){y[0] = tmp; return b - y;};
ОК, у нас есть
-
while(1)
= while (true) или 'loop forever'
-
*(--b)
пре-декремент b и прочитайте значение из этого индекса массива
- если мы нашли z, заменим первый элемент на значение, которое мы читаем из него, и возвращаем
b-y
- арифметику указателя для индекса массива, на котором мы находимся
то есть. мы сканируем назад через массив, чтобы найти последний экземпляр z
и возвращаем индекс, в котором мы его нашли. Мы всегда найдем z
в массиве, потому что мы помещаем его в качестве первого элемента, т.е. Если z
не находится в массиве, тогда мы возвращаем 0.
// are the following 3 lines ever even reached?
Нет, я так не думаю.
Ответ 2
какой тип без знака
unsigned
не подходит для unsigned int
.
Почему вы добавляете int в массив ints?
Указатели и массивы - это не одно и то же. Код, который вы указали, использует указатели, а не массивы. После строки int * b = y + size;
b
является указателем, указывающим на запись size
записей, из которых указывает y
. Например, если size
были 2
, b
будет указывать на третью запись. ASCII-арт:
+---------+
| 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
уменьшает указатель, цикл работает обратно через память.
следующие три строки, которые когда-либо достигались?
Нет. return
выйдет из функции, когда будет найдена первая совпадающая запись, которая может быть в начале (так как y[0]
устанавливается на z
в начале). Тем не менее, как указывает Тед Гофф в комментариях, цикл начинается и продолжается до начала (где y
указывает), если size
есть 0
при записи, что, вероятно, в конечном итоге приведет к сбою программы с нарушение доступа к памяти.
Ответ 3
Первое, что делает этот код, доказывает, что автор некомпетентен.
Но я собираю эту часть задания: понимание написанного кода
некомпетентными людьми.
Для начала:
-
unsigned
- допустимый тип С++, сокращение для unsigned int
. Это
как правило, лучше всего избегать, если только вы не делаете манипуляции с битами.
-
В вашем коде нет массивов; вы добавляете целое число в
указатель. И, как ни странно, []
- это не индексация массива, а
так что a[b]
в точности эквивалентен *(a+b)
. (По крайней мере, для
построение типов.) Возможно, вам захочется найти книгу о C, чтобы объяснить
это; в С++ мы обычно используем std::vector
, чтобы избежать всех
это путаница в отношении арифметики указателя.
Что касается той части, которую вам трудно понять: для начала, давайте
напишите это разумно:
while ( true ) {
-- b;
if ( *b == z ) {
y[0] = tmp;
return b - y;
}
}
О единственном, что должно вызывать проблему, есть возврат
statement: это вычитание указателя; в этом случае, поскольку y
является
первый элемент массива (судя по остальной части кода), b - y
вычисляет индекс элемента, на который указывает b
.
Использование указателей здесь было бы чистой обфускацией, за исключением того, что
идиома является вездесущей в C и продолжается с итераторами в С++.
И вы правы, что код после цикла никогда не может быть выполнен;
только путь выхода из цикла через return
.
Более чистый способ записи цикла:
int i = size;
while ( i != 0 && y[i - 1] != z ) {
-- i;
}
y[0] = tmp;
return i;