我要生成的函数称为:
int Range(int values[], int numValues)
目的是返回数组中的最大值与数组中的最小值之差。
下面是我的代码,但是它不起作用。任何帮助将不胜感激:)
#include <stdio.h>
int Range(int values[], int numValues)
{
int i;
int large;
int small;
int displayone;
int displaytwo;
int calc;
large = values[0];
small = values[0];
for(i=0;i<numValues;i++){
if(values[i]>large){
displayone = values[i];
}
else if(values[i] < small){
displaytwo = values[i];
}
}
calc = displayone - displaytwo;
return calc;
}
答案 0 :(得分:3)
您需要正确跟踪较小和较大的值。您可以删除不需要的displayone
和displaytwo
变量。只需使用large
和small
来跟踪循环中的值即可。
严格来说,要使函数健壮,还应该考虑其他几件事:
int
值与另一个值相减的结果可能导致溢出-例如,考虑INT_MAX-INT_MIN。其结果大约为40亿,比未签名的int
可以表示的大约20亿要大得多。从数学上讲,范围将始终为正数;负面的可能在这里没有意义。因此,使返回类型为unsigned int
应该是适当的,并防止溢出,并确保将中间large
和small
变量扩展到long long
以允许最终的减法正确发生。考虑到以上所有因素,该功能变为:
#include <stdio.h>
unsigned int Range(int values[] , int numValues)
{
int i;
long long large; // <<<< Make long long to support ...
long long small; // <<<< ... final subtraction
unsigned int calc; // <<<< Make unsigned int to match return
if (numValues < 1) // <<<< Handle invalid input
return 0;
large = values[0];
small = values[0];
for(i=0;i<numValues;i++){
if(values[i]>large)
large = values[i]; // <<<< assign to large here
else if(values[i] < small)
small = values[i]; // <<<< and similar for small
}
calc = (uint)(large - small); // <<<< then calculate difference
return calc;
}
答案 1 :(得分:0)
如Ian的answer所述,如果数组中的数字既可以是正数也可以是负数,并且仅受类型int
的限制所约束,而不会更小范围,您需要以无符号整数形式返回范围,因为最大整数减去最小整数会使有效整数范围(但无符号整数范围)溢出。
解决计算问题的一种方法是使用比数组类型更长的带符号类型(这是Ian的答案),但是当不再有带符号类型时,最终会遇到问题。以下代码在我的GitHub上的SOQ(堆栈溢出问题)存储库中,作为src/so-5256-3870子目录中的文件array-range-17.c
提供。它仅使用int
和unsigned
类型,而不再使用任何更长的类型。
/* SO 5256-3870 */
#include <assert.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
static unsigned ArrayRange(size_t num_values, int values[num_values])
{
int large;
int small;
unsigned range;
if (num_values < 1)
return 0;
large = values[0];
small = values[0];
for (size_t i = 1; i < num_values; i++)
{
if (values[i] > large)
large = values[i];
else if (values[i] < small)
small = values[i];
}
if ((large >= 0 && small >= 0) || (large <= 0 && small <= 0))
{
/* Most common cases - both values of same sign; no overflow risk */
/* Any mode of binary arithmetic */
assert(large >= small);
range = large - small;
}
else if ((-INT_MAX == INT_MIN) || (small != INT_MIN))
{
/*
** Two's complement arithmetic with values with different signs
** but the small value is not INT_MIN, or one's complement
** arithmetic or sign-magnitude arithmetic (which have negative
** zeros but no asymmetry in the positive vs negative ranges).
*/
/* Different signs — therefore large is positive and small is negative */
assert(large > 0 && small < 0);
range = (unsigned)large + (unsigned)(-small);
}
else
{
/* Twos-complement arithmetic — small is INT_MIN */
assert(-INT_MAX - 1 == INT_MIN);
assert(small == INT_MIN && large > 0);
range = (unsigned)large + INT_MAX + 1;
}
return range;
}
int main(void)
{
int arrays[][2] =
{
{ +345, +436 },
{ +436, +345 },
{ -199, -439 },
{ -439, -199 },
{ -999, +999 },
{ +999, -999 },
{ 0, 0 },
{ 0, INT_MAX },
{ 0, INT_MIN },
{ 0, INT_MAX },
{ -1000, INT_MAX },
{ +1000, INT_MAX },
{ -1000, INT_MIN },
{ +1000, INT_MIN },
{ INT_MIN, INT_MAX },
{ INT_MIN, INT_MIN },
{ INT_MAX, INT_MAX },
{ INT_MIN, -INT_MAX },
};
enum { NUM_ARRAYS = sizeof(arrays) / sizeof(arrays[0]) };
for (int i = 0; i < NUM_ARRAYS; i++)
{
unsigned int range = ArrayRange(2, arrays[i]);
printf("%+11d:%+-11d = %u\n", arrays[i][0], arrays[i][1], range);
}
return 0;
}
测试代码仅适用于具有两个元素的数组,但也适用于较大的数组。输出为:
+345:+436 = 91
+436:+345 = 91
-199:-439 = 240
-439:-199 = 240
-999:+999 = 1998
+999:-999 = 1998
+0:+0 = 0
+0:+2147483647 = 2147483647
+0:-2147483648 = 2147483648
+0:+2147483647 = 2147483647
-1000:+2147483647 = 2147484647
+1000:+2147483647 = 2147482647
-1000:-2147483648 = 2147482648
+1000:-2147483648 = 2147484648
-2147483648:+2147483647 = 4294967295
-2147483648:-2147483648 = 0
+2147483647:+2147483647 = 0
-2147483648:-2147483647 = 1
正如我在评论中指出的那样,如果数组的整数类型是无符号的,则代码非常简单;无需担心溢出,并且所有数据都具有相同的必要性征兆。
您可以参数化上面的代码以使用不同的整数类型。这是一些可以编译的代码:
-DUSE_INTMAX
-使用intmax_t
和uintmax_t
。-DUSE_LONG_LONG
-使用long long
和unsigned long long
。-DUSE_LONG
-使用long
和unsigned long
。-DUSE_INT64
-使用int64_t
和uint64_t
。-DUSE_INT32
-使用int32_t
和uint32_t
。-DUSE_INT16
-使用int16_t
和uint16_t
。-DUSE_INT
(或以上都不是)-使用int
和unsigned
。添加short
,signed char
和int8_t
对于读者来说并不是一件很令人兴奋的练习。
/* SO 5256-3870 */
#include <assert.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <inttypes.h>
/* Paramterization for signed types */
#if defined(USE_INTMAX)
typedef intmax_t SignedType;
typedef uintmax_t UnsignedType;
#define SIGNED_MAX INTMAX_MAX
#define SIGNED_MIN INTMAX_MIN
#define DATA_FMT "20" PRIdMAX
#define RANGE_FMT PRIuMAX
#elif defined(USE_LONG_LONG)
typedef long long SignedType;
typedef unsigned long long UnsignedType;
#define SIGNED_MAX LLONG_MAX
#define SIGNED_MIN LLONG_MIN
#define DATA_FMT "20lld"
#define RANGE_FMT "llu"
#elif defined(USE_LONG)
typedef long SignedType;
typedef unsigned long UnsignedType;
#define SIGNED_MAX LONG_MAX
#define SIGNED_MIN LONG_MIN
#define DATA_FMT "20ld" // 11ld would do is sizeof(long) == 4
#define RANGE_FMT "lu"
#elif defined(USE_INT64)
typedef int64_t SignedType;
typedef uint64_t UnsignedType;
#define SIGNED_MAX INT64_MAX
#define SIGNED_MIN INT64_MIN
#define DATA_FMT "20" PRId64
#define RANGE_FMT PRIu64
#elif defined(USE_INT32)
typedef int32_t SignedType;
typedef uint32_t UnsignedType;
#define SIGNED_MAX INT32_MAX
#define SIGNED_MIN INT32_MIN
#define DATA_FMT "11" PRId32
#define RANGE_FMT PRIu32
#elif defined(USE_INT16)
typedef int16_t SignedType;
typedef uint16_t UnsignedType;
#define SIGNED_MAX INT16_MAX
#define SIGNED_MIN INT16_MIN
#define DATA_FMT "6" PRId16
#define RANGE_FMT PRIu16
#else /* USE_INT */
typedef int SignedType;
typedef unsigned UnsignedType;
#define SIGNED_MAX INT_MAX
#define SIGNED_MIN INT_MIN
#define DATA_FMT "11d"
#define RANGE_FMT "u"
#endif
static UnsignedType ArrayRange(size_t num_values, SignedType values[num_values])
{
if (num_values == 0)
return 0;
SignedType large = values[0];
SignedType small = values[0];
for (size_t i = 1; i < num_values; i++)
{
if (values[i] > large)
large = values[i];
else if (values[i] < small)
small = values[i];
}
UnsignedType range;
assert(small <= large);
if (small >= 0 || large < 0 || (large == 0 && small != SIGNED_MIN))
{
/* Most common cases - both values of same sign; no overflow risk */
/* Any mode of binary arithmetic */
assert(large >= small);
range = large - small;
}
else if ((-SIGNED_MAX == SIGNED_MIN) || (small != SIGNED_MIN))
{
/*
** Two's complement arithmetic with values with different signs
** but the small value is not SIGNED_MIN, or one's complement
** arithmetic or sign-magnitude arithmetic (which have negative
** zeros but no asymmetry in the positive vs negative ranges).
*/
/* Different signs — therefore large is positive and small is negative */
assert(large > 0 && small < 0);
range = (UnsignedType)large + (UnsignedType)(-small);
}
else
{
/* Twos-complement arithmetic — small is SIGNED_MIN */
assert(-SIGNED_MAX - 1 == SIGNED_MIN);
assert(small == SIGNED_MIN && large >= 0);
range = (UnsignedType)large + SIGNED_MAX + 1;
}
return range;
}
int main(void)
{
SignedType arrays[][2] =
{
{ +345, +436 },
{ +436, +345 },
{ -199, -439 },
{ -439, -199 },
{ -999, +999 },
{ +999, -999 },
{ 0, 0 },
{ 0, SIGNED_MAX },
{ 0, SIGNED_MIN },
{ 0, SIGNED_MAX },
{ -1000, SIGNED_MAX },
{ +1000, SIGNED_MAX },
{ -1000, SIGNED_MIN },
{ +1000, SIGNED_MIN },
{ SIGNED_MIN, SIGNED_MAX },
{ SIGNED_MIN, SIGNED_MIN },
{ SIGNED_MAX, SIGNED_MAX },
{ SIGNED_MIN, -SIGNED_MAX },
};
enum { NUM_ARRAYS = sizeof(arrays) / sizeof(arrays[0]) };
for (int i = 0; i < NUM_ARRAYS; i++)
{
UnsignedType range = ArrayRange(2, arrays[i]);
printf("%+" DATA_FMT ":%+-" DATA_FMT " = %" RANGE_FMT "\n",
arrays[i][0], arrays[i][1], range);
}
return 0;
}
在运行MacOS 10.14 Mojave的Mac上使用-DUSE_INTMAX
进行编译,使用GCC 8.2.0进行编译时,我得到的结果是:
+345:+436 = 91
+436:+345 = 91
-199:-439 = 240
-439:-199 = 240
-999:+999 = 1998
+999:-999 = 1998
+0:+0 = 0
+0:+9223372036854775807 = 9223372036854775807
+0:-9223372036854775808 = 9223372036854775808
+0:+9223372036854775807 = 9223372036854775807
-1000:+9223372036854775807 = 9223372036854776807
+1000:+9223372036854775807 = 9223372036854774807
-1000:-9223372036854775808 = 9223372036854774808
+1000:-9223372036854775808 = 9223372036854776808
-9223372036854775808:+9223372036854775807 = 18446744073709551615
-9223372036854775808:-9223372036854775808 = 0
+9223372036854775807:+9223372036854775807 = 0
-9223372036854775808:-9223372036854775807 = 1
我相信代码可以在使用二进制补码算法的机器上工作。我相信它将在使用补码或符号幅度算法的机器上运行,但是我无法对其进行测试。