将unsigned int与unsigned int相加时发生溢出

问题描述

我正在尝试为此解决方案(codewars cata,6 kyu):

创建一个函数,该函数返回两个最低正数的和 给出至少4个正整数的数组的数字。没有浮球或 非正整数将被传递。例如,当一个数组是 如[19、5、42、2、77]这样传递,输出应为7。 [10,343445353,3453445,3453545353453]应该返回3453455。

我几乎找到了它。但是显然,我对这里的类型力学有些误解。对于测试用例

数字= {2000000000、2000000000、2000000000、2000000000、2000000000}

我得到溢出。这对我来说是完全奇怪的。我读过C int类型的大小取决于编译系统。我有64位系统,所以我的int很大。此外,在此任务中,我们只有 unsigned 个整数,因此看来32位 4 * 10 ^ 9可能就足够了。我尝试使用uint_32t和uint_64t类型。现在,我正在尝试转换所有变量,这不是方便的方法。寻找解决方案我还需要了解什么?

这是我当前的代码

#include <stddef.h>
#include <stdio.h>
long sum_two_smallest_numbers(size_t n,const int numbers[n]) {
  int current_low1;//suppose first 2 ones are the lowest
  int current_low2;//and current_low1 is reserved for the lowest one

  int delta1;//variables for comparations
  int delta2;
  //every new value in array to be compared with 
  //current_low1 and current_low2.
  //then define - if new values are lesser
  //and if so - find out is new value the lowest
  if (numbers[0] < numbers[1]){
    current_low1 = numbers[0];
    current_low2 = numbers[1];
  } else {
    current_low1 = numbers[1];
    current_low2 = numbers[0];
  }
  int ind;
  for (ind = 2; (unsigned long) ind < n; ind++){
    if ((numbers[ind] < current_low1) && (numbers[ind] < current_low2)){
      delta1 = current_low1 - numbers[ind];
      delta2 = current_low2 - numbers[ind];
      if (delta1 > delta2){
        current_low1 = numbers[ind];
      } else{
        current_low2 = numbers[ind];
      }
    } else if ((numbers[ind] >= current_low1) && (numbers[ind] < current_low2)){
      current_low2 = numbers[ind];
    } else if ((numbers[ind] < current_low1) && (numbers[ind] >= current_low2)){
      current_low1 = numbers[ind];
    }
    }

  return (unsigned long)(current_low1 + current_low2);
}

非常感谢您的回答。在阅读所有帖子并经过深思熟虑后,我找到了解决方案... 因此,我使用了 signed 整数。因为 int 声明认情况下会调用带符号整数。然后,我将前4个变量的声明更改为 unsigned int 。现在就可以了!我什至不再需要将返回语句打成长串。

谢谢大家,尤其是@Adrian Mole!

解决方法

我将类型更改为uint64_t并调用它。

#include <stddef.h>
#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>

uint64_t sum_two_smallest_numbers(size_t n,const uint64_t  numbers[n]) {
  uint64_t  current_low1;//suppose first 2 ones are the lowest
  uint64_t  current_low2;//and current_low1 is reserved for the lowest one

  uint64_t  delta1;//variables for comparations
  uint64_t  delta2;
  //every new value in array to be compared with 
  //current_low1 and current_low2.
  //then define - if new values are lesser
  //and if so - find out is new value the lowest
  if (numbers[0] < numbers[1]){
    current_low1 = numbers[0];
    current_low2 = numbers[1];
  } else {
    current_low1 = numbers[1];
    current_low2 = numbers[0];
  }
  size_t ind;
  for (ind = 2; ind < n; ind++){
    if ((numbers[ind] < current_low1) && (numbers[ind] < current_low2)){
      delta1 = current_low1 - numbers[ind];
      delta2 = current_low2 - numbers[ind];
      if (delta1 > delta2){
        current_low1 = numbers[ind];
      } else{
        current_low2 = numbers[ind];
      }
    } else if ((numbers[ind] >= current_low1) && (numbers[ind] < current_low2)){
      current_low2 = numbers[ind];
    } else if ((numbers[ind] < current_low1) && (numbers[ind] >= current_low2)){
      current_low1 = numbers[ind];
    }
    }

  return (current_low1 + current_low2);
}

#define SIZE 5

int main()
{
    
    uint64_t  balance[SIZE] = {2000000000,2000000000,2000000000};

    printf("%" PRIu64,sum_two_smallest_numbers(SIZE,balance));

    return 0;
}

它打印4000000000

printf("%" PRIu64...#include <inttypes.h>用于打印uint64_t

,

不要仅仅因为您的操作系统或平台是64位,就假定C编译器具有64位int类型。实际上,许多/大多数此类系统(例如64位Windows上的MSVC)没有。

如果您的基本int类型为32位,则两个2000000000 有符号整数 的总和将溢出(但未签名)。

因此,将您的numbers参数声明为const int64_t numbers[n];并且类似地,在调用模块的数组声明中使用int64_t类型。您可能还可以使用long long int,因为它也应该至少 64位宽。

您还应该将int函数(以及该函数的返回类型)中的相关局部sum_two_smallest_numbers变量更改为“显式”的64位(或long long)整数。