需要帮助调试

时间:2018-09-28 23:58:46

标签: c for-loop if-statement range

我要生成的函数称为:

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

2 个答案:

答案 0 :(得分:3)

您需要正确跟踪较小和较大的值。您可以删除不需要的displayonedisplaytwo变量。只需使用largesmall来跟踪循环中的值即可。

严格来说,要使函数健壮,还应该考虑其他几件事:

  1. 元素数为零(或更少)的情况-在这种情况下,范围是不确定的。返回零可能是我们能做的最好的事情。
  2. 一个int值与另一个值相减的结果可能导致溢出-例如,考虑INT_MAX-INT_MIN。其结果大约为40亿,比未签名的int可以表示的大约20亿要大得多。从数学上讲,范围将始终为正数;负面的可能在这里没有意义。因此,使返回类型为unsigned int应该是适当的,并防止溢出,并确保将中间largesmall变量扩展到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)

Iananswer所述,如果数组中的数字既可以是正数也可以是负数,并且仅受类型int的限制所约束,而不会更小范围,您需要以无符号整数形式返回范围,因为最大整数减去最小整数会使有效整数范围(但无符号整数范围)溢出。

解决计算问题的一种方法是使用比数组类型更长的带符号类型(这是Ian的答案),但是当不再有带符号类型时,最终会遇到问题。以下代码在我的GitHub上的SOQ(堆栈溢出问题)存储库中,作为src/so-5256-3870子目录中的文件array-range-17.c提供。它仅使用intunsigned类型,而不再使用任何更长的类型。

/* 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_tuintmax_t
  • -DUSE_LONG_LONG-使用long longunsigned long long
  • -DUSE_LONG-使用longunsigned long
  • -DUSE_INT64-使用int64_tuint64_t
  • -DUSE_INT32-使用int32_tuint32_t
  • -DUSE_INT16-使用int16_tuint16_t
  • -DUSE_INT(或以上都不是)-使用intunsigned

添加shortsigned charint8_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

我相信代码可以在使用二进制补码算法的机器上工作。我相信它将在使用补码或符号幅度算法的机器上运行,但是我无法对其进行测试。