实验2
四、实验结论
实验任务1
- 源代码task1.c
//task1 随机学员编号
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define N 100
#define CNT 5
int main()
{
int number;
int i;
srand(time(0));
for(i = 0 ; i<CNT ; i++)
{
number = rand() % 100 + 1;//line14
printf("20490042%04d\n",number);//line15
}
return 0;
}
- 运行测试截图

- 问题回答
问题1
程序的功能是通过伪随机生成CNT个(此时是5个)以“20490042”开头的,以“0001”到“0100”结尾的16位学生编号。
问题2
line14(在我提交的源代码中为line18)的代码功能是为number赋值:其中先通过rand()函数,依靠前面用当前时间设置的种子,生成一个随机数,然后做取余100后加1操作,使得number数值在1~100之间(包括两端)。
问题3
line15(在我提交的源代码中为line19)中 %04d 的作用是告诉printf()以整数形式输出number(%d),且让它在排版上占据4个位置(4),其中左侧空缺使用 0 来填充(0)。
问题4
运行测试截图

共进行了5次测试运行,其中第1、5次保留了srand(time(0));代码,2、3、4次注释了这行代码
分析
比较第1、5次测试运行可以发现,有srand(time(0));存在时,程序输出了不同的学号;比较第2、3、4次测试运行可以发现,没有srand(time(0));存在时,程序输出了完全相同的学号;比较第1次到2、3、4次再到第5次全过程,该代码从保留到注释再到保留,正好对应了产生随机数的不同——>相同——>不同。
结论
由分析可知,srand(time(0))决定了产生的随机数,该代码存在时,随机数由当前系统时间决定;该代码不存在时;产生的随机数是相同的,不同次的运行生成不再变化的数据。
补充
经过补充了解,srand()用于设置随机数种子,time(0)表示当前系统时间,默认情况下rand()相当于使用srand(1),所以不配套使用srand()函数的情况下,rand()将在不同批次的运行中输出相同随机数。
实验任务2
- 源代码task2.c
//task2 自动贩卖机
#include <stdio.h>
int main()
{
int choice,quantity;
float total_price = 0, amount_paid, change;
while(1)
{
printf("\n自动饮料售卖机菜单:\n");
printf("1. 可乐 - 3 元/瓶\n");
printf("2. 雪碧 - 3 元/瓶\n");
printf("3. 橙汁 - 5 元/瓶\n");
printf("4. 矿泉水 - 2 元/瓶\n");
printf("0. 退出购买流程\n");
printf("请输入饮料编号: ");
scanf("%d", &choice);
if(choice == 0)
break;
if(choice < 1 || choice > 4)
{
printf("无效的饮料编号,请重新输入。\n");
continue;//问题2
}
printf("请输入购买的数量: ");
scanf("%d", &quantity);
if(quantity < 0)
{
printf("购买数量不能为负数,请重新输入。\n");
continue;//问题2
}
if(choice == 1 || choice == 2)
total_price += 3 * quantity;
else if(choice == 3)
total_price += 5 * quantity;
else
total_price += 2 * quantity;
printf("请输入金额: ");
scanf("%f", &amount_paid);
change = amount_paid - total_price;
printf("本次购买总价: %.2f 元\n", total_price);
printf("找零: %.2f 元\n", change);
total_price = 0;//line47
}
printf("感谢您的购买,欢迎下次光临!\n");
return 0;
}
- 运行测试截图

- 问题回答
问题1
line47(在我提交的源代码中为line52)的total_price = 0;如果去掉,将导致同一次运行中的多次循环中总花费累加(示范代码的line33至line38,提交代码的line38至line43每次都采用将total_price原始值加上本次总花费),使每次计算出来的total_price都是前面每次循环计算值的总和。
补充
既然使用累加策略会导致total_price每次循环后都需要重置为0,为什么定义时不能不给予初始值,而在计算时使用=(赋值)而非+=(初始值加上本次总花费)?我想应该是可以的,我目前倾向于这种写法。
问题2
在while循环中使用continue,语义是跳过while循环中本轮continue之后的操作,跳到while循环本轮结束时;所以,在循环中使用continue,语义是跳过循环中这一轮的后续操作,跳到循环的本轮结束时。
实验任务3
- 源代码task3.c
//task3 红绿灯模拟
#include <stdio.h>
int main()
{
char colour;
for(int i=0 ; i<4 ; i++)
{
scanf("%c", &colour);
getchar();
switch( colour )
{
case 'r':printf("stop!\n");break;
case 'g':printf("go go go\n");break;
case 'y':printf("wait a minute\n");break;
default:printf("something must be wrong...\n");
}
}
return 0;
}
- 运行测试截图

实验任务4
- 源代码task4.c
//task4 模拟记账
#include <stdio.h>
int main()
{
double sum = 0, max = 0, min = 20000;
double data;
printf("输入今日开销,直到输入-1终止:\n");
while(1)
{
scanf("%lf", &data);
if(data == -1)
break;
if(data > max)
max = data;
if(data < min)
min = data;
sum = sum + data;
}
printf("今日累计消费总额: %.1f\n", sum);
printf("今日最高一笔开销: %.1f\n", max);
printf("今日最低一笔开销: %.1f\n", min);
return 0;
}
- 运行测试截图

实验任务5
- 源代码task5.c
//task5 三角形判断PLUS
#include <stdio.h>
int main()
{
int a, b, c;
for(int i=0 ; i<5 ; i++)
{
scanf("%d%d%d", &a, &b, &c);
if( a>=b+c || b>=a+c || c>=a+b)
{
printf("不能构成三角形\n");
continue;
}
if( a*a == b*b+c*c || b*b == a*a+c*c || c*c == b*b+a*a )
{
printf("直角三角形\n");
continue;
}
else if( a==b || b==c)
{
printf("等边三角形\n");
continue;
}
else if( a==b || b==c || a==c )
{
printf("等腰三角形\n");
continue;
}
else
printf("普通三角形\n");
}
return 0;
}
- 运行测试截图

实验任务6
- 源代码task6.c
//task6 随机幸运日
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main()
{
int lucky_day, ans;
int ifr = 0;
srand(time(0));//为rand()设置种子,为当前时间
lucky_day = rand() % 30 + 1;//调用rand(),生成11月中的某个日期(1~30)
printf("猜猜2026年11月哪一天是你的lucky day\n");
for(int i=0 ; i<3 ; i++)
{
if( !i )
printf("\n开始喽,你又三次机会,猜吧(1~30): ");
else
printf("\n再猜(1~30): ");
scanf("%d", &ans);
if( ans == lucky_day )
{
ifr = 1;
break;
}
if( ans < lucky_day )
printf("\n你猜的日期早了,你的lucky day还没到呢\n");
else
printf("\n你猜的日期晚了,你的lucky day在前面哦\n");
}
if( ifr )
printf("\n哇,猜中了:)\n");
else
printf("\n次数用光啦。11月你的lucky day是%d号\n", lucky_day);
return 0;
}



- 运行测试截图
五、实验总结
输入输出中格式符务必与数据类型相匹配
在scanf中使用 %f 或 %lf 这类浮点格式符时,变量类型必须与格式符匹配,如果在定义时使用int会造成错误输出(例如在task2中怎么输入结果都是0.00,这是scanf和printf同时产生的问题);
以此类推,在 scanf 中输入浮点型变量时,格式符必须和变量类型严格匹配(double 必须用 %lf。float 用 %f),否则会造成读取错误(例如task4中输入浮点数后程序会卡死,double 用了 %d 后输入失败,残留字符导致 while(1) 死循环)。
由for(int i=0 ; i<n ; i++)引发的小巧思:区分第一次迭代与后续迭代
在task6中,第一次输入提示词与猜错后要求再输入的提示词不同,给我在代码简洁性上提出了挑战。我的计划是在不增加赋值语句的情况下靠判断实现它。本来,我想到自己已经使用了一个ifr变量用于监测用户是否在3次(或3次以内)循环中猜到正确答案,准备用ifr来同时表示是否为第一次,但发现行不通。此时我转念想到了用于循环计数的变量i。因为曾经受过的教学影响,我习惯于将i、j这类循环时的临时变量从0开始赋值。
因为if()后语句执行的条件是“括号()内为真值”,第一次循环时i的值为0,0前加上!正好表示真值,此后循环中i恒为正整数,此时i前加上!正好表示假值,这天然的区分了第一次迭代与后续迭代。于是有了task6源代码中的line19至line23,通过i的值表示真假,区分第一次迭代与后续迭代。
在写总结时需要与AI达成和解
此前,我一直认为AI在学习代码的过程中担任的只有“帮你写”和“查资料”两种功能,前者在学习场景下基本被认为应少用,后者则相对能安全地提升学习效率。然而今天写这篇作业时,我将自己写下的“推理”“结论”“补充”和“实验总结”都交给AI进行检查校对,此时发生了令人尴尬的情况:AI在尝试纠正我每一处表述不规范。
一方面,我希望保留自己实践推理出来的结论;另一方面,我也希望自己不要将一个极其不规范的、误导性的答案提交上来。我认为这是摸索式的工科学习模式与工科理论严谨性的依次冲突。处理不好,AI就会像一个极其苛刻的朋友,反反复复地强调、否决你改了数次的答案,并给你它得到的唯一正确解。我认为这是令人受打击、沮丧的。
但最后我得强调,我并不认为这种探索模式与严守定理这一准则是冲突的。首先,以往没有AI的时代,一代代人探索着学习工科,他们也有自己阶段性的感悟总结,不一定完全正确,但代表着他们学到了一些东西,甚至在未来也能被纠正;其次,如果我们能在探索时、实践时就将一个函数、一个算法的运行逻辑学的相对透彻些,将专有名词理解、将特殊情况考虑到,那么我们写出来的结论也能更倾向于正确,而AI也并非完全死板,它允许“不标准的正确”,这不标准之处正是人的自由;最后,我想说,源代码也好、推导出的结论也罢,人将它交给AI定夺,本质是一种害怕出错,更本质是一种不自信。我们或许可以相信一点自己的学习发展潜力、也可以不要恪守完美主义,与AI和解,本质上是对我们学习过程、发展过程的一种自我和解。

浙公网安备 33010602011771号