Понимание плохо написанного кода, второй год 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;