【问题标题】:Split Integer into two separate Integers将整数拆分为两个单独的整数
【发布时间】:2015-08-14 18:45:36
【问题描述】:

假设我有

int n=123456;
int x,y=0;

如何将整数“n”分成两半。

注意:n 中的总位数始终是 2 的倍数,例如 1234、4567、234567、345621 等...都有 2、4、6、8 位. 我想把它们分成两半。

我正在尝试使用以下代码,但它不起作用,y 变量以某种方式保持反转的第二部分。

int x, y=0, len, digit;
int n=123456;

len=floor(log10(abs(n))) + 1;
x=n;
while((floor(log10(abs(x))) + 1)>len/2)
{
    digit=x%10;
    x=x/10;
    y=(y*10)+digit;
}
printf("First Half = %d",x);
printf("\nSecond Half = %d",y);

当输入为:

n=123456;

我得到的输出:

上半场 = 123
下半场 = 654

我想要的输出:

上半场:123

下半场:456

【问题讨论】:

  • 请指导我,我们不能这样做吗?首先通过 sprintf 将 int 转换为字符串,然后将其子串化,然后再转换回 int ??如何做到这一点?
  • 你的问题很不清楚。也许如果你做对了,你自己就会找到答案。
  • 我说的是数字中的位数..都有4位和6位,是2的倍数
  • @Eugene 你在这里遗漏了一些代码。上述示例中的任何内容都不会为y 提供 654 或除初始 0 以外的任何值
  • 请将此重要信息放入您的问题中

标签: c loops split integer reverse


【解决方案1】:

这是一个演示程序。它不使用除 printf 之外的任何函数。:) 因此这是最简单的解决方案。

#include <stdio.h>

int main( void )
{
    unsigned int a[] = { 12, 1234, 123456, 12345678, 1234567890 };
    const unsigned int Base = 10;

    for ( size_t i = 0; i < sizeof( a ) / sizeof( *a ); i++ )
    {   
        unsigned int divisor = Base;
        while ( a[i] / divisor > divisor ) divisor *= Base;

        printf( "%u\t%u\n", a[i] / divisor, a[i] % divisor );
    }        
}

程序输出是

1       2
12      34
123     456
1234    5678
12345   67890

如果您要使用有符号整数类型和负数,那么程序可以如下所示

#include <stdio.h>

int main( void )
{
    int a[] = { -12, 1234, -123456, 12345678, -1234567890 };
    const int Base = 10;

    for ( size_t i = 0; i < sizeof( a ) / sizeof( *a ); i++ )
    {   
        int divisor = Base;
        while ( a[i] / ( a[i] < 0 ? -divisor : divisor ) > divisor ) divisor *= Base;

        printf( "%d\t%d\n", a[i] / divisor, a[i] % divisor );
    }        
}

它的输出是

-1      -2
12      34
-123    -456
1234    5678
-12345  -67890

【讨论】:

  • 很难从大多数角度反对这个答案是最优的
【解决方案2】:

这实际上是我会做的

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

int main(void)
{
  int x, y=0, len, digit;
  int n=123456;

  len=floor(log10(abs(n))) + 1;
  x = n / pow(10, len / 2);
  y = n - x * pow(10, len / 2;
  printf("First Half = %d",x);
  printf("\nSecond Half = %d",y);
}

【讨论】:

  • 感谢我的工作:) 你是最棒的......非常感谢......上帝保佑你
  • 实际上,当问题与整数有关时,对浮点值进行操作是一个非常糟糕的解决方案。
  • 您编辑了您的第一个代码 :),您的第一个代码比再次反转字符串要好 .. 它有点冗长 .. . 为什么您删除了您的第一个代码兄弟?它工作正常......
  • 哦!我明白了..但是再次反转 int 有点幼稚,看起来不像专业:\除此之外还有其他方式吗?
  • 我再次编辑了它,但实际上我试图获得 123 654,所以我添加了一个 reverse 函数。但后来我意识到你实际上想要 123 456。
【解决方案3】:

这可以通过用除数除以模运算符来完成,即 10(NumberOfDigits/2)

#include <stdio.h>

int getNumberOfDigits(int n)
{
    int counter = 0;
    for (; n > 0; n /= 10)
        counter++;
    return counter;
}

int main(void)
{
    int n = 123456;

    int divider = 1;
    for (int i = 0; i < getNumberOfDigits(n) / 2; i++) {
        divider *= 10;
    }
    printf("%d, %d\n", n / divider, n % divider);

    return 0;
}

【讨论】:

    【解决方案4】:

    另一种可能性:

    // split an int value into two pieces with the same number of decimal
    // digits in each piece.  a couple of examples to demonstrate the output
    //     iVal          iTop           iBot
    //     1234            12             34
    //   123456           123            456
    void split_int (int iVal, int *iTop, int *iBot)
    {
        int iTopx = iVal;   // save a copy of the value to be split later
    
        // start with assuming two decimal digits. if value is zero will still work.
        // we will then keep shifting the value right by two decimal digits as
        // we increment our divisor by one decimal digit so that we can create
        // a divisor we can then use to split the value using integer division
        // to get the top half and remainder of integer division for the bottom half.
    
        int iTen = 10;   // divisor value to split two decimal digits
        iVal /= 100;     // shift value right by two decimal digits
        while (iVal) {   // check to see if we are done, if not continue counting
            iTen *= 10;  // increase the divisor value we will use to split digits
            iVal /= 100; // shift value right by two decimal digits
        }
    
        *iTop = iTopx / iTen;  // split off top part by dividing by divisor
        *iBot = iTopx % iTen;  // split off bottom part by taking remainder
    }
    
    // test harness for the function above to try out several input data variations
    // and print the results.  This is a Visual Studio Windows Console Application
    // so the entry point is _tmain().
    int _tmain(int argc, _TCHAR* argv[])
    {
        int iTop, iBot, iVal;
    
        printf ("    iVal       iTop        iBot\n");    // output heading
    
        split_int ((iVal = 123456), &iTop, &iBot);
        printf ("   %8.8d   %8.8d    %8.8d\n", iVal, iTop, iBot);
    
        split_int ((iVal = 12345), &iTop, &iBot);
        printf ("   %8.8d   %8.8d    %8.8d\n", iVal, iTop, iBot);
    
        split_int ((iVal = 12), &iTop, &iBot);
        printf ("   %8.8d   %8.8d    %8.8d\n", iVal, iTop, iBot);
    
        split_int ((iVal = 0), &iTop, &iBot);
        printf ("   %8.8d   %8.8d    %8.8d\n", iVal, iTop, iBot);
    
        split_int ((iVal = 1234567890), &iTop, &iBot);
        printf ("   %8.8d   %8.8d    %8.8d\n", iVal, iTop, iBot);
    
        split_int ((iVal = -1234567890), &iTop, &iBot);
        printf ("   %8.8d   %8.8d    %8.8d\n", iVal, iTop, iBot);
    
        return 0;
    }
    

    产生的输出

        iVal       iTop        iBot
       00123456   00000123    00000456
       00012345   00000012    00000345
       00000012   00000001    00000002
       00000000   00000000    00000000
       1234567890   00012345    00067890
       -1234567890   -00012345    -00067890
    

    【讨论】:

      【解决方案5】:

      由于这似乎是关于数字的问题,更具体地说是整数,因此您不应该使用字符串或浮点运算。

      int n = 123456;
      
      int digits = 0;
      int m = n;
      while (m) {
          digits++;
          m /= 10;
      }
      
      digits /= 2;
      int tmp = 0, lower_half = 0;
      while (digits--) {
          tmp *= 10;
          tmp += n % 10;
          n /= 10;
      }
      
      while (tmp) {
          lower_half *= 10;
          lower_half += tmp % 10;
          tmp /= 10;
      }
      

      这里,n 包含上半部分数字,lower_half 包含下半部分。

      【讨论】:

      • 我不知道,投反对票的不是我。您的代码看起来不错并且也可以正常工作。 +1
      【解决方案6】:

      最简单的方法是使用sprintf 函数。这需要一个值并根据提供的说明符对其进行格式化。将整数表示为字符串后,只需取字符串的每一半。使用sscanf,您可以将过程反转回整数。

      void print_both_halves(int x) {
          char str[80]; // magic number lengths
          char tmp[80];
          int len;
          int a, b;
      
          len = sprintf(str, "%d", x); // returns the number of chars written
      
          strncpy(tmp, str, len/2);
          tmp[len/2] = '\0';
          sscanf(tmp, "%d", &a); // gets the first half
      
          strncpy(tmp, &(str[len/2]), len/2); // copies from the middle of str
          tmp[len/2] = '\0';
          sscanf(tmp, "%d", &b); // gets the second half
      }
      

      【讨论】:

      • 谢谢,但在您的代码中,tmp 是字符串数据类型,我想要整数数据类型的结果,以便以后可以进行更多计算
      • 使用 atoi() 将两个字符串转换回整数
      • 这是一个关于数字的问题,你不应该使用字符串来解决它。
      • 你为什么分配tmp = strncpy(...)tmp 不可修改,函数返回值是为了方便,因此您可以在复合语句中将其传递给另一个函数。这会产生编译错误。
      • @Weather Vane 我实际上手头没有编译器,但我认为它是可修改的(它不是静态的、常量或其他任何东西)?无论如何,你是对的,至少更好的风格
      【解决方案7】:

      使用字符串进行拆分的另一种变体:

      #include <stdio.h>
      #include <string.h>
      #include <stdlib.h>
      
      int split( int val, int *top, int *bot )
      {
        char  tmp[23]; // should be large enough to hold a 64-bit decimal integer
                       // plus sign plus 0 terminator
        char  low[12] = {0};
        char high[12] = {0};
      
        if ( val < 0 )
          val = -val;
      
        sprintf( tmp, "%d", val );
        if ( strlen( tmp ) % 2 )
          return 0;
      
        strncpy( low, tmp, strlen( tmp ) / 2 );
        strncpy( high, tmp + strlen( tmp ) / 2, strlen( tmp ) / 2 );
      
        *top = (int) strtol( low, NULL, 10 );
        *bot = (int) strtol( high, NULL, 10 );
      
        return val;
      }
      
      int main( int argc, char **argv )
      {
        if ( argc < 2 )
        {
          fprintf( stderr, "USAGE: %s integer_value_with_even_number_of_digits\n", argv[0] );
          exit( 0 );
        }
      
        int val = (int) strtol( argv[1], NULL, 10 );
        int lo, hi;
      
        if ( split( val, &lo, &hi ) )
          printf( "val: %d, lo: %d, hi: %d\n", val, lo, hi );
        else
          fprintf( stderr, "USAGE: %s integer_value_with_even_number_of_digits\n", argv[0] );
      
        exit( 0 );
      }
      

      一些示例运行:

      [fbgo448@n9dvap997]~/prototypes/splitter: ./splitter 1
      USAGE: ./splitter integer_value_with_even_number_of_digits
      [fbgo448@n9dvap997]~/prototypes/splitter: ./splitter 12
      val: 12, lo: 1, hi: 2
      [fbgo448@n9dvap997]~/prototypes/splitter: ./splitter -12
      val: -12, lo: 1, hi: 2
      [fbgo448@n9dvap997]~/prototypes/splitter: ./splitter -123
      USAGE: ./splitter integer_value_with_even_number_of_digits
      [fbgo448@n9dvap997]~/prototypes/splitter: ./splitter -1234
      val: -1234, lo: 12, hi: 34
      [fbgo448@n9dvap997]~/prototypes/splitter: ./splitter 12345678
      val: 12345678, lo: 1234, hi: 5678
      [fbgo448@n9dvap997]~/prototypes/splitter: ./splitter -1234567890
      val: -1234567890, lo: 12345, hi: 67890
      [fbgo448@n9dvap997]~/prototypes/splitter: ./splitter 012
      val: 12, lo: 1, hi: 2
      [fbgo448@n9dvap997]~/prototypes/splitter: ./splitter 00123456
      val: 123456, lo: 123, hi: 456
      [fbgo448@n9dvap997]~/prototypes/splitter: ./splitter 001234567
      USAGE: ./splitter integer_value_with_even_number_of_digits
      

      您没有提到值是否必须为正数,或者前导零是否计入位数(由于它被读取为整数值而不是字符串,因此转换后没有前导零)。

      对我来说,这段代码具有简单的优点。我们本质上将数字视为一串数字以从中间拆分,因此(至少在我看来)使用字符串操作似乎是最直接的。在性能方面,这不应该比使用log 获取数字并循环它们慢。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-01-01
        • 2018-01-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-05-23
        相关资源
        最近更新 更多