C returns 中的 Armstrong 数字程序错误值

Armstrong number program in C returns wrong value

我正在编写一个程序来查看用户输入的号码是否为 Armstrong,这是我的代码:

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

int main(){

int x = 0;

printf("Enter a natural number: ");
scanf("%d", &x);
int ans = x;

// Digit Counter
int counter = 0;          //Variable for number of digits in the user entered number
int b = x;                //For each time number can be divided by 10 and isnt 0
for (int i = 1; i <= x; i++){ // Then counter variable is incremented by 1
   b /= 10;
   if (b != 0){
     counter += 1;
   }            
}
++counter;

//Digit Counter
int sum = 0;
// Digit Finder
int D;
for (int j = 1; j <= x; j++){
   D = x % 10;               //Shows remainder of number (last digit) when divided by 10
   sum += pow(D, counter);   //Raises Digit found by counter and adds to sum
   printf("%d\n", sum);
   x /= 10;                  // Divides user entered number by 10 to get   rid of digit found
}



if (sum == ans){
   printf("%d is a Armstrong number! :)", ans);
}else 
   printf("%d is not an Armstrong number :(", ans);
   //Digit Finder

   return 0;
}

我的问题是程序运行良好,除了一点,当程序被赋予一个 1[=28 开头的 Armstrong 编号时=] 然后它表现正常并指示它是否是 Armstrong 号码,但是当我输入以 1 开头的 Armstrong 号码时,它将打印出 Armstrong 号码但 -1。

例如:如果我输入诸如 371 之类的东西,这是一个 Armstrong 号码,它会显示它是一个 Armstrong 号码。但是,如果我输入 1634,它将输出 1633,即 1 小于 1634 .

我该如何解决这个问题?顺便说一句,有人可以评论我的代码并告诉我它是否看起来不错 professional/efficient 因为我是 C 语言的初学者并且会喜欢别人对我的代码的看法。

请从第二个循环中删除 j++ for (int j = 1; j <= x; j++)

我试过这个:

void armstrong(int x)
{
    // count digits
    int counter = 0, temp = x, sum = 0;
    while(temp != 0)
    {
        temp = temp/10;
        ++counter; // Note: pre increment faster
    }
    // printf("count %d\n",counter);
    
    temp = x;
    while(temp != 0)
    {
        sum += pow(temp % 10, counter);
        temp = temp/10;
    }
    // printf("sum %d\n",sum);
    if(x == sum)
    {
        printf("Armstrong\n");
    }
    else
    {
        printf("No Armstrong\n");
    }
}

int main(){

    armstrong(371);
    armstrong(1634);

   return 0;
}

How can I fix this problem.

一旦计算出位数,您就知道要进行的迭代次数。因此,不要循环直到达到 x:

的值
for (int j = 1; j <= x; j++){

改用数字counter

for (int j = 1; j <= counter; j++) {

also by the way could someone comment on my code and tell me if it seems good and professional/efficient because i am a beginner in C and would like someone else's opinion on my code.

您可以做很多事情来改进您的代码。

  1. 首先,任何一段代码都应该正确缩进和格式化。现在你的代码没有缩进,这使得它更难阅读,而且总体上看起来很难看。因此,请始终正确缩进您的代码。使用 IDE 或一个好的文本编辑器,它会帮助你。

  2. 保持代码风格一致。如果你正在写作

if (some_cond) {
 ...
}
else
   //do this

不一致。 else 也用大括号括起来。

  1. 始终检查您使用的函数的 return 值,尤其是 scanf。它将避免您将来出现许多错误。

if (scanf("%d", &x) == 1)
    //...all OK...
else
   // ...EOF or conversion failure...
   exit(EXIT_FAILURE);
  1. 您的第一个 for 循环将无用地迭代 x 次。知道打了就可以停了0:
for (int i = 1; i <= x; i++){ // Then counter variable is incremented by 1
   b /= 10;
   if (b == 0){
      break;
   }
   counter += 1;    
}
  1. C 有 ++ 运算符。使用它而不是 counter += 1

  2. int D; 你创建它,但不初始化它。总是尽快初始化你的变量

  3. C 有 const 限定符关键字,它使值不可变。这使您的代码更具可读性,因为 reader 可以立即告诉您该值不会更改。在您的代码中,您可以更改 ans 变量并将其设为 const int 因为它永远不会更改:

const int ans = x;
  1. 为变量使用更具描述性的名称。 ans, D 什么都别告诉我。使用适当的名称,以便您的代码的 reader 可以轻松理解您的代码。

在我看来,这些是您应该做并继续做的一些事情,以提高您的代码和编码技能。我相信可以有更多的东西。让您的代码尽可能简单易读。

让我们以此为基础添加处理多个数字基数的能力。为什么?因为我们可以!!!! :-)

#include <stdio.h>
#include <math.h>

double log_base(int b, double n)
  {
  return log(n) / log((double)b);
  }

int is_armstrong_number(int b,  /* base */
                        int n)
  {
  int num_digits = trunc(log_base(b, (double)n)) + 1;
  int sum = 0;
  int remainder = n;
  
  while(remainder > 0)
    {
    sum = sum + pow(remainder % b, num_digits);
    remainder = (int) (remainder / b);
    }

  return sum == n;
  }

int main()
  {
  printf("All the following are valid Armstrong numbers\n");

  printf("  407 base 10 - result = %d\n", is_armstrong_number(10, 407));
  printf("  0xEA1 base 16 - result = %d\n", is_armstrong_number(16, 0xEA1));
  printf("  371 base 10 - result = %d\n", is_armstrong_number(10, 371));
  printf("  1634 base 10 - result = %d\n", is_armstrong_number(10, 1634));
  printf("  0463 base 8 - result = %d\n", is_armstrong_number(8, 0463));
  
  printf("All the following are NOT valid Armstrong numbers\n");
  
  printf("  123 base 10 - result = %d\n", is_armstrong_number(10, 123));
  printf("  0x2446 base 16 - result = %d\n", is_armstrong_number(16, 0x2446));
  printf("  022222 base 8 - result = %d\n", is_armstrong_number(8, 022222));
  }

is_armstrong_number 的开头,我们直接计算位数,而不是循环遍历数字。然后,我们循环遍历 b 中 n 的数字,对于给定的数字基数,将增加到数字中数字位数的数字的值相加。一旦余数为零,我们就知道没有更多的数字需要计算,我们 return 一个标志,指示给定数字是否为给定基数中的阿姆斯壮数字。

这个循环中的条件

for (int i = 1; i <= x; i++){ // Then counter variable is incremented by 1
   b /= 10;
   if (b != 0){
     counter += 1;
   }            
}

没有意义,因为循环中会有许多冗余迭代。

例如,如果 x 等于 153,即仅包含 3 个数字,则循环将正好迭代 153 次。

循环后变量计数器的额外增量

++counter;

使代码在逻辑上不一致。

你至少可以用下面的方式代替循环

int counter = 0;
int b = x;

do
{
    ++counter;
} while ( b /= 10 );

此循环迭代的次数恰好等于给定数字中的位数。

在这个循环中

for (int j = 1; j <= x; j++){
   D = x % 10;               //Shows remainder of number (last digit) when divided by 10
   sum += pow(D, counter);   //Raises Digit found by counter and adds to sum
   printf("%d\n", sum);
   x /= 10;                  // Divides user entered number by 10 to get   rid of digit found
}

看来你没有考虑到变量 x 在循环体内被减小了

   x /= 10;                  // Divides user entered number by 10 to get   rid of digit found

所以循环可以过早地中断它的迭代。在任何情况下,循环的条件再次与第一个循环的条件没有太大意义,只会增加一个错误。

用于存储给定数字的变量类型应为无符号整数类型。否则用户可以输入负数。

您可以编写一个单独的函数来检查给定数字是否为阿姆斯壮数字。

给你。

#include <stdio.h>

int is_armstrong( unsigned int x )
{
    const unsigned int Base = 10;
    
    size_t n = 0;

    unsigned int tmp = x;

    do 
    { 
        ++n; 
    } while ( tmp /= Base );
    
    unsigned int sum = 0;
    
    tmp = x;
    do
    {
        unsigned int digit = tmp % Base;
        unsigned int power = digit;
        
        for ( size_t i = 1; i < n; i++ ) power *= digit;
        
        sum += power;
    } while ( ( tmp /= Base ) != 0 && !( x < sum ) );
    
    return tmp == 0 && x == sum;
}

int main(void) 
{
    unsigned int a[] = 
    {
        0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 153, 370, 371, 407, 
        1634, 8208, 9474, 54748, 92727, 93084, 548834
    };
    const size_t N = sizeof( a ) / sizeof( *a );
    
    for ( size_t i = 0; i < N; i++ )
    {
        printf( "%u is %san Armstrong number.\n", a[i], is_armstrong( a[i] ) ? "": "not " );
    }

    return 0;
}

程序输出为

0 is an Armstrong number.
1 is an Armstrong number.
2 is an Armstrong number.
3 is an Armstrong number.
4 is an Armstrong number.
5 is an Armstrong number.
6 is an Armstrong number.
7 is an Armstrong number.
8 is an Armstrong number.
9 is an Armstrong number.
153 is an Armstrong number.
370 is an Armstrong number.
371 is an Armstrong number.
407 is an Armstrong number.
1634 is an Armstrong number.
8208 is an Armstrong number.
9474 is an Armstrong number.
54748 is an Armstrong number.
92727 is an Armstrong number.
93084 is an Armstrong number.
548834 is an Armstrong number.