【问题标题】:For Loop Not Counting Array ValuesFor 循环不计算数组值
【发布时间】:2021-01-13 05:54:13
【问题描述】:

这里是超级新秀。只是在本学期的 C 课程之前做了一点学习。我发现了一本书练习题,要求对数组中的温度值进行分类。这是我所拥有的一切:

// write program to process collection of daily high temps

#include <stdio.h>
    
int main (void)
{
    int temp[26] = {55, 62, 68, 74, 59, 45, 41, 58, 60, 67, 
                    65, 78, 82, 88, 91, 92, 90, 93, 87, 80, 
                    78, 79, 72, 68, 61, 59};

    int i;
    float sum;
    float avg;
    int r1, r2, r3; // range 1, range 2, range 3

    // Loop to catagorize temperature values
    for(i = 0; i <= 26; i++)
    {
        if (temp[i] <= 60)
        {
            r1++;
        }
        else if ((temp[i] > 60) && (temp[i] <= 84))
        {
            r2++;
        }
        else 
        {
            r3++;
        }   

    }

    printf("\nThe number of cold days are: %d", r1);
    printf("\nThe number of pleasant days are: %d", r2);
    printf("\nThe number of hot days are: %d", r3);

    // Loop to take the average temperature
    for (i = 0; i <= 25; i++)
    {
        sum = sum + temp[i];
        avg = sum / i;
    }

    printf("\nThe average temperature of the set is: %f", avg);

    return 0;
}

平均值计算正确,但是,代码未正确分类数组中的临时值。我昨天刚学了数组。任何人都可以帮忙吗?谢谢!

【问题讨论】:

  • 不需要这个(temp[i] &gt; 60) &amp;&amp; 。尝试你的代码并思考逻辑。这样的构造只会在以后更改代码时产生不一致的风险。与您在显示的代码中实际陷入的相同类型的不一致性漏洞,使用“26”作为数组大小,26 个初始化器用于数组,错误地&lt;=26 用于第一个循环,或多或少正确地使用&lt;=25第二个循环,允许第一个循环中的错误潜入。您可以通过自动使用数组的大小来避免sizeof(temp)/sizeof(temp[0])&lt;而不是&lt;=

标签: arrays c loops for-loop


【解决方案1】:

您调用了未定义的行为:

1- 通过使用未初始化的变量int r1, r2, r3; float sum; float avg;,您应该将它们初始化为零。

2- 通过在循环for(i = 0; i &lt;= 26; i++) 中访问if (temp[i] &lt;= 60),而temp 的大小为26(应该只访问0 - 25)。

【讨论】:

    【解决方案2】:

    您应该将 sum, avg, r1, r2, r3 初始化为 0。此外,您的数组范围是 0-25,因此应将 for(i = 0; i &lt;= 26; i++) 更改为 for(i = 0; i &lt;= 25; i++)

    // write program to process collection of daily high temps
    
    #include <stdio.h>
        
    int main (void)
    {
        int temp[26] = {55, 62, 68, 74, 59, 45, 41, 58, 60, 67, 
                        65, 78, 82, 88, 91, 92, 90, 93, 87, 80, 
                        78, 79, 72, 68, 61, 59};
    
        int i;
        float sum = 0;
        float avg = 0;
        int r1 = 0, r2 = 0, r3 = 0; // range 1, range 2, range 3
    
        // Loop to catagorize temperature values
        for(i = 0; i <= 25; i++)
        {
            if (temp[i] <= 60)
            {
                r1++;
            }
            else if ((temp[i] > 60) && (temp[i] <= 84))
            {
                r2++;
            }
            else 
            {
                r3++;
            }   
        }
    
        printf("The number of cold days are: %d\n", r1);
        printf("The number of pleasant days are: %d\n", r2);
        printf("The number of hot days are: %d\n", r3);
    
        // Loop to take the average temperature
        for (i = 0; i <= 25; i++)
        {
            sum = sum + temp[i];
            avg = sum / i;
        }
    
        printf("The average temperature of the set is: %f\n", avg);
    
        return 0;
    }
    

    【讨论】:

      【解决方案3】:

      为了增加变量的值,您需要将值初始化为变量。在这种情况下,变量是 r1、r2 和 r3。增量运算符将其值增加 1。但如果该值之前未分配,则运算符无法找到将增加的值。 这里 r1++ 类似于 r1=r1+1。 所以它应该被初始化为

      r1=0,r2=0,r3=0;
      
      r1++; // which means r1=0+1=1
      
      

      【讨论】:

        【解决方案4】:

        除了其他答案中的现有解决方案之外,我提出了这个解决方案,它向您介绍了防御性编程的概念。在这种情况下,我专注于防御非平凡代码中的不一致。

        #include <stdio.h>
            
        int main (void)
        {
            int temp[/* auto */] =  {55, 62, 68, 74, 59, 45, 41, 58, 60, 67, 65, 78, 82,
            /* newline shows 2*13 */ 88, 91, 92, 90, 93, 87, 80, 78, 79, 72, 68, 61, 59 };
            /* in case space allows, this allows humans to grasp the total number and e.g.
               notice when the number of initialisers is incorrect; the compiler does not
               mind of course */
        
            int i=0; /* this init is paranoid, in case loop setup is unusually without init */
            float sum = 0.0f; /* this init is needed, see other answers */
            float avg = 0.0f; /* this init is needed, see other answers */
            int r1 = 0, r2 = 0, r3 = 0; // range 1, range 2, range 3
        
            size_t length = sizeof(temp)/sizeof(temp[0]); /* avoid need for magic numbers */
        
            // Loop to catagorize temperature values
            for(i = 0; i < length; i++) /* avoid need for magic numbers */
            {
                if (temp[i] <= 60)
                {
                    r1++;
                } else if (temp[i] <= 84) /* avoid copy of first treshold */
                {
                    r2++;
                } else 
                {
                    r3++;
                }   
            }
        
            printf("The number of cold days are: %d\n", r1);
            printf("The number of pleasant days are: %d\n", r2);
            printf("The number of hot days are: %d\n", r3);
        
            // Loop to take the average temperature
            for (i = 0; i < length; i++) /* avoid need for magic number */
            {
                sum = sum + temp[i];
                avg = sum / i;
            }
        
            printf("The average temperature of the set is: %f\n", avg);
        
            return 0;
        }
        

        您可能会注意到,避免使用幻数(使用 &lt;)和初始化所有内容的习惯会阻止其他答案中讨论和解决的两个问题。

        您还可以通过输出一些附加信息来引入人类发现错误的机会,当然前提是它与您的要求不冲突。在这种情况下,可以在您的团队中以一种通用的方式,以一种可以方便地移除以便交付的方式创建额外的输出。如果没有这种删除机制,这会在输出中展示“不显眼”的附加信息(我承认这明显夸大了):

        printf("The average temperature of the set of %i temperatures "
               "(%i of which have been classified) is: %f\n", length, r1 + r2 + r3, avg);
        

        在 if-else 结构中对齐{} 的特殊方式是我最喜欢的缩进样式。在我看来,但这只是一种观点,它也是防御性编程,因为至少我确实更容易像那样发现 if-else-trees,因此更有机会发现错误。使用{} 即使是单语句分支也是其中的一部分,它可以防止在没有{} 的情况下向单语句else 分支添加语句引入的错误。

        删除逻辑上不需要的(temp[i] &gt; 60) &amp;&amp; 可以防止类似的错误

        if (temp[i] < 60)
        {
            r1++;
        } else if ((temp[i] > 60) && (temp[i] < 84))
        {
            r2++;
        } else 
        {
            r3++;
        }
        

        因为它避免了复制代码(在本例中是针对阈值 60 的检查)以及两个副本之间不一致的风险。在这种情况下,我引入的错误会导致边缘外壳温度 60 的错误分类。

        【讨论】:

        • 可以说,使用 0.0f 匹配 float 但例如不完全是double,是反对防御概念的。这是一种根深蒂固的习惯,它不是防御性编程的预期介绍的一部分。
        猜你喜欢
        • 2016-12-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-03-27
        • 1970-01-01
        相关资源
        最近更新 更多