【问题标题】:Generating absurd output产生荒谬的输出
【发布时间】:2017-05-18 19:42:46
【问题描述】:

我编写了以下代码,但它生成了荒谬的输出值。我无法弄清楚代码中有什么问题。

#include <stdio.h>

int main(void)
{
    int t, n, i, count;
    scanf("%d", &t);

    while(t--)
    {
        scanf("%d", &n);
        long long a[n], limit;

        for(i = 1; i <= n; i++)
            scanf("%lld", &a[i]);

        count = 1;
        limit = a[1];
        for(i = 2; i <= n; i++)
        {
            if(a[i] < limit)
            {
                count++;
                limit = a[i];
            }
        }

        printf("%lld\n", count);
    }

    return 0;
}

输入:-

3
1
10
3
8 3 6
5
4 5 1 2 3

输出:-

-4621320042389176319
4615368115365085186
-4621320334446952446

请解释我的代码有什么问题。

【问题讨论】:

  • for 循环的范围(以及循环内的索引)都是错误的。您正在访问超出数组a 的范围。数组索引范围为0... N-1

标签: c io printf output


【解决方案1】:

您在这里使用了错误的长度修饰符:

 printf("%lld\n", count);

这样做会调用未定义的行为,因此可以打印任何东西——任何事情都可能发生。

要打印intcount 是),只需使用不带任何长度修饰符的d

 printf("%d\n", count);

(或将count 定义为long long int,这是lld 所期望的)。

【讨论】:

    【解决方案2】:

    给定

    int count;
    

    这段代码

    printf("%lld\n", count);
    

    是未定义的行为。

    根据the C Standard,格式说明符"ll" 用于long long int 类型:

    ll (ell-ell) 指定以下 diouxX 转换说明符适用于 long long intunsigned long long int 参数;或以下n 转换说明符适用于 指向 long long int 参数的指针。

    如果转换规范无效,则行为是 未定义。

    【讨论】:

      【解决方案3】:

      我无法重现垃圾输出,但我在您的代码中看到了两次出现的 UB,这是由于越界访问 a 数组引起的:

      for(i = 1; i <= n; i++)
         scanf("%lld", &a[i]);
      

      ...和...

      for(i = 2; i <= n; i++)
      {         
          if(a[i] < limit)
          {
                  count++;
                  limit = a[i];
          }
      }
      

      在第一种情况下,您将遍历 [1, n] 范围(其中包含 n。在第二种情况下,您将遍历 [2, n] 范围(其中包含 n

      但是您的a 数组有n 元素,所以它的范围是[0, n),其中n 独占

      【讨论】:

        【解决方案4】:

        至少有两个问题: 首先,在 C 数组中,索引以 0 开头,而不是 1。所以它必须是

            for(i = 0; i < n; i++)
                scanf("%lld", &a[i]);
        
            count = 1;
            limit = a[0];
            for(i = 1; i < n; i++)
            {
                if(a[i] < limit)
                {
                    count++;
                    limit = a[i];
                }
            }
        

        其次,您调用printf("%lld\n", count);,但count 是'普通整数',所以它应该是printf("%d\n", count);

        【讨论】: