将整数拆分为两个单独的整数

9
假设我有:
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转换为string,然后进行子串操作,最后再转回int?如何实现此操作? - Prateek
你的问题非常不清楚。也许如果你把它弄清楚了,你就会自己找到答案。 - too honest for this site
1
我说的是数字中的位数..它们都有4位和6位数字,这些数字都是2的倍数。 - Prateek
1
@Eugene,你这里缺少了一些代码。以上示例中没有任何东西会给y赋值为654或任何初始值0以外的值。 - Paul Roub
1
请在您的问题中包含这些必要信息。 - Weather Vane
显示剩余4条评论
7个回答

12

这是一个演示程序,它除了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

1
从大多数角度来看,很难反驳这个答案是最优的。 - mfsiega

4

这是我会做的事情

#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);
}

谢谢你完成了我的工作 :) 你是最棒的...非常感谢你.. 上帝保佑你 - Prateek
3
在问题涉及整数时,使用浮点数进行运算实际上是一种相当糟糕的解决方案。 - The Paramagnetic Croissant
你编辑了你的第一段代码 :) ,你的第一段代码比再次反转字符串要好...它有点冗长...为什么你删除了你的第一段代码,兄弟?它之前运行得很好啊... - Prateek
哦!我明白了...但是再次反转整数有点幼稚,看起来不太专业:\ 除此之外还有其他方法吗? - Prateek
我又编辑了一下,但是我意识到你想要的是 123 456 而不是 123 654,所以我添加了一个“reverse”函数。 - Swann
@TheParamagneticCroissant 我完全支持你的回答,实际上我用了他的代码来节省时间。否则我会简单地使用while循环来找到数字的数量。 - Swann

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;
}

1
另一种可能性:
// 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

0

最简单的方法是使用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是字符串数据类型,我想要结果为整数数据类型,这样我以后可以进行更多的计算。 - Prateek
1
这是一个关于数字的问题,你不应该使用字符串来解决它。 - The Paramagnetic Croissant
@Weather Vane 我手头实际上没有编译器,但我本以为它是可修改的(它不是静态的、常量或其他什么东西)?无论如何,你是对的,至少要有更好的风格。 - mfsiega
你没有对 tmp 进行空终止(两次)。将可能未经空终止的字符串传递给 sscanf() 是未定义行为。现在也有很多在线编译器可用 (1, 2, 3, …)。 - cremno
@mfrankli tmp 是一个具有固定地址的本地变量,存储在堆栈上。你不能直接给它赋另一个值。tmp 不是一个指针。 - Weather Vane
显示剩余4条评论

0

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

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 - Prateek

0

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

#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获取数字并循环遍历它们慢。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接