面试题:可正常运行的C#乘法表打印代码有什么问题?
C#九九乘法表打印代码面试题
这是一道C#方向的求职面试题,给出的乘法表打印代码可以正常运行,但存在容易被开发者忽略的隐含问题,代码内容如下:
public static void Main() { int i, j; Console.Write(" "); for (i = 1; i < 10; i++) Console.Write(String.Format("{0,3:d}", i)); Console.WriteLine(); for (i = 0; i < 32; i++) Console.Write("="); Console.WriteLine(); for (i = 1; i < 10; i++) { Console.Write(i + " | "); for (j = 1; j < 10; j++) Console.Write(String.Format("{0,3:d}", i * j)); Console.WriteLine(); } Console.ReadKey(); }
运行效果参考

任何认真学习过C#的程序员、系统工程师或系统数学家都应当知道该问题的答案。
提问者初步发现的问题
提问者最初只找到两处他认为不严重的小问题:
- 代码将乘法表的边界值10做了硬编码,但九九乘法表本身仅使用1-9共9个数值,硬编码不算严重缺陷
- 使用
i + " | "的字符串拼接写法在性能和内存占用上不够优化,但属于无关紧要的细枝末节
代码隐含的核心问题
实际上这段代码的问题远不止上述两点,其中最核心、也是出题人所指的隐含问题如下:
- 魔法数字泛滥且宽度计算错误:代码中所有和排版、边界相关的数值全为硬编码的魔数:循环边界10、表头缩进的4个空格、分隔线长度32、列宽3,这些数值之间存在强依赖关系,但完全没有通过逻辑关联计算:
- 实际内容总宽度为4(行首区域) + 9*3(9个占3位的乘积列)= 31,但分隔线硬编码为32个
=,比分隔内容长1位,属于明显的计算错误 - 所有排版参数没有和乘法表上限值绑定,如果需要调整乘法表规模(比如改为12*12乘法表),需要同时修改多处硬编码值,极易出现漏改导致排版完全错乱
- 实际内容总宽度为4(行首区域) + 9*3(9个占3位的乘积列)= 31,但分隔线硬编码为32个
- 循环变量作用域不合理:循环变量
i、j被声明在Main方法的最外层,而非各自所属的for循环内部,这是C语言时代的遗留写法,不符合C#的变量作用域设计原则。过大的变量作用域很容易导致后续维护时误改变量值、引用到错误的变量值引发逻辑bug——比如打印分隔线的循环就复用了变量i,循环结束后i的值为32,只是因为后续循环重新给i赋了初始值才没有引发错误。 - 冗余性能损耗并非细枝末节:提问者认为字符串拼接是小问题,但实际上代码中反复调用
String.Format包装后再传给Console.Write,而Console.Write本身就支持复合格式化重载,额外调用String.Format会产生大量不必要的临时字符串;同时循环逐字符打印32个=、值类型传入格式化方法产生的装箱操作,在大规模输出场景下会带来明显的性能损耗。 - 非交互场景兼容性缺陷:代码末尾的
Console.ReadKey()依赖交互式控制台输入,在无交互环境(如后台服务、CI/CD流水线、输出重定向场景)下运行会直接抛出异常,不适合作为通用代码逻辑。 - 逻辑冗余:代码打印了完整的9*9乘法矩阵,根据乘法交换律
i*j = j*i,上三角区域(j>i)的内容和下三角完全重复,属于无意义的冗余计算和输出,标准九九乘法表仅需打印j<=i的下三角区域即可。
内容的提问来源于stack exchange,提问作者Kosmo零
相关产品推荐
相关产品推荐

