实验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;
}
  • 运行测试截图

task1_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
运行测试截图

task1_2
共进行了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;
}
  • 运行测试截图

task2

  • 问题回答
问题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;
}
  • 运行测试截图

task3

实验任务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;
}
  • 运行测试截图

task4

实验任务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;
}
  • 运行测试截图

task5

实验任务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;
}

task6_1

task6_2

task6_4

  • 运行测试截图

五、实验总结

输入输出中格式符务必与数据类型相匹配

在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和解,本质上是对我们学习过程、发展过程的一种自我和解。

posted @ 2026-10-28 19:32  Exosister233  阅读(8)  评论(2)    收藏  举报