求平方和时是否需要显式处理负数或零?


220

我最近在课堂上做了一个测试。问题之一是:

给定一个数字n,用C / C ++编写一个函数,该函数返回该数字平方的数字总和。(以下内容很重要)。的范围Ñ为[ - (10 ^ 7),10 ^ 7]。示例:如果n = 123,则您的函数应返回14(1 ^ 2 + 2 ^ 2 + 3 ^ 2 = 14)。

这是我写的函数:

int sum_of_digits_squared(int n) 
{
    int s = 0, c;

    while (n) {
        c = n % 10;
        s += (c * c);
        n /= 10;
    }

    return s;
}

看着我正确。所以现在测试又回来了,我发现老师由于我不明白的原因没有给我所有的分数。据他说,为了使我的功能更完整,我应该添加以下细节:

int sum_of_digits_squared(int n) 
 {
    int s = 0, c;

    if (n == 0) {      //
        return 0;      //
    }                  //
                       // THIS APPARENTLY SHOULD'VE 
    if (n < 0) {       // BEEN IN THE FUNCTION FOR IT
        n = n * (-1);  // TO BE CORRECT
    }                  //

    while (n) {
        c = n % 10;
        s += (c * c);
        n /= 10;
    }

    return s;
}

为此,参数n是在[-(10 ^ 7),10 ^ 7]范围内,因此它可以是负数。但是我看不到我自己的函数版本在哪里失败。如果我理解正确,的含义while(n)while(n != 0)不是 while (n > 0),所以在我的函数版本中,数字n不会失败。它会一样地工作。

然后,我在家中的计算机上尝试了该功能的两个版本,并且对所尝试的所有示例都获得了完全相同的答案。因此,sum_of_digits_squared(-123)等于sum_of_digits_squared(123)(再一次等于14)(即使没有我显然应该添加的细节)。的确,如果我尝试在屏幕上打印数字的位数(从重要性的最小到最大),那么123我会得到,3 2 1-123我会得到-3 -2 -1(实际上很有趣)。但是在这个问题上,因为我们对数字取平方并不重要。

那么,谁错了?

编辑:我不好,我忘记指定了,不知道这很重要。在我们的课程和测试中使用的C版本必须为C99或更高版本。因此,我猜(通过阅读注释)我的版本将以任何方式获得正确的答案。


120
n = n * (-1)是一种荒谬的写作方式n = -n; 只有一个学者甚至会想到它。更不用说添加多余的括号了。
user207421 '19

32
编写一系列单元测试,以检查给定的实现是否符合规范。如果一段代码存在(功能)问题,那么应该有可能编写一个测试来证明给定特定输入的不正确结果。
卡尔,

94
我发现有趣的是,可以用三(3)种完全不同的方式来解释“平方数的数字之和”。(如果数字为123,则可能的解释为
18、14

23
@ilkkachu:“数字平方的总和”。好吧,“数字平方”显然是123 ^ 2 = 15129,所以“数字平方的数字总和”是“ 15129的数字总和”,显然是1 + 5 + 1 + 2 + 9 = 18。
安德烈亚斯·雷布兰德

15
n = n * (-1)?啊?您的教授正在寻找的是:“ n = -n”。C语言具有一元减号运算符。
哈兹

Answers:


245

总结评论中一直渗入的讨论:

  • 没有充分的理由提前进行测试n == 0。该while(n)测试将完美地处理该情况。
  • %负数操作数的结果定义不同时,您的老师可能还习惯于更早的时间。在某些老的系统(包括,特别是,早期的Unix上的PDP-11,其中丹尼斯里奇最初开发C),结果a % b的范围内[0 .. b-1],这意味着-123%10为7。在这样的系统中,测试事先n < 0需要。

但是第二个符号仅适用于较早的时间。在C和C ++标准的当前版本中,整数除法被定义为向0截断,因此事实证明即使在为负数的情况下,n % 10也可以保证给您(可能为负数)的最后一位数字。nn

因此,“……的含义是while(n)什么?”这个问题的答案是什么“完全一样while(n != 0),而回答“愿意为负此代码正常工作,以及积极的n?” “在任何符合标准的现代编译器下都是。” 问题的答案:“那么,老师为什么要把它记下来?” 可能是他们没有意识到1999年C和2010年左右C发生的重大语言重新定义。


39
“没有充分的理由提前测试n == 0” –从技术上讲,这是正确的。但是考虑到我们是在教学环境中谈论一位教授,他们可能比我们更欣赏简洁而不是简洁。添加额外的测试n == 0至少可以使所有读者立即,完全明白在这种情况下会发生什么。没有它,读者必须使自己满意,确实确实跳过了循环,并且return的默认值s是正确的。
ilkkachu

22
另外,教授可能想知道学生已经知道并且已经考虑过该函数为什么以及如何在输入为零的情况下运行(即,它不会偶然返回正确的值)。他们可能遇到了一些学生,这些学生不知道在那种情况下会发生什么,循环可以运行零次,等等。在处理教学设置时,最好对所有假设和特殊情况都更加清楚。 ..
ilkkachu

36
@ilkkachu如果是这样,那么老师应该分发一项需要这种测试才能正常工作的任务。
klutt

38
@ilkkachu好吧,在一般情况下,我同意你的观点,因为我绝对赞赏简洁而不是简洁-而且几乎一直都在这样做,而不必只是在教学环境上。但是话虽如此,有时简洁还是清楚的,如果您可以安排主代码处理一般情况边缘情况,而又不会使代码(和覆盖率分析)与特殊情况的特殊情况杂乱无章,那是一件美丽的事!我认为即使在初学者的水平上也值得赞赏。
Steve Summit

49
@ilkkachu通过该参数,您当然还应该添加n = 1的测试,依此类推。没什么特别的n=0。引入不必要的分支和复杂性并不会使代码变得更容易,反而会使代码变得更困难,因为现在您不仅必须证明通用算法是正确的,而且还必须分别考虑所有特殊情况。
Voo

107

您的代码非常好

你是绝对正确的,你的老师是错误的。绝对没有理由增加这种额外的复杂性,因为它根本不影响结果。它甚至引入了一个错误。(见下文)

首先,n显然完全不需要单独检查if 是否为零,这很容易实现。老实说,如果您的老师对此有异议,我实际上会质疑他的能力。但是我想每个人都会时不时放屁。但是,我确实while(n)应该将其更改为,while(n != 0)因为它增加了一点额外的清晰度,甚至不需要花费额外的时间。不过这是小事。

第二个更容易理解,但他仍然错了。

这就是C11标准6.5.5.p6所说的:

如果商a / b是可表示的,则表达式(a / b)* b + a%b等于a;否则,a / b和a%b的行为均未定义。

脚注说:

这通常称为“向零截断”。

截断为零意味着for的绝对值a/b等于(-a)/ball a和的绝对值b,这又意味着您的代码非常完美。

模数是简单的数学运算,但可能违反直觉

但是,您的老师的确有一点需要您当心,因为对结果求平方的事实实际上在这里至关重要。a%b根据上述定义进行计算很容易,但是这可能违反您的直觉。对于乘法和除法,如果操作数具有等号,则结果为正。但是,对于模,结果与第一个操作数的符号相同。第二个操作数完全不影响符号。例如,7%3==1但是(-7)%(-3)==(-1)

这是一个演示它的片段:

$ cat > main.c 
#include <stdio.h>

void f(int a, int b) 
{
    printf("a: %2d b: %2d a/b: %2d a\%b: %2d (a%b)^2: %2d (a/b)*b+a%b==a: %5s\n",
           a, b ,a/b, a%b, (a%b)*(a%b), (a/b)*b+a%b == a ? "true" : "false");
}

int main(void)
{
    int a=7, b=3;
    f(a,b);
    f(-a,b);
    f(a,-b);
    f(-a,-b);
}

$ gcc main.c -Wall -Wextra -pedantic -std=c99

$ ./a.out
a:  7 b:  3 a/b:  2 a%b:  1 (a%b)^2:  1 (a/b)*b+a%b==a:  true
a: -7 b:  3 a/b: -2 a%b: -1 (a%b)^2:  1 (a/b)*b+a%b==a:  true
a:  7 b: -3 a/b: -2 a%b:  1 (a%b)^2:  1 (a/b)*b+a%b==a:  true
a: -7 b: -3 a/b:  2 a%b: -1 (a%b)^2:  1 (a/b)*b+a%b==a:  true

因此,具有讽刺意味的是,您的老师通过错误证明了自己的观点。

您老师的密码有缺陷

是的,实际上是。如果输入为INT_MINAND,体系结构为2的补码,且符号位为1且所有值位均为0的位模式不是陷阱值(使用没有陷阱值的2的补码是很常见的),那么您老师的代码将产生未定义的行为就行了n = n * (-1)。您的代码(如果有的话)比他的代码更好。考虑到通过使代码不必要的复杂并获得绝对零值来引入一个小错误,我想说您的代码要好得多。

换句话说,在INT_MIN = -32768的编译中(即使结果函数不能接收到<-32768或> 32767的输入),-32768 的有效输入也会导致未定义的行为,因为-(-32768i16)的结果不能表示为16位整数。(实际上,-32768可能不会导致错误的结果,因为-(-32768i16)通常计算结果为-32768i16,并且您的程序正确处理了负数。)(取决于编译器,SHRT_MIN可以是-32768或-32767。)

但是您的老师明确指出n可以在[-10 ^ 7; 10 ^ 7]。16位整数太小;您将必须使用[至少] 32位整数。使用int似乎可以使他的代码安全,除非那int不一定是32位整数。如果针对16位体系结构进行编译,则您的两个代码段都存在缺陷。但是您的代码仍然要好得多,因为这种情况重新引入了上述错误INT_MIN及其版本。为了避免这种情况,您可以编写,long而不是int,这是任一体系结构上的32位整数。long保证A 可以保存[-2147483647; 2147483647]。C11标准5.2.4.2.1 LONG_MIN通常是-2147483648但允许的最大值(是,最大值,它是一个负数)LONG_MIN2147483647

我将对您的代码进行哪些更改?

您的代码就可以了,所以这些并不是真正的抱怨。如果我真的真的需要对您的代码说些什么,那就更像是,有些小事情可能会使它变得更加清晰。

  • 变量的名称可能会更好一些,但是它是一个易于理解的简短函数,因此没什么大不了的。
  • 您可以将条件从更改nn!=0。从语义上讲,它是100%等效的,但它使它更加清晰。
  • c(我重命名为digit)的声明移到while循环内,因为它仅在此处使用。
  • 更改参数类型以long确保它可以处理整个输入集。
int sum_of_digits_squared(long n) 
{
    long sum = 0;

    while (n != 0) {
        int digit = n % 10;
        sum += (digit * digit);
        n /= 10;
    }

    return sum;
}

实际上,这可能会有点误导,因为-如上所述,变量digit可以获取负值,但是数字本身从不为正或为负。有几种解决方法,但这确实很挑剔,我不会在意这么小的细节。尤其是最后一位数字的单独功能过于复杂。具有讽刺意味的是,这是您的老师的代码真正解决的问题之一。

  • 更改sum += (digit * digit)为,sum += ((n%10)*(n%10))然后digit完全跳过变量。
  • 更改digit负号。但是我强烈建议不要为了使变量名有意义而使代码更复杂。这是非常强烈的代码气味。
  • 创建一个单独的函数来提取最后一位数字。int last_digit(long n) { int digit=n%10; if (digit>=0) return digit; else return -digit; }如果您想在其他地方使用该功能,这将很有用。
  • 只需c像最初一样命名即可。该变量名不会提供任何有用的信息,但是另一方面,它也不会引起误解。

但老实说,在这一点上,您应该继续进行更重要的工作。:)


19
如果输入为INT_MIN并且架构使用二进制补码(这是很常见的),那么您的教师代码将产生未定义的行为。 哎哟。那会留下痕迹。;-)
Andrew Henle

5
应该提到的是,除此以外(a/b)*b + a%b ≡ a,OP的代码还取决于舍入/为零的事实(-c)*(-c) ≡ c*c。它可以被认为,额外的检查,尽管标准合理保证这一切,因为它是足够不明显。(当然,同样可以说,应该有一条注释链接相关的标准部分,但样式准则会有所不同。)
大约

7
@MartinRosenau你说“可能”。您确定这确实在发生,还是标准或某些东西允许这样做,还是您只是在推测?
klutt

6
@MartinRosenau:好的,但是使用这些开关将使其不再是C。GCC / clang没有任何开关可以中断我知道的任何ISA上的整数除法。即使忽略符号位,也可以使用常数除数的常规乘法逆来提高速度。(但是我所熟悉的所有具有硬件除法指令的ISA都以C99方式实现它,将其截断为零,因此C %/运算符可以仅idiv在x86或sdivARM或任何平台上编译为a 。仍然,这与大多数情况无关更快的编译时常数除数的代码生成)
Peter Cordes,

5
@TonyK AFIK,通常是这样解决的,但按照标准是UB。
klutt

20

我不完全喜欢您的版本或老师的版本。老师的版本不需要您正确指出的额外测试。C的mod运算符不是正确的数学mod:负数mod 10将产生负结果(正确的数学模数始终为非负数)。但是既然您要对它进行平方运算,就没有区别。

但这远非显而易见,因此我将向您的代码中添加不是您的老师检查的内容,而是一个大注释来解释其工作原理。例如:

/ *注意:这适用于负值,因为模数平方* /


9
%最好将C 称为余数,因为即使是有符号类型也是如此。
彼得·科德斯

15
平方很重要,但是我认为这是显而易见的部分。我应该指出的是,(例如)-7 % 10 实际上将-7而不是3
雅各Raihle

5
“适当的数学模量”没有任何意义。正确的术语是“欧几里德模数”(请注意后缀!),实际上C的%运算符不是。
Jan Hudec

我喜欢这个答案,因为它解决了多种解释模数的问题。切勿将这样的事情留给机会/解释。这不是代码高尔夫球。
哈珀-恢复莫妮卡

1
“适当的数学模数始终是非负的” -并非如此。取模运算的结果是一个等价类,但通常将结果视为属于该类的最小非负数。
klutt

10

注意:在我编写此答案时,您确实已经说明您正在使用C。我的答案大部分是关于C ++的。但是,由于您的标题仍然是C ++,并且该问题仍被标记为C ++,所以我还是选择了答案,以防其他人仍然有用,尤其是因为到目前为止我所看到的大多数答案都不尽人意。

在现代C ++中(注意:我真的不知道C在这方面代表什么),您的教授在这两个方面似乎都是错误的。

首先是这部分:

if (n == 0) {
        return 0;
}

在C ++中,这基本上与以下内容相同

if (!n) {
        return 0;
}

这意味着您的while相当于这样的事情:

while(n != 0) {
    // some implementation
}

这意味着由于您只是退出了if而无论如何都不会执行,因此确实没有理由将if放在这里,因为循环后的操作和if的操作都是等效的。尽管我应该说这是出于某些原因,但它们与众不同,但是如果需要,您需要使用它。

所以说真的,除非我弄错了,否则这个if语句并不是特别有用。

第二部分是毛茸茸的地方:

if (n < 0) {
    n = n * (-1);
}  

问题的核心是负数模量的输出是什么。

在现代C ++中,这似乎是大多是明确的

二进制/运算符产生商,二进制%运算符产生第一个表达式除以第二个表达式的余数。如果/或%的第二个操作数为零,则行为未定义。对于整数操作数,/运算符得出代数商,其中舍弃任何小数部分;如果商a / b在结果类型中可表示,则(a / b)* b + a%b等于a。

然后:

如果两个操作数均为非负数,则其余为非负数;如果不是,则其余符号由实现定义。

正如所引用答案的张贴者正确指出的那样,此等式的重要部分就在这里:

(a / b)* b + a%b

以您的案例为例,您将获得以下内容:

-13/ 10 = -1 (integer truncation)
-1 * 10 = -10
-13 - (-10) = -13 + 10 = -3 

唯一要注意的是最后一行:

如果两个操作数均为非负数,则其余为非负数;如果不是,则其余符号由实现定义。

这意味着在这种情况下,只有符号似乎是实现定义的。在您的情况下这不应该是一个问题,因为,因为无论如何您都在平方这个值。

也就是说,请记住,这不一定适用于早期版本的C ++或C99。如果那是您的教授正在使用的,那可能就是原因。


编辑:不,我错了。C99或更高版本似乎也是如此

C99要求a / b可表示时:

(a / b)* b + a%b等于a

还有另一个地方

当整数被除法并且除法不精确时,如果两个操作数都为正,则/运算符的结果为小于代数商的最大整数,并且%运算符的结果为正。如果任一操作数为负,则/运算符的结果是小于代数商的最大整数,还是大于代数商的最小整数,由%定义。如果商a / b可表示,则表达式(a / b)* b + a%b等于a。

ANSI C或ISO C是否指定了-5%10?

嗯是的。即使在C99中,这似乎也不会影响您。等式是相同的。


1
您引用的部分不支持此答案。“其余符号由实现定义”并不意味着(-1)%10可能产生-11;这意味着它可以产生-19,在后一种情况下(-1)/10将产生,-1并且OP的代码永远不会终止。
stewbasic

您能为此指出一个来源吗?我很难相信(-1)/ 10为-1。那应该是0。而且(-1)%10 = 9似乎违反了控制方程。
Chipster

1
@Chipster,开始(a/b)*b + a%b == a,然后让a=-1; b=10,给予(-1/10)*10 + (-1)%10 == -1。现在,如果-1/10确实向下取整(向-inf取整),则我们有(-1/10)*10 == -10,并且您需要(-1)%10 == 9使第一个方程式匹配。像其他答案状态一样,这不是它在当前标准中的工作方式,而是它过去的工作方式。这不是真正的余料,这样的东西,然后其余的迹象,但怎么划分的回合,要满足的方程。
ilkkachu

1
@Chipster来源是您引用的摘录。请注意(-1)*10+9=-1,因此选择(-1)/10=-1(-1)%10=9不会违反控制方程式。另一方面,(-1)%10=1无论如何选择,选择都不能满足控制方程(-1)/10。没有整数q这样的q*10+1=-1
stewbasic

8

正如其他人指出的那样,对n == 0的特殊处理是无稽之谈,因为对于每个认真的C程序员来说,显然“ while(n)”可以胜任。

n <0的行为不是那么明显,这就是为什么我更愿意看到这两行代码:

if (n < 0) 
    n = -n;

或至少一个评论:

// don't worry, works for n < 0 as well

老实说,您什么时候开始考虑n可能为负?编写代码或阅读老师的言论时?


1
无论N是否为负,N平方都将为正。那么,为什么要先删除标志?-3 * -3 = 9; 3 * 3 =9。或者自从我学会了30多年来,数学发生了变化吗?
Merovex

2
@CB坦白说,我什至在编写测试时都没有注意到n可能为负,但是当返回时,我只是感觉即使循环数为负,while循环也不会被跳过。我在计算机上做了一些测试,证实了我的怀疑。之后,我发布了这个问题。所以,不,我在编写代码时没有那么深入地思考。
user010517720 '19

5

这使我想起我失败的一项作业

追溯到90年代。讲师一直在讲循环,长话短说,我们的任务是编写一个函数,该函数将返回任何大于0的给定整数的位数。

因此,例如,位数3213

尽管该任务只是说要写一个返回数字位数的函数,但我们的预期是我们将使用一个除以10的循环,直到... 得到它为止,如本讲座所述

但是我没有明确说明使用循环,所以我:took the log, stripped away the decimals, added 1并且随后在全班同学面前被抨击。

重点是,作业的目的是测试我们对讲座中所学知识的理解。从我收到的演讲中,我了解到计算机老师有点混蛋(但也许有计划的混蛋?)


在您的情况下:

用C / C ++编写一个函数,该函数返回数字平方的数字总和

我肯定会提供两个答案:

  • 正确答案(先平方),以及
  • 与例子相符的错误答案,只是为了让他开心;-)

5
还有第三个平方的数字和吗?
克里斯,

@kriss-是的,我并不聪明:-(
SlowLearner

1
在我的学习时间里,我也有过分模糊的经历。一位老师想要一点操纵库,但他对我的代码感到惊讶,并说它没有用。我必须向他指出,他从未在作业中定义字节顺序,在我做出其他选择时,他选择了低位作为位0。唯一令人烦恼的部分是,即使我不告诉他,他也应该能够找出区别所在。
克里斯,

1

通常,在分配中,并非仅仅因为代码有效就给出了所有标记。您还将获得使解决方案易于阅读,高效且优雅的标记。这些东西并不总是相互排斥的。

我无法充分利用的一个方法是“使用有意义的变量名”

在您的示例中,它并没有太大的区别,但是,如果您正在开发具有数百万行代码的项目,那么可读性就变得非常重要。

我倾向于使用C代码看到的另一件事是人们试图变得聪明。与其使用while(n!= 0),不如通过编写while(n)来向所有人展示我的聪明之处,因为这意味着同一件事。很好,它可以在您拥有的编译器中使用,但是正如您所建议的那样,教师的较早版本没有以相同的方式实现它。

一个常见的例子是在同时增加索引的同时引用数组中的索引;Numbers [i ++] = iPrime;

现在,下一个从事代码工作的程序员必须知道我是在作业分配之前还是之后递增,以便有人可以炫耀。

兆字节的磁盘空间比一卷厕纸便宜,为了保持清晰度而不是节省空间,您的程序员同伴会更快乐。


2
我仅用C编程过几次,我知道++i在评估之前i++增加,之后增加。while(n)也是常见的语言功能。基于这样的逻辑,我已经看到了很多类似的代码if (foo == TRUE)。我同意re:不过是变量名。
阿兰·ocallaghan

3
通常,这不是一个坏建议,但是为了防御性编程的目的而避免使用基本语言功能(无论如何人们都会不可避免地遇到)是过多的。总之,简短明了的代码通常更具可读性。我们在这里不是在谈论疯狂的perl或bash单行,而是真正的基本语言功能。
阿兰·ocallaghan

1
不确定,对此答案有何反对意见。对我来说,这里所说的一切都是真实和重要的,并且对每个开发人员都是很好的建议。尤其是智能资产编程部分,即使这while(n)不是最糟糕的例子(我“ if(strcmp(one, two))更喜欢” )
Kai Huppmann

1
除此之外,你真的不应该让任何人谁不知道之间的区别i++++i修改应在生产中使用的C代码。
klutt

2
@PaulMcCarthy我们俩都是为了代码可读性。但是我们不同意这个意思。而且,这不是客观的。一个人容易读懂的东西对另一个人来说很难读。人格和背景知识对此有很大影响。我的主要观点是,盲目遵循某些规则不会获得最大的可读性。
klutt

0

我不会争论'%'的原始定义或现代定义是否更好,但是任何在如此短的函数中编写两个return语句的人都不应该教C编程。额外的返回值是goto语句,我们不在C中使用goto。此外,不执行零检查的代码将具有相同的结果,额外的返回值使其更难阅读。


4
“额外的回报是goto语句,我们不在C语言中使用goto。” -这是非常广泛的概括和非常广泛的结合。
SS安妮

1
“我们”在C语言中肯定使用goto。这没有错。
klutt

1
此外,像int findChar(char *str, char c) { if(!str) return -1; int i=0; while(str[i]) { if(str[i] == c) return i; i++; } return -1; }
klutt

1
@PeterKrassoi我不提倡难以阅读的代码,但是我看到了无数的示例,其中的代码看起来像是一团糟,只是为了避免简单的goto或额外的return语句。这是适当使用goto的一些代码。我要求您删除goto语句,同时使代码更易于阅读和维护:pastebin.com/aNaGb66Q
klutt

1
@PeterKrassoi请同时显示您的版本:pastebin.com/qBmR78KA
klutt

0

问题陈述令人困惑,但是数值示例阐明了数字平方的数字总和的含义。这是一个改进的版本:

写在C和C ++的公共子集的函数,它接受一个整数n的范围[-10 7,10 7 ]和返回的其代表性的数字的平方之和在基座10实施例:如果n123,你的函数应该返回14(1 2 + 2 2 + 3 2 = 14)。

您编写的函数很好,但有2个细节:

  • 参数应该具有类型long为类型在指定范围内,以适应所有的值long由C标准保证具有至少31值的位,因此具有范围足以表示在所有的值[-10 7,10 7 ]。(请注意,类型int足以满足返回类型,其最大值为568。)
  • %负操作数的行为是非直觉的,其规格在C99标准和以前的版本之间有所不同。您应该记录为什么您的方法即使对于负输入也有效。

这是修改后的版本:

int sum_of_digits_squared(long n) {
    int s = 0;

    while (n != 0) {
        /* Since integer division is defined to truncate toward 0 in C99 and C++98 and later,
           the remainder of this division is positive for positive `n`
           and negative for negative `n`, and its absolute value is the last digit
           of the representation of `n` in base 10.
           Squaring this value yields the expected result for both positive and negative `c`.
           dividing `n` by 10 effectively drops the last digit in both cases.
           The loop will not be entered for `n == 0`, producing the correct result `s = 0`.
         */
        int c = n % 10;
        s += c * c;
        n /= 10;
    }
    return s;
}

老师的答案有多个缺陷:

  • 类型int的值范围可能不足。
  • 不需要特殊情况下的值0
  • 否定负值是不必要的,并且可能具有不确定的行为n = INT_MIN

考虑到问题陈述中的额外约束(C99和的值范围n),只有第一个缺陷才是问题。额外的代码仍会产生正确的答案。

您应该在此测试中获得良好的成绩,但是在书面测试中需要进行解释,以表明您对否定性问题的理解n,否则老师可能会认为您没有意识到,只是很幸运。在口试中,您会得到一个问题,而您的答案将会被钉上。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.