Магические числа в массивах? - C ++ - PullRequest
7 голосов
/ 19 января 2010

Я довольно новый программист, и я прошу прощения, если эта информация легко доступна, я просто пока не смог ее найти.

Вот мой вопрос:

Считается ли магическим числом, когда вы используете литеральное число для доступа к определенному элементу массива?

Например:

arrayOfNumbers[6] // Is six a magic number in this case?

Я задаю этот вопрос, потому что один из моих профессоров непреклонен в том, что все буквенные числа в программе являются магическими числами. Было бы хорошо, если бы я получил доступ к элементу массива, используя действительное число, вместо того, чтобы использовать именованную константу для каждого элемента.

Спасибо!

Ответы [ 11 ]

22 голосов
/ 19 января 2010

Это действительно зависит от контекста. Если у вас есть такой код:

arr[0] = "Long";
arr[1] = "sentence";
arr[2] = "as";
arr[3] = "array.";

... тогда 0..3 не считаются магическими числами. Однако, если у вас есть:

int doStuff() 
{
   return my_global_array[6];
}

... тогда 6 определенно магическое число.

6 голосов
/ 19 января 2010

Это довольно волшебно.

Я имею в виду, , почему вы получаете доступ к 6-му элементу? Какая семантика должна применяться к этому числу? В его нынешнем виде все, что мы знаем, это «6-е (от нуля) число». Если бы мы знали объявление arrayOfNumbers, мы бы также знали его тип (например, int или double).

Но если бы вы сказали:

arrayOfNumbers[kDistanceToSaturn]; 

... теперь это имеет гораздо большее значение для тех, кто читает код.

Как правило, каждый выполняет итерацию по массиву, выполняя некоторую операцию с каждым элементом, потому что он не знает, каков размер массива, и вы не можете просто получить к нему доступ жестко закодированным способом.

Однако иногда элементы массива имеют специфическое значение, например, в графическом программировании. Иногда массив всегда имеет один и тот же размер, потому что этого требуют данные (например, определенные матрицы преобразования). В этих случаях может быть или не быть нормальным доступ к конкретному элементу по номеру: эксперты по доменам будут знать, что вы делаете, но, вероятно, не будут универсалы. Присвоение магического индекса имени делает его более очевидным для тех, кто должен поддерживать ваш код, и помогает предотвратить случайный ввод неправильного номера.

В моем примере выше я предположил, что ваш массив содержит расстояния от Солнца до планеты. Солнце было бы нулевым элементом, поэтому arrayOfNumbers [kDistanceToSun] = 0. Тогда при увеличении каждый элемент содержит расстояние до следующей самой далекой планеты: ртути, Венеры и т. Д. Это гораздо удобнее для чтения, чем просто набрать номер Планета, которую вы хотите. В этом случае массив имеет фиксированный размер, потому что есть фиксированное количество планет (ну, кроме всего разгрома Плутона).

Другая проблема заключается в том, что "arrayOfNumbers" ничего не говорит нам о содержимом массива. Мы уже знаем, что это массив чисел, потому что мы видели объявление где-то, где вы сказали int arrayOfNumers[12345]; или как вы его объявили. Вместо этого что-то вроде:

int distanceToPlanetsFromSol[kNumberOfPlanets];

... дает нам гораздо лучшее представление о том, что собой представляют данные и какова их семантика. Одна из ваших целей как программиста должна заключаться в написании кода, который самодокументируется таким образом.

И тогда мы можем поспорить в другом месте, если kNumberOfPlanets должно быть 8 или 9. :)

5 голосов
/ 19 января 2010

Вы должны спросить себя, почему вы получаете доступ к этой конкретной позиции. В этом случае я предполагаю, что если вы делаете arrayOfNumbers[6], шестая позиция имеет какое-то особое значение. Если вы думаете, что это значит, вы, вероятно, понимаете, что это магическое число, скрывающее это.

2 голосов
/ 19 января 2010

другой взгляд на это:

Что если после некоторого шанса программе потребуется доступ к 7-му элементу вместо 6-го? КАК бы вы или сопровождающий знали это? Если, например, если 6-я запись - это количество деревьев в CA, было бы хорошо поставить

 #define CA_STATE_ENTRY 6

Тогда, если теперь таблица переупорядочена, кто-то может увидеть, что ему нужно изменить это на 9 (скажем). Кстати, я не говорю, что это лучший способ поддерживать массив для подсчета количества деревьев в зависимости от состояния - вероятно, это не так.

Аналогично, если позже люди захотят изменить программу для работы с деревьями в штате Орегон, то они знают, что нужно заменить

 trees[CA_STATE_ENTRY]

с

 trees[OR_STATE_ENTRY]

Дело в том

 trees[6]

не является самодокументирующимся

Конечно, для c ++ это должно быть перечисление, а не # define

1 голос
/ 19 января 2010

Не все литералы в программе действительно квалифицируются как "магические числа" - но этот, безусловно, кажется. 6 не дает нам понятия, почему вы обращаетесь к этому конкретному элементу массива.

Чтобы не было магическим числом, вам нужно, чтобы его значение было достаточно ясным даже при первом (или хотя бы минимальном) исследовании, почему это значение используется. Например, много кода будет выполнять такие вещи, как: &x[0]. В этом случае, как правило, довольно ясно, что «0» на самом деле означает «начало массива».

1 голос
/ 19 января 2010

Вы должны предоставить больше контекста для значимого ответа. Не все буквальные числа магические, но многие из них. В случае, подобном этому, нет никакого способа сказать наверняка, хотя большинство случаев, которые я могу придумать, не имеет руки с явным индексом массива >> 1, вероятно, квалифицируется как волшебство.

0 голосов
/ 19 января 2010

В системе, совместимой с MISRA, все значения, кроме 0 и 1, считаются магическими числами. Мое мнение всегда было, если постоянное значение очевидно или, вероятно, не изменится, тогда оставьте это как число. Если вы сомневаетесь, создайте уникальную константу, так как длительное обслуживание будет проще.

0 голосов
/ 19 января 2010

Обычно не все постоянные значения в программном обеспечении называются магическими числами. Файлы классов Java всегда начинаются с шестнадцатеричного значения 0xcafebabe для Windows .exe файл с MZ 0x4d, 0x5a, это позволяет быстро (но не обязательно) идентифицировать содержимое двоичного файла.

0 голосов
/ 19 января 2010

Это проблема профессоров, они часто слишком академичны. Теоретически он прав, как обычно, но обычно магические числа используются в более строгом контексте, когда число встроено в поток data , что позволяет вам определять определенные свойства потока (например, заголовок подписи например, тип файла). См. Также эту запись в Википедии .

0 голосов
/ 19 января 2010

Это не волшебное число, если ваша программа делает что-то особенное, особенно с шестым номером.Не могли бы вы предоставить контекст?

...