这是我的问题:
当您使用字面数字访问数组的特定元素时,是否被认为是魔数?
例如:
arrayOfNumbers[6] // Is six a magic number in this case?
我提出这个问题是因为我的一位教授坚信程序中所有的文字数字都是魔法数字。如果我可以直接使用实数访问数组元素,而不是为每个元素使用命名常量,那就太好了。
谢谢!
这是我的问题:
当您使用字面数字访问数组的特定元素时,是否被认为是魔数?
例如:
arrayOfNumbers[6] // Is six a magic number in this case?
这真的取决于上下文。如果您有以下代码:
arr[0] = "Long";
arr[1] = "sentence";
arr[2] = "as";
arr[3] = "array.";
...那么0到3就不被视为魔数。但是,如果您有:
int doStuff()
{
return my_global_array[6];
}
...那么6绝对是一个神奇的数字。
这真是神奇。
我的意思是,为什么您要访问第6个元素?应该应用于该数字的语义是什么?现在我们所知道的只有“第六个(从零开始计数的)数字”。如果我们知道 arrayOfNumbers
的声明,我们将进一步了解其类型(例如 int
或 double
)。
但如果您说:
arrayOfNumbers[kDistanceToSaturn];
现在,对于阅读代码的人来说,它有了更多的含义。
通常情况下,我们会遍历一个数组,在每个元素上执行某些操作,因为我们不知道这个数组的长度,也不能以硬编码的方式访问它。
然而,有时候数组元素具有特定的含义,例如在图形编程中。有时候数组的大小总是相同的,因为数据需要(例如某些变换矩阵)。在这些情况下,按编号访问特定元素可能是可以接受的,也可能不可以:领域专家会知道你在做什么,但一般人可能不会。给神奇的索引号取个名字,可以让那些需要维护你的代码的人更容易理解,也可以帮助你防止意外输入错误的编号。
在我上面的例子中,我假设你的数组保存了从太阳到行星的距离。太阳将是第零个元素,因此arrayOfNumbers[kDistanceToSun] = 0。然后,随着增量的增加,每个元素都包含到下一个最远行星的距离:水星、金星等等。这比只键入您想要的行星的数字要容易阅读得多。在这种情况下,数组的大小是固定的,因为行星的数量是固定的(当然,除了整个冥王星事件)。
另一个问题是,"arrayOfNumbers"并没有告诉我们数组的内容。我们已经知道它是一个数字数组,因为我们在某个地方看到了声明,其中你写道int arrayOfNumers[12345];
或者你以其他方式声明了它。相反,可以使用类似于:
int distanceToPlanetsFromSol[kNumberOfPlanets];
这样做可以更好地了解数据的实际含义和语义。作为程序员,你的目标之一应该是编写具有自我记录功能的代码。
然后我们可以在其他地方讨论kNumberOfPlanets
是否应该是8个还是9个。 :)
你应该问自己为什么要访问那个特定的位置。在这种情况下,我假设如果你正在执行arrayOfNumbers[6]
,第六个位置具有某种特殊含义。如果你想知道这个含义,你可能会意识到它是隐藏的一个魔术数字。
从另一个角度来看:
如果程序需要访问第七个元素而不是第六个元素,你或维护者如何知道呢?例如,如果第六个条目是加利福尼亚州的树木数量,那么将其放置在正确的位置将是一件好事。
#define CA_STATE_ENTRY 6
如果现在表格被重新排序,有人会发现他们需要将这个改为9(比如说)。顺便说一下,我并不是说这是维护按州计算树木数量数组的最佳方法 - 这可能不是最好的方法。
同样地,如果以后有人想要更改程序以处理俄勒冈州的树木,那么他们就知道要替换掉
trees[CA_STATE_ENTRY]
使用
trees[OR_STATE_ENTRY]
trees[6]
不是自我记录的
当然,对于C++而言,应该使用枚举而不是#define。
并非程序中的所有文字都被认为是“魔数”——但这个确实看起来像是。 6
并没有给我们任何线索,说明为什么要访问数组的特定元素。
如果不想成为魔数,你需要在第一次检查(或至少最小检查)时就清楚地知道其含义,以便了解为什么使用该值。例如,很多代码会执行以下操作:&x[0]
。在这种情况下,通常很清楚 '0' 实际上只是表示“数组的开头”。
如果你需要访问数组中的特定元素,很可能你的方法是错误的。
你几乎总是应该迭代整个数组。
如果你的程序涉及到特定的数字六,那么它就不是一个神奇数字了。你能提供一些上下文吗?
这就是教授的问题,他们通常过于学术化。从理论上讲,他通常是正确的,但通常情况下,魔数是在更严格的上下文中使用的,当数字嵌入到数据流中时,允许您检测流的某些属性(例如文件类型的签名头)。 另请参见此维基百科条目。
#define TWO 2
...if (i % TWO) printf("i is odd\n");
. 教授们应该学会不要过于笼统地概括。像“所有的字面数字都是神奇数字”这样的说法对于一位教授来说是荒谬的。 - Mehrdad Afshari