如何在C语言中连接两个整数

23

虽然Stack Overflow已经回答了很多其他语言的这个问题,但没有C语言的答案。因此我想问一下,因为我也遇到了同样的问题。

如何在C语言中连接(concatenate)两个整数?

示例:

x = 11;
y = 11;
我希望将 z 设为以下内容:
z = 1111;

其他示例尝试使用字符串来实现此目的。有没有一种不使用字符串的方法呢?

我正在寻找一种在C语言中高效地实现此操作的方法,因为在我的特定用法中,这将进入代码的时间关键部分。

谢谢提前!


9
喜欢 100 * x + y 这样的格式吗? - Kerrek SB
1
你想要C还是C++?两者的答案会非常不同。从标题来看,我猜你想要C。 - Mooing Duck
请用 C 语言实现,谢谢。 - 101010
1
当 y == 0 时,100 * x + y 失败。 - 101010
10个回答

50
unsigned concatenate(unsigned x, unsigned y) {
    unsigned pow = 10;
    while(y >= pow)
        pow *= 10;
    return x * pow + y;        
}

证明编译/正确性/速度

我避免使用log10pow函数,因为我相当确定它们使用浮点数并且速度较慢,所以这个方法在您的机器上可能更快。也许。进行分析。


我认为没有什么能够超过你的答案。 - Tae-Sung Shin
4
必须满足 y >= pow,我认为concatenate(1,10)不应该等于20。 - Daniel Fischer
先生,您说得对,对于某些数字,我的计算是不准确的。已经修正。 - Mooing Duck
请友善一点。这将进入嵌入式微控制器。我所提到的“开销”是指浮点数处理所生成的机器代码量。 - 101010
5
可能会出现潜在的无限循环:例如在32位系统上尝试concatenate(1, 1000000000)。你可以在while循环内部加入if (pow > UINT_MAX / 10) return y;来避免这种情况。 - chqrlie
显示剩余7条评论

12
z = x * pow(10, log10(y)+1) + y;

解释:

首先获取应该排在第二位的变量的数字个数:

int digits = log10(y)+1;  // will be 2 in your example

然后您可以通过将另一个变量乘以10^digits来"移位"该变量。

int shifted = x * pow(10, digits);   // will be 1100 in your example

最后您需要添加第二个变量:

z = shifted + y;   // 1111

或者一行代码实现:

z = x * pow(10, (int)log10(y)+1) + y;

2
我正在为你的回答点赞,因为你真正解释了问题。 - Mooing Duck
最好避免在整数问题中使用浮点数运算。 - chux - Reinstate Monica

3

这可能不是最优的或最快的解决方案,但没有人提到它,它很简单,也可能很有用。

您可以使用 sprintf()strtol()

char str[100];
int i=32, j=45;
sprintf(str, "%d%d", i, j);
int result=strtol(str, NULL, 10);

你首先使用sprintf()将数字一和另一个数字写入字符串中(就像你使用printf()打印到标准输出一样),然后使用strtol()将结果字符串转换为数字。 strtol()返回一个long,它可能是大于可以存储在int中的值,因此您可能需要先检查结果值。
int result;
long rv=strtol(str, NULL, 10);
if(rv>INT_MAX || rv<INT_MIN || errno==ERANGE)
{
    perror("Something went wrong.");
}
else
{
    result=rv;
}

如果strtol()返回的值不在int的范围内(即不在包括INT_MININT_MAX在内的范围内),则会出现错误。其中,INT_MININT_MAX来自于limits.h
如果字符串中的值太大而无法表示为long,则由于溢出,errno将被设置为ERANGE(来自于errno.h)。
关于strtol()的更多信息,请点击这里
编辑:
正如来自chqrlie的启示性评论所指出的,负数可能会与此方法造成麻烦。
您可以使用此代码或其修改版来解决这个问题。
char str[100], temp[50];
int i=-32, j=45, result;
sprintf(temp, "%+d", j);
sprintf(str, "%d%s", i, temp+1);
long rv=strtol(str, NULL, 10);

首先,将第二个数字及其符号打印到字符数组temp中。

%+d中的+将导致数字的符号被打印出来。

现在,将第一个数字和第二个数字(但不包括第二个数字的符号部分)打印到str中。我们通过忽略temp中的第一个字符来跳过第二个数字的符号部分。

最后完成strtol()


1
这是处理潜在溢出的好方法。添加相应的代码,设置和测试errno并将结果与INT_MININT_MAX进行比较会很有帮助。ij的负值也会导致问题。 - chqrlie
@chqrlie,感谢您抽出时间告诉我们这个问题。我没有考虑到负数的问题,也没有想到需要查看INT_MIN - J...S
如果(rv>INT_MAX || rv<INT_MIN || errno==ERANGE)应该改为if(rv>LONG_MAX || rv<LONG_MIN || errno==ERANGE)`。一般而言,这种方法无法检测出 'strtol("!!!", ...)'中的错误,因为errno不能确定地设置。 - chux - Reinstate Monica

2
这是@Mooing Duck答案的变体,它使用查找表来处理10的倍数(适用于整数乘法速度较慢的平台)。它还返回unsigned long long以允许更大的值,并在查找表中使用unsigned long long来解决@chqrlie关于无限循环的评论。如果可以保证组合输入不超过unsigned,则可以更改这些内容。
static const unsigned long long pow10s[] = {
   10,100,1000,10000,100000,1000000,10000000,100000000,1000000000,10000000000
};
unsigned long long concat(unsigned x, unsigned y) {
    const unsigned long long *p = pow10s;
    while (y >= *p) ++p;
    return *p * x +y;        
}

2
最初的回答:您还可以使用宏来连接字符串(简单方式)。
您可以使用宏来连接字符串(简单方式)。
#include<stdio.h>
#define change(a,b) a##b
int main()
 {
    int y;
    y=change(12,34);
    printf("%d",y);
    return 0;
 }

它有一个缺点。我们无法在这个方法中传递参数。最初的回答。

2
int myPow(int x, int p)
{
     if (p == 0) return 1;
     if (p == 1) return x;

     int tmp = myPow(x, p/2);
     if (p%2 == 0) return tmp * tmp;
     else return x * tmp * tmp;
}
int power = log10(y);
z = x*myPow(10,power+1)+y;

在这里,我不好意思地抄袭了myPow函数,来源于https://dev59.com/GXI_5IYBdhLWcg3wJfkM#1505791


1

这里有另一种方法来做:

int concat(int x, int y) {
    int temp = y;
    while (y != 0) {
        x *= 10;
        y /= 10;
    }
    return x + temp;
}

谁知道你会得到什么性能。只有尝试才能知道。


concat(123, 0) 返回的是 123 而不是 1230。建议使用 do ... while 循环。 - chux - Reinstate Monica
这确实是最好的答案,一旦解决了边缘情况。我也会使用“unsigned”,但OP不确定。 - chux - Reinstate Monica

0

这是对@Mooing Duck@none答案的改进版本。

根据需要,只需将十进制数x进行移位即可。

unsigned concatenate2(unsigned x, unsigned y) {
  unsigned y_temp = y;
  do {  // do loop to insure at least one shift
    x *= 10;
    y_temp /= 10;
  } while (y_temp > 0);
  return x + y;  
}

可以使用更广泛的数学方法来减少溢出可能性。@technosaurus

#include <inttypes.h>

uintmax_t concatenate2(unsigned x, unsigned y) {
  uintmax_t x_temp = x;
  unsigned y_temp = y;
  do {  // do loop to insure at least one shift
    x_temp *= 10;
    y_temp /= 10;
  } while (y_temp > 0);
  return x_temp + y;  
}

0
也许这个会有用:
int x=11,y=11,temp=0;
int z=x;
while(y>0)
{
    // take reciprocal of y into temp
    temp=(temp*10)+(y%10);       
    y=y/10;
}
while(temp>0)
{
    // take each number from last of temp and add to last of z
    z=(z*10)+(temp%10);      
    temp=temp/10;
}

代码很长,但很简单。 如果有任何错误,请纠正我。


“Assertion `func(0, 10) == 10' failed”. 可能还有其他边缘情况。 - Mooing Duck

-3
#include<iostream>
using namespace std;

int main()
{
    int a=0,b=0,count=0,c=0,t=0;
    cout<<"enter 2 no"<<endl;
    cin>>a>>b;
    t=b;

    while(b!=0)
    {
        b=b/10;
        count++;
    }

    while(count!=0)
    {
        a=a*10;
        count--;
        c=a+t;
    }

    cout<<"concate no is:"<<c;
}

5
楼主希望在C语言中寻找解决方案。你提供了一个C++的解决方案,因为你使用了 cincout。而且,你回答了一个旧问题,已经有几个广受欢迎的答案。你的解决方案有何优势,值得发表吗? - honk

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