【问题标题】:Why does my code fall apart when I ask it to divide two variables? [duplicate]当我要求我的代码除以两个变量时,为什么我的代码会崩溃? [复制]
【发布时间】:2022-08-04 05:15:26
【问题描述】:

我目前正在学习 cs50 课程(免费版,所以我没有同学或老师的反馈),我们被要求编写一个程序来读取用户输入的文本,并分析文本:

  • 字母数
  • 字数
  • 句子数
  • L = 平均每 100 个单词的字母数
  • S = 平均每 100 个单词的句子数
  • 年级 = (((0.0588) * L) - ((0.296) * S)) - 15.8)

示例文本:

“你喜欢这里还是那里?我不喜欢这里或那里。我在任何地方都不喜欢它们。”

我已经对代码进行了调试,它成功地计算了字母、单词和句子。

第一个问题出现在这里:

    float calculate_avg_letters(int letters, int 
    words)
    {
        float L = ((letters) / (words)) * 100;
   
        return (L);
    } 

我已经尝试了一切(我认为),从更改数据类型、重新排列括号、使用两个单独的函数先执行除法然后乘以结果变量、更改前一个变量的数据类型。逐步调试显示(字母 = 80)、(单词 = 21)和(句子 = 3),所以 L = ((80 / 21) * 100)。它应该是 ~380,但我能得到的最接近的是 300,并且大多数变体输出类似于 1.44e13

对于上下文,这是整个代码:

    #include <cs50.h>
    #include <stdio.h>
    #include <string.h>
    #include <ctype.h>
    #include <math.h>


    float count_letters(string paragraph);
    float count_words(string paragraph);
    float count_sentences(string paragraph);
    float calculate_avg_letters(int letters, int 
    words);
    float calculate_avg_sentences(int sentences, int 
    words);
    int calculate_grade_level(int L, int S);


    int main(void)
    {
        string text = get_string(\"Text: \");

        float letters = count_letters(text);
        float words = count_words(text);
        float sentences = count_sentences(text);
        float L = calculate_avg_letters(letters, 
    words);
        float S = calculate_avg_sentences(sentences, 
    words);
        int grade = calculate_grade_level(L, S);

        // print results
        if (grade < 1)
        {
            printf(\"Before Grade 1\\n\");
        }
        else if (grade >= 16)
        {
            printf(\"Grade 16+\\n\");
        }
        else
        {
            printf(\"Grade %i\\n\", grade);
        }




    }






    int calculate_grade_level(int L, int S)
    {

        int grade = (((0.0588 * L) - (0.296 * S)) - 
    15.8);
        return round(grade);

    }



    float count_letters(string paragraph)
    {
        int length = strlen(paragraph);
        float letters = 0;

        for (int i = 0; i < length; i++)
        {
            if (isalpha(paragraph[i]))
            letters++;
        }
        printf(\"%.1f letters\\n\", letters);
        return letters;

    }




    float count_words(string paragraph)
    {
        int length = strlen(paragraph);
        float words = 0;

        for (int i = 0; i < length; i++)
        {
            if (paragraph[i] == \' \')

                words++;

        }
        words = words + 1;
        printf(\"%.1f words\\n\", words);
        return words;
    }




    float count_sentences(string paragraph)
    {
        int length = strlen(paragraph);
        float sentences = 0;

        for (int i = 0; i < length; i++)
        {
            if (paragraph[i] == \'.\' || paragraph[i] 
    == \'!\' || paragraph[i] == \'?\')
            {
                sentences++;
            }
        }
        printf(\"%.1f sentences\\n\", sentences);
        return sentences;
    }



    float calculate_avg_letters(int letters, int 
    words)
    {
        float L = ((letters) / (words)) * 100;

        return L;
    }



    float calculate_avg_sentences(int sentences, int 
    words)
    {
        float S = ((sentences / words) * 100);
        return S;

    }
  • 欢迎来到堆栈溢出。请阅读How to Ask和minimal reproducible example,并尝试显示所有,但只有代码这是证明您所询问的具体问题所必需的。
  • 非常简单...除法是使用整数(截断)完成的,然后转换并存储为浮点数。尝试使用 `float L = (float)words/letters * 100.0;

标签: c cs50


【解决方案1】:

我已经尝试了一切(我认为),从更改数据类型、重新排列括号、使用两个单独的函数先执行除法然后乘以结果变量、更改前一个变量的数据类型。

您只需要使用正确的类型,考虑到每个变量需要存储什么以及需要如何使用,这种类型更有意义。

让我们考虑像这样的函数(和变量)

float letters = count_letters(text);

整数类型,比如说int,应该是你的首选,当涉及到数数某物。我会编写一个具有以下签名的函数

int count_letters(char const *paragraph);

// Then, in 'main'
int letters = count_letters(text);

现在,让我们考虑calculate_avg_letters

float calculate_avg_letters(int letters, int words)
{
    float L = ((letters) / (words)) * 100;
    //                  ^^^                That's an integral division.   
    return (L);
} 

这是一个常见的错误。给定操作的所有项都是int,执行的是整数除法,并且只有后结果将转换为float。

参见例如What is the behavior of integer division?

您需要做的只是将至少一个操作数显式转换为浮点数。

double average_per_100_words(int item, int words)
{
    return (double)item / words * 100;
    //                    ^^^^^   ^^^  Those will be implicitly converted to double
}

// Then, in 'main'
double L = average_per_100_words(letters, words);
double S = average_per_100_words(sentences, words);

话又说回来,calculate_grade_level 的原型和定义应该相应地改变。

int grade_level(double L, double S)
{ //            ^^^^^^    ^^^^^^                       Avoid truncation
    return round(((0.0588 * L) - (0.296 * S)) - 15.8);
}

【讨论】:

  • 这解决了它!感谢您提供深入的解释。真的帮助我更好地理解了这个过程。但是,cs50 检查程序给了我 8/11 的笑脸 -__- ...所以我在其他地方遇到了问题,但我会看看我是否可以在回来寻求帮助之前解决它。再次感谢您!
  • 我回来了。所以我现在已经把我的代码变成了 10/11 笑脸(几乎在那里)。最后剩下的问题似乎发生在年级水平的四舍五入和整数(双)处理上。有一个文本提示,预计是 7 级,但我的代码返回 8 级。在纸上做了一些非常快速且有些草率的四舍五入后,我注意到我收到的最终答案是 7.45(非常接近 7.5 ,并且我假设双打处理的额外小数点将其推到四舍五入到 8。有什么建议吗?
  • @jaudiola 好吧,如果 double 过于精确,您可以使用 float 返回,这可能是预期的类型。如果不知道失败测试的确切条件,就很难判断。
  • 找到了。这是我的一个愚蠢的错误。定义函数时忘记更改输入类型......错误:int calculate_grade_level(int L,int S)......正确:int calculate_grade_level(double L,double S)......以及在main之前声明时也是如此。傻我……哈哈
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-11-18
  • 1970-01-01
  • 1970-01-01
  • 2015-07-11
相关资源
最近更新 更多