【问题标题】:Print the digits of a number in reverse order without arrays or functions在没有数组或函数的情况下以相反的顺序打印数字的数字
【发布时间】:2010-12-29 18:46:48
【问题描述】:

作为作业问题,我正在从标准输入读取十进制整数,将其转换为不同的基数(也从标准输入提供)并将其打印到屏幕上。

这是我目前所得到的:

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

int main()
{
    int num, base, remainder, quotient;
    printf("please enter a positive number to convert: ");
    scanf("%d", &num);
    printf("please enter the base to convert to: ");
    scanf("%d", &base);

    remainder = quotient = 1;

    // validate input
    if (num < 0 || base < 0) {
        printf("Error - all numbers must be positive integers!\n");
        return 1;
    }

    // keep dividing to find remainders
    while (quotient > 0) {
        remainder = num % base;
        quotient = num / base;
        num = quotient;
        if (remainder >= 10) {
            printf("%c", remainder + 55);
        } else {
            printf("%d", remainder);
        }
    }   
    printf("\n");
    return 0;
}   

这很好用,只是它使用的算法计算从最低有效位到最高有效位的转换数字,从而将其反向打印。因此,例如,将 1020 转换为十六进制 (0x3FC ) 将打印 CF3

我可以使用什么技巧来反转这些数字以按正确的顺序打印。我只能使用 if-else,而简单的数学运算符和 printf()/getchar()/scanf() - 不能使用函数、数组或指针。谢谢。

【问题讨论】:

  • +1 代码简洁。不错的第一次尝试。
  • 谢谢 - 我实际上已经完成了很多编码工作,但其中大部分是 python、ruby 和 c#.. 所以我真的不能把第一次尝试归功于 ;)跨度>
  • 我认为,您应该发出警告(错误?)。如果基数高于 37,您将打印出特殊字符...当基数高于 255 时,您的程序会如何运行...您将打印出什么?
  • 我实际上更关心 base == 0

标签: c string integer


【解决方案1】:

我们可以使用递归函数来反转数字的数字顺序:

我们需要这些库中的一些数学函数 - stdlib.hmath.h

int reverse(int x)
{
    if(abs(x)<=9)
    {
        return x;
    }
    else
    {
        return reverse(x/10) + ((x%10)*(pow(10, (floor(log10(abs(x)))))));
    }
}

'If 语句'是递归函数的基本情况。

“Else 语句”一开始可能看起来很吓人,但实际上它只是简单的算术运算。 floor(log10(abs(x))) 为我们提供了 x 的位数,因此 ((x%10)*(pow(10, (floor(log10(abs(x))))))) 只是将数字的“个”位数字按照所需的反转数字放在正确的位置。

为了更好地理解,让我们举个例子,让 123 成为我们需要反转的数字。函数reverse 将做的第一件事是询问自己 12 (reverse(x/10)) 的反面,以及第二次使用参数 12 调用该函数时它会问自己 1 的反面,现在这将是我们函数的基本情况。它会以abs(1)&lt;=9 的形式返回1,现在2 将使用((x%10)*(pow(10, (floor(log10(abs(x)))))) 在前面添加,然后返回213 将由相同的前缀。

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

int reverse(int x);
int main()
{
    int x, revInt;
    scanf("%d", &x);           // input : 123
    revInt = reverse(x);
    printf("%d", revInt);      // output : 321
    return 0;
}

【讨论】:

    【解决方案2】:

    根据建议,解决此问题的方法是保持打印最后一个数字并为每个数字重复循环。我通过保存前一个商并在每次到达时打印(然后重置数字并重新开始)来跟踪打印条件,然后将其重置为之前的商。听起来很复杂,但对代码的更改很简单。我的循环停止条件是当我连续打印 2 次时,因为大多数时候它只会计算商/余数而不打印任何内容,而当连续打印 2 位数字时,它是最后两位。无论如何,这是代码:

    #include <stdio.h>
    #include <stdlib.h>
    int main()
    {
        int num, saved, base, remainder;
        int quotient, prev_q, stop_q, just_printed;
    
        printf("please enter a positive number to convert: ");
        scanf("%d", &num);
        printf("please enter the base to convert to: ");
        scanf("%d", &base);
    
        saved = num;
        remainder = quotient = prev_q = just_printed = 1;
        stop_q = 0;
    
        // validate input
        if (num <= 0 || base <= 0) {
            printf("Error - all numbers must be positive integers!\n");
            return 1;
        }
    
        // divide
        while (1) {
            remainder = num % base;
            quotient = num / base;
            num = quotient;
    
            // print if it's the last number and reset num to the next 
            if (quotient == stop_q) {
                if (remainder >= 10) { printf("%c", remainder + 55); } 
                else { printf("%d", remainder); }
    
                // if 2 consecutive printing occur, this means it's time to end this
                if (just_printed) { break; }
    
                // next time print when hitting the previous quotient
                stop_q = prev_q;
    
                // reset the number to the original value
                num = saved;
    
    
                just_printed = 1;
            } else {
                just_printed = 0;
            }
            prev_q = quotient;
        }   
        printf("\n");
        return 0;
    }    
    

    感谢所有参与的人!

    【讨论】:

      【解决方案3】:

      嘿!我也认出了我在学校第一年的一个著名作业(@Epitech 学生:不要复制/粘贴以下代码,尝试提出自己的解决方案,这是为了你自己好^^)

      解决您的问题的方法是以递归方式执行问题:

      void    my_putnbr_base(int num, int base)
      {
        int   start;
        int   remainder;
      
        remainder = num % base;
        start = (num - remainder) / base;
        if (start != 0)
          my_putnbr_base(start, base);
        if (remainder >= 10)
          printf("%c", remainder + 55);
        else
          printf("%d", remainder);
      }
      

      你的作业是否指定它只适用于正数?如果没有,很容易包含负数处理:

      void    my_putnbr_base(int num, int base)
      {
        int   start;
        int   remainder;
      
        if (num < 0)
          {
            putchar('-');
            my_putnbr_base(-num, base);
          }
        else
          {
            remainder = num % base;
            start = (num - remainder) / base;
            if (start != 0)
              my_putnbr_base(start, base);
            if (remainder >= 10)
              printf("%c", remainder + 55);
            else
              printf("%d", remainder);
          }
      }
      

      @arno :是的,因为示例代码使用的是 ASCII 表。如果我们想要真正灵活的东西,我们需要 base in 参数。例如:

      >> my_putnbr_base(4242, "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ")
      39U
      >> my_putnbr_base(42, "0123456789ABCDEF")
      2A
      

      这实现了示例:

      void    my_putnbr_base(int num, char *base)
      {
        int   start;
        int   remainder;
        int   len;
      
        len = strlen(base);
        if (num < 0)
          {
            putchar('-');
            my_putnbr_base(-num, base);
          }
        else
          {
            remainder = num % len;
            start = (num - remainder) / len;
            if (start != 0)
              my_putnbr_base(start, base);
            printf("%c", base[remainder]);
          }
      }
      

      希望能解决你的问题!

      编辑:我没看错^^你不能使用函数,所以递归是不可能的......这是一种交互方式,你可以把它放在main()中。正如我向您展示的那样,您可以通过添加负数处理和灵活的基数来改进此代码:)

      int     my_putnbr_base_it(int num, int base)
      {
        unsigned int  quotient = 1;
        unsigned int  remainder;
      
        while ((num / quotient) >= base)
          quotient *= base;
        while (quotient)
          {
            if ((remainder = (num / quotient) % base) < 10)
              printf("%d", remainder);
            else
              printf("%c", 55 + remainder);
            quotient /= base;
          }
        return (0);
      }
      

      希望它现在可以解决所有问题!

      【讨论】:

        【解决方案4】:

        有趣的任务,你有一个家庭作业。 我是一个初学者程序员,我试图解决这个任务。

        以下代码正在运行(我没有进行很多测试,显然正在运行)。我确信这不是最佳和最佳解决方案,但这是我唯一能想到的。它应该适用于任何基础。不幸的是,它不会转换 10->A、11->B 等:

        #include <stdio.h>
        #include <stdlib.h>
        #include <math.h>
        
        int main(){
                int nr,base,res,tp,tpb,tpbt,r,rnr,lp,lpt,i;
                float baset,rt;
        
                /** Read number */
                printf("nr=");
                scanf("%d",&nr);
        
                /** Read base */
                printf("base=");
                scanf("%d",&base);
        
                /** Returning result */
                res=0;
        
                /** Test if number is positive
                and base is bigger than 2 */
                if(nr<0||base<2){
                        /** Error */
                        res=1;
                }
                else{
                        /** Determine how many
                        digits are necessary */
                        lp=0;
                        baset=base;
                        while(baset>1){
                                lp++;
                                baset/=10;
                        }
        
                        /** Determine full power
                        of 10 when r has length of lp */
                        tpb=1;
                        while((lp--)>0){
                                tpb*=10;
                        }
        
                        /** Power of ten that will be
                        incremented */
                        tp=0;
        
                        /** Converted number (will be printed
                        as the result) */
                        rnr=0;
        
                        /** Algorithm */
                        while(nr>0){
                                r=nr%base;
                                nr/=base;
                                rt=r;
        
                                /** Temporary lp for
                                r */
                                lpt=0;
                                while(rt>1){
                                        lpt++;
                                        rt/=10;
                                }
        
                                /** Temporary tpb for
                                lpt */
                                tpbt=tpb;
                                for(i=0;i<lpt;i++){
                                        tpbt/=10;
                                }
        
                                /** Build number */
                                rnr+=r*pow((double)(tpbt),(double)(tp++));
                        }
                }
        
                /** Show number */
                printf("number is: %d \n",rnr);
        
                return (res);
        }
        

        【讨论】:

        • 在代码中实现自己的简单 pow 函数。这并不难:使用 for/while 循环。
        【解决方案5】:

        这是一个很好的尝试,而且措辞很好。如果我们有更多的人以如此清晰的方式提问!

        这些限制似乎是人为的。我猜你还没有在课堂上学习过函数、数组、指针等,但我认为这个问题不应该在没有函数和/或数组的情况下优雅地解决。

        无论如何,你可以这样做:

        curr := base
        pow := 1
        while num / curr >= 1 do:
            curr := curr * base
            pow := pow + 1
        
        while pow >= 1:
            pow := pow - 1
            print floor(num / base ** pow)
            num := mod(num, base ** pow)
        

        基本上,您是在计算第一个循环中需要多少位数,然后稍后以正确的顺序打印这些数字。

        您的代码存在一些具体问题。我知道这是 C 类的开始,但是,现在知道这些问题总比不知道要好:

        printf("please enter a positive number to convert: ");
        

        您应该在此之后添加一个fflush(stdout),以确保输出出现在调用scanf() 之前。默认情况下,stdout 在许多系统上是行缓冲的,因此在您的程序等待输入之前可能不会出现提示。

        printf("please enter the base to convert to: ");
        

        同上。

            if (remainder >= 10) {
                printf("%c", remainder + 55);
            } else {
                printf("%d", remainder);
            }
        

        您假设为 ASCII 字符集。这不一定是真的。但是如果没有数组或指针,就没有简单的方法来打印对应于10... 的字母表。此外,您的代码可能会为 base &gt; 36 打印奇怪的字符。

        您还应该知道,安全地使用scanf() 非常困难。希望您以后能学到更好的获取输入的方法。

        【讨论】:

          【解决方案6】:

          您可以尝试这种方法。 这更像是一个概念证明,你仍然需要处理一些特殊情况,但是,嘿,这是你的功课:)

          #include <stdio.h>
          #include <stdlib.h>
          
          int main()
          {
              int num, base, remainder, quotient;
              int divider;
          
              printf("please enter a positive number to convert: ");
              scanf("%d", &num);
              printf("please enter the base to convert to: ");
              scanf("%d", &base);
          
              remainder = quotient = 1;
          
              // validate input
              if (num < 0 || base < 0) {
                  printf("Error - all numbers must be positive integers!\n");
                  return 1;
              }
          
              // First get the highest divider
              divider = base;
          
              while ( num / divider > base ) {
                divider *= base;
              }
          
              do {
          
                // Get the highest digit
                remainder = num / divider;
          
                // And update num accordingly
                num -= remainder * divider;
                divider /= base;
          
                if (remainder >= 10) {
                  printf("%c", remainder + 55);
                } else {
                  printf("%d", remainder);
                }
          
              } while ( divider );
          
              printf("\n");
              return 0;
          }
          

          【讨论】:

            【解决方案7】:

            您可以使用两个循环。第一个不断产生碱基的功率,直到它找到一个大于输入数的功率。第二个从这里开始(或者更确切地说,之前的一个幂)并返回到 base^0(即 1)以首先计算输出的最高有效位。

            未经测试的伪代码:

            // Determine highest power, don't actually need "power" it's just there for illustration
            power = 0;
            baseraisedtopower = 1;
            while (baseraisedtopower <= input)
            {
                baseraisedtopower *= base;
                power++;
            }
            // Go back one step, could have saved previous result
            baseraisedtopower /= base;
            power--;
            // Output
            while (input > 0)
            {
                // Integer division, truncate
                quotient = input / baseraisedtopower;
                printf("%c", quotient + 55);
                input -= quotient * baseraisedtopower;
                baseraisedtopower /= base;
                power--;
            }
            

            【讨论】:

              【解决方案8】:

              在一个循环中,您可以计算位数和 big_base。
              在第二个循环中,您可以输出从最高位开始的数字,如下所示:

              n = 1020,3 个十六进制数字,big_base = 16*16

              1st step
              1020 / (16*16) = 3

              2nd step
              n = 1020- 3*(16*16) = 252
              252 / (16) = 15, F

              3rd step
              n = 252 - 15*16 = 12, C

              【讨论】:

              • +1。您需要找出 N,其中base^N &lt;= num &lt; base^(N+1)
              • 使用浮点数学很容易: ceil( log(num) / log(base) ) 但我想这是不允许的,这太容易了。
              【解决方案9】:

              (这里删除了帖子的原始部分,因为它不是解决方案)

              那么我能看到的唯一解决方案是执行你现在拥有数字的次数的循环。

              所以首先你计算所有数字直到你到达最后一个,然后打印出来。

              然后你取原始值 + 基数并再次开始除法,直到你得到第二个“最高值”数字。打印出来。

              这是一个双循环,您计算所有内容两次,但不会使用额外的存储空间。

              【讨论】:

              • 循环体是如何处理它的示例。他可以内联它。但我意识到这不是老师所追求的。所以我在代码下面提供了一个额外的解决方案。
              • 我喜欢第二种解决方案 - 考虑到限制(没有数组、指针等),这似乎是一种不错的方法,即使它有点慢和冗余。 +1
              【解决方案10】:

              您可以重写计算每个数字的代码以充当状态机。它将从初始状态开始并计算位数,然后将状态更改为“打印第 N 位”以打印最高有效数字,然后将状态更改为进行到次要有效数字,等等,直到它进入最后状态。在循环中运行它,您将按正确的顺序输出所有数字。

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 2015-05-05
                • 2019-06-25
                • 1970-01-01
                • 2016-02-17
                • 1970-01-01
                • 2021-08-23
                相关资源
                最近更新 更多