一开始,C 可能有点难以应付,但对于任何语言,尤其是 C,您只需将任务分解为尽可能小的部分,然后研究该语言提供哪些工具来完成您需要做的事情.正如 cmets 中正确提到的,您的任务基本上是从数据文件中读取值并计算每个月在您的温度范围内可用的飞行天数百分比。
这是否意味着这将是一个简单的任务——不——故意如此。这是一个很好的作业,可以让你学习 C 的基础知识、基本的文件 I/O、循环,以及基本的数组索引处理。当你的作业说:
查看需求和数据
数组不是必需的(输入文件的名称除外),但可以简化您的解决方案。
简化这个词应该跳出那个提示给你。为什么会给出这个提示?这是什么意思?与任何项目一样,您必须分析数据和需求,以确定如何解决问题以及您的选择是什么。仔细查看作业会告诉你,你的数据文件包含 2 年的数据,每天按行排列。这些要求希望您使用两年的数据来计算任何给定月份的总天数的良好飞行天数百分比,以得出您的百分比。
考虑选项
如果没有数组,您将如何处理它?如果您只是要将最佳百分比和最佳月份存储在局部变量中,则必须阅读整个文件来计算所涉及的每个月的百分比。这意味着您必须读取文件 12 次才能计算最大百分比、设置最佳月份并在所有 12 个月之间进行比较。
如果您使用数组,您将如何处理它?那么,您需要哪些信息来计算每个月的飞行天数百分比?该月的总天数,以及每个月的总飞行天数(在您的低温/高温范围内)。
通过实施思考
你知道只有 12 个月,所以如果你有一个包含 12 个元素的数组,那么它可以表示每个数组元素每个月可用的天数(0-11 - 但请注意:月份是编号的1-12 [1 月 - 12 月])。如果您在每个月保留另一个 12 元素的飞行天数数组,您可以根据存储在 2 个简单的 12 元素一维数组中的数据进行所有计算。最好的部分是您可以一次性通过数据文件填充两个数组。
您如何计算每个月在数组槽中的天数?好吧,如果您将所有数组元素初始化为0,您可以简单地为从文件中读取的每一天和飞行日的每个元素添加 1(您将该行的月份读取为每行中的第一个数字)所以您读取每一行(将月份读取为m),您可以为文件的每一行执行一些简单的操作,例如totaldays[m] = totaldays[m] + 1;(或只是totaldays[m]++;)。您可以使用简单的温度测试,如果您在该行中读取的温度介于您的低/高飞行温度之间,您可以类似地执行flyingdays[m]++;。读取整个文件一次后,两个数组都填满了,一个保存每个月的总天数,另一个保存每个月的总飞行天数。
(注意:同样,数组索引是0-11(12 个元素)而月份是1-12,所以你真的需要像totaldays[m-1]++; 和flyingdays[m-1]++; 这样的东西)
然后,为了完成您的计算,您可以使用像 for (m = 0; m < 12; m++) 这样的简单循环并计算每个月的飞行天数百分比,并保留 2 个简单变量(一个 maxpercent,另一个 bestmonth)在您对每个月进行计算后进行测试,以最终到达您首飞的最佳飞行月份。 (请记住,如果您循环使用 0-11,您的月份现在将是 m + 1 以存储在 bestmonth 等中。
最后(这应该始终是第一个,但在此解释中属于此处),您必须为每个变量选择type 的存储空间。现在,当您开始为变量选择存储空间types 时,这应该始终是您的想法,但您也可以随时对其进行微调。因此,如果您还不太熟悉它,请不要在一开始就过度关注它,只需使用int 或unsigned int 为整数值粗略输入您的类型,如果数据合适,并采取随着经验的增长,更仔细地审视它。
已经好了,怎么样?每次都采用相同的方式,根据需要存储的大小(或值范围)匹配存储。如果您的月份仅在1-12 之间,您真的需要整个unsigned int(范围为0 - 4294967295)来存储这些值吗?一个月可以是负数吗?如果不是,您为什么要使用签名的int 来保存该值? (有正当理由,只是不在这里)那么合适的最小unsigned type 是多少? unsigned char 保存的值范围为 0 - 255,所以肯定会这样做...
原型
既然您已经确定了您的程序要求,查看了数据的值,并考虑了您的代码需要执行的逻辑,那么终于该拿起键盘了。看看你想出的东西,你会发现应该类似于:
#include <stdio.h>
int main (void) {
/* declare & initialize variables */
/* (hint) */
unsigned char totaldays[12] = {0};
unsigned char flyingdays[12] = {0};
/* prompt for input of t_low/t_high and filename */
/* open file */
/* read totaldays and flyingdays into array */
/* (hint at an efficient way below) */
while (fscanf (fp, "%hhu %hhu %hu %f", &m, &d, &y, &t) == 4) {
}
/* close file */
/* loop though each month and compute percentage, test for max,
set best month, print totals statistics for that month */
/* (hint) */
for (m = 0; m < 12; m++) {
}
/* finally print best month for maiden flight */
return 0;
}
验证
完成代码并验证您的输出是否与low = 60 和high = 80 的作业中给出的解决方案相匹配。如果您遇到问题,请告诉我,我很乐意与您进一步合作。
更多解释
首先,(有点fscanf逻辑)对于您的读取循环,如果您查看数据文件,您可以读取月份m,日期d,年份y,然后是温度t 如果需要,可以转换为值。即声明如下:
unsigned char mbest, m, d, tl, th;
unsigned short y = 0;
float maxpct = 0.0, t = 0.0;
但是如果你仔细看看你需要做什么,你永远不会在任何计算中使用日期 d 或年份 y。 scanf 函数允许您读取和丢弃带有%*u 的值(其中u 可以是任何类型说明符,例如d 用于int,c 用于char 等)而无需这些添加到返回(或scanf 函数返回的成功匹配计数)。因此,不要声明和阅读 d 和 y,而是不用它们并使用:
unsigned char mbest, m, tl, th;
float maxpct = 0.0, t = 0.0;
...
while (fscanf (fp, "%hhu %*u %*u %f", &m, &t) == 2)
仅从每一行中提取m 和t 以获得2 的总回报(或匹配计数)。在此背景下,您的读取循环可能如下所示:
/* read all values from file, update both arrays
NOTE: array[0] holds month 1 data
adjust array index as needed */
while (fscanf (fp, "%hhu %*u %*u %f", &m, &t) == 2)
{
totaldays[m-1]++; /* increment number of days for month m */
if (tl <= t && t <= th)
flyingdays[m-1]++; /* increment flying days in month m */
}
注意,由于我们首先将数组值初始化为 zero,因此当我们增加任何给定月份的值(m-1 数组索引)时,我们只是将该月的计数加 1。
现在为您的计算循环。有了总天数和飞行天数,您现在可以逐步遍历数组并轻松计算每个月的百分比,类似于:
for (m = 0; m < 12; m++)
{
float pct = (float)flyingdays[m]/totaldays[m] * 100; /* compute percent */
if (pct > maxpct) { /* if greater than max, update max & mbest */
maxpct = pct;
mbest = m + 1;
}
printf ("Month %2hhu: %5.1f percent of days in range.\n", m + 1, pct);
}
注意:上面的printf 对齐输出比您的要求稍好。如果你想完全匹配你的分配输出,你可以使用:
printf ("Month %hhu: %.1f percent of days in range.\n", m + 1, pct);
现在,考虑到它可以工作,并且考虑到你已经花了一天的时间在它上面工作,我敢打赌你应该能够完成剩下的工作。如果没有,请发表另一条评论,我们会让您摆脱困境。
拼图的所有部分
有时,了解拼图的所有部分如何组合在一起确实很有帮助。在 C 语言中,几乎任何事情都有很多方法,所以这只是一种方法:
#include <stdio.h>
int main (void) {
/* declare & initialize variables */
char iname[31] = {0};
unsigned char totaldays[12] = {0};
unsigned char flyingdays[12] = {0};
unsigned char mbest, m, tl, th; /* types match size of data held */
float maxpct = 0.0, t = 0.0;
FILE *fp = NULL;
mbest = m = tl = th = 0;
/* prompt for input of t_low/t_high and filename */
printf ("Tell me about your dragon’s preferred temperature for flying:\n"
"What is the coldest temperature they can fly in?\n");
scanf ("%hhu", &tl);
printf ("What is the hottest temperature they can fly in?\n");
scanf ("%hhu", &th);
printf ("Please enter the name of the weather data file for Dragon Island.\n");
scanf (" %30[^\n]%*c", iname); /* limit name to 30 chars */
/* open file, or exit */
if (!(fp = fopen (iname, "r"))) {
fprintf (stderr, "error: file open failed '%s'.\n", iname);
return 1;
}
/* read totaldays and flyingdays into arrays
NOTE: array[0] holds month 1 data
adjust array index as needed */
while (fscanf (fp, "%hhu %*u %*u %f", &m, &t) == 2)
{
totaldays[m-1]++; /* increment number of days for month m */
if (tl <= t && t <= th)
flyingdays[m-1]++; /* increment flying days in month m */
}
/* close file */
fclose (fp);
/* loop though each month and compute percentage, test for max,
set best month, print totals statistics for that month */
for (m = 0; m < 12; m++)
{
/* compute percent */
float pct = (float)flyingdays[m]/totaldays[m] * 100;
if (pct > maxpct) { /* if greater than max, update max & mbest */
maxpct = pct;
mbest = m + 1;
}
printf ("Month %2hhu: %5.1f percent of days in range.\n", m + 1, pct);
}
/* finally print best month for maiden flight */
printf ("I recommend month %hhu for the Celebration of the First Flight!\n",
mbest);
return 0;
}
输出
$ ./bin/dragonflight
Tell me about your dragon’s preferred temperature for flying:
What is the coldest temperature they can fly in?
60
What is the hottest temperature they can fly in?
80
Please enter the name of the weather data file for Dragon Island.
island.txt
Month 1: 66.1 percent of days in range.
Month 2: 71.4 percent of days in range.
Month 3: 72.6 percent of days in range.
Month 4: 98.3 percent of days in range.
Month 5: 95.2 percent of days in range.
Month 6: 48.3 percent of days in range.
Month 7: 48.4 percent of days in range.
Month 8: 11.3 percent of days in range.
Month 9: 63.3 percent of days in range.
Month 10: 100.0 percent of days in range.
Month 11: 83.3 percent of days in range.
Month 12: 77.4 percent of days in range.
I recommend month 10 for the Celebration of the First Flight!
调试 - 最后一步
有多种方法可以调试您的程序。通常,当您关心值时,您可以简单地使用printf 转储中间值,或者使用像gdb 这样的调试器来查看值。出于此处的目的,让我们看一些值。关闭文件后只需添加几个循环和printf。例如:
fclose (fp);
for (m = 0; m < 12; m++)
printf (" totaldays[%2hhu] : %2hhu flyingdays[%2hhu] : %2hhu pct : %f\n",
m+1, totaldays[m], m+1, flyingdays[m],
(float)flyingdays[m]/totaldays[m] * 100);
输入验证时间:
temp low : 60
temp high : 80
当您查看每个数组中的中间值时,您应该会看到:
totaldays[ 1] : 62 flyingdays[ 1] : 41 pct : 66.129036
totaldays[ 2] : 56 flyingdays[ 2] : 40 pct : 71.428574
totaldays[ 3] : 62 flyingdays[ 3] : 45 pct : 72.580650
totaldays[ 4] : 60 flyingdays[ 4] : 59 pct : 98.333336
totaldays[ 5] : 62 flyingdays[ 5] : 59 pct : 95.161285
totaldays[ 6] : 60 flyingdays[ 6] : 29 pct : 48.333332
totaldays[ 7] : 62 flyingdays[ 7] : 30 pct : 48.387096
totaldays[ 8] : 62 flyingdays[ 8] : 7 pct : 11.290322
totaldays[ 9] : 60 flyingdays[ 9] : 38 pct : 63.333332
totaldays[10] : 62 flyingdays[10] : 62 pct : 100.000000
totaldays[11] : 60 flyingdays[11] : 50 pct : 83.333328
totaldays[12] : 62 flyingdays[12] : 48 pct : 77.419350
看看你有什么,然后告诉我。