C博客作业03--函数

| 这个作业属于哪个班级 | C语言--网络2011/2012 |
| ---- | ---- | ---- |
| 这个作业的地址 | C博客作业03--函数 |
| 这个作业的目标 | 学习如何设计函数、C语言基本数据类型
| 名字 | 黎钊涵

展示PTA总分

本章学习总结

1.1 函数

在C语言中,函数与编程是密切相关的,比如平常用到的printf、scanf,其实都是函数,他们是已经被编辑好的函数,放在了头文件中,如果我们想使用一个函数,就需要给它定义和声明,才能调用,使用函数可以使代码更加简洁规范,增强可读性,便于读者理解

1.1.1 定义

一个函数的定义其实需要三部分内容:函数返回值类型、函数名称、函数参数

  • 函数名称

函数名实际上就是一个标识符,以字母或_(下划线)开始,后接任意数量的字母或数字或_(下划线)的组合,例如:lzhdsg 而不能表示为 lzh-dsg

  • 函数返回值

函数的返回值则与函数所定义的类型密切相关,一般来说,函数返回的类型就是函数定义的类型,比如我们定义了一个函数类型为int,则它的返回值类型也为int,而如果定义函数类型为void,则此函数没有返回值

  • 函数参数

函数参数分为实参和形参,实参就是拥有数据、实际上传输数据的参数,而形参就是没有实际数据要等待接受数据的参数;当我们调用之前所定义、声明的函数时,此函数传入的参数和函数体内接收到的参数其实并不是同一个变量,它们的值有可能相等,也可能不相等,如果对形参做出一个动作指令,实参可能不受影响;同时实参可以是常量、变量、表达式、函数等,形参与实参相对应,形参只能位于函数内部,它是在被调用时分配内存,一旦调用结束就立刻释放内存;除此之外,函数中的数据传递方向是单向的,只能由实参传递给形参,而不能把形参的值反向地传递给实参,也正因此,我们才说实参不因为形参的改变而改变,在函数调用过程中,形参的值发生改变并不会影响实参

一般定义形式:

函数类型  函数名(形参)
{
   函数体
}

1.1.2 声明

在调用某函数前应该对被调用函数进行声明,类似于使用变量前对变量进行说明,声明目的是使编译器系统知道被调函数返回值的类型,从而按照此类型做出相应的处理

一般在文件头声明

#include <stdio.h>

int MAX(int x, int y);
int MIN(int x, int y);

...

也可以在函数头声明

#include <stdio.h>

int main(void)
{
    int a = 2;
    int b = 5;

    int MAX(int x, int y);
    int MIN(int x, int y);

    ...

1.1.3 调用

声明之后,可以在需要的位置对函数进行调用

...
 printf("%d\n", MAX(a,b));
 printf("%d\n", MIN(a,b)); 
...

1.1.4 代码总览

int function( int x, int y );//函数声明
int main()
{
m=function(j);
}//函数调用
int function( int x, int y )//函数定义
{
...
return a;//返回a的值给function,若函数头为void则无返回
}

1.1.5 小知识点

在以下几种情况时可以省去对被调函数的函数说明(https://zhuanlan.zhihu.com/p/94377668)

  • 如果被调函数的返回值是整型或字符型时,可以不对被调函数作说明,而直接调用。这时系统将自动对被调函数返回值按整型处理

  • 当被调函数的函数定义出现在主调函数之前时,在主调函数中也可以不对被调函数再作说明而直接调用

  • 如在所有函数定义之前,在函数外预先说明了各个函数的类型,则在以后的各主调函数中,可不再对被调函数作说明。

  • 对库函数的调用不需要再作说明,但必须把该函数的头文件用include命令包含在源文件前部

1.2 全局变量、局部变量、静态局部变量

1.2.1 全局变量

  • 全局变量:定义在函数外而不属于任何函数的变量,生存周期贯穿整个程序执行过程

  • 存在意义:解决多个函数间的变量共用,它对作用范围内的所有函数都起作用

  • 作用范围:从定义开始到程序所在的文件结束

  • 定义位置:程序头部,两函数中间或程序尾部,只要在函数外部即可,一般位于程序的最前面,即第一个函数的前面

  • 例:

#include<stdio.h>

int x;                     //定义全局变量x

int f();

int main(void)
{
  int a = 1;
  x = a;                   //对全局变量x赋值
  a = f();                 //a的值为4
  {
     int b = 2;
     b = a + b;            //b的值为6
     x = x + b;            //全局变量运算
  }
  printf("%d %d", a, x);
  return 0;
}

int f()
{
  int x = 4;               //x为局部变量,在本函数中,全局变量x不起作用
  return x;
}

1.2.2 局部变量

  • 局部变量:定义在函数内部的变量,随着函数调用的结束而被系统回收

  • 存在意义:避免各个函数之间的变量相互干扰,便利结构化程序设计

  • 作用范围:所在函数内部

  • 定义位置:一般位于函数或复合语句的开始处,标准C规定不能定义在中间位置

  • 例:

int main(void)
{
 int a = i;          //主函数的局部变量
  {                  //复合语句开始
    int b = 2;       //复合语句内的局部变量
    ...
  }                  //复合语句结束
 printf("%d", a);
 return 0;
}

1.2.3 静态局部变量

  • 静态局部变量:一种特殊的局部变量,存放在静态存储区,不会像普通函数一样因为函数调用的结束而被系统回收,它的生存周期和全局变量一样,会持续到程序结束, 如果定义没有赋初值,系统将自动赋0,若赋初值也只在第一次调用时起作用,从第二次调用开始,都按前一次调用保留的值使用

  • 存在意义:拥有能力与局部变量相同,生存周期与全局变量相同,有点二者取优结合的意思

  • 作用范围:只能用于所定义函数,不能用于其他函数(包括主函数)

  • 定义格式:static 类型名 变量名

  • 例:

...
static double f = 1;    //定义静态变量,第一次赋值为1
f = f * n;              //上一次调用的值再乘n
...

1.3 C数据类型及注意点

注意数据类型以及取值范围

1.3.1 整型变量

  • int类型
    取值范围(16位):-32768~32767(-2^15— 2^15-1)
    转换说明:%d

  • short类型
    取值范围(16位):-32768~32767(-2^15— 2^15-1)
    转换说明:%d

  • long类型
    取值范围(16位):取值范围(16位)-2147483648~2147483648(-2^31— 2^31-1)
    转换说明:%ld

1.3.2 浮点型变量

  • 单精度float
    取值范围:10^-37 —10^37
    转换说明:%f

  • 双精度double
    取值范围:(2^63— 2^63-1)
    转换说明:%f

1.4 C运算符

  • 逻辑运算符

    • “与” :“&&”
    • “或”:“||”
  • 关系运算符

    • “等于”:==
    • “小于”;<
    • “大于”;>
    • “小等于”:<=
    • “大等于”;>=
    • “不等于”;!=

注意“等于”是“==”不是“=”,“=”为赋值,将右边的值赋给左边

  • 算术运算符

    • 加:+
    • 减:-
    • 乘:*
    • 除:/
    • 取余:%
    • 自加:++
    • 自减:--

注意“乘”是“*”不是“×”

综合作业(6分):小学生口算表达式自动生成系统

2.1.模块流程图



2.2.函数功能及全局变量介绍

2.2.1.全局变量

int GatValue1();//生成一位随机数
int GatValue2();//生成两位随机数
char GetSymbol();//生成二则运算符
char GetSymbo2();//生成四则运算符
void Expression(int num1, char op, int num2);//生成随机表达式
void Rewards();//奖励小朋友的话
void Encouragements();//鼓励小朋友的话

2.2.2 菜单相关函数

void OperateMenu();//游戏操作界面
void GradeOneMenu();//一年级
void GradeTwoMenu();//二年级
void GradeThreeMenu();//三年级
  • 主菜单
int main(void)
{
	OperateMenu();//游戏操作界面	
	return 0;
}
void OperateMenu()//游戏操作界面
{
	char option;
	int temp;
	system("cls");//清屏

	do
	{
		system("cls");
		printf("******************************************\n");
		printf("1.一年级口算\n");
		printf("2.二年级口算\n");
		printf("3.三年级口算\n");
		printf("4.退出系统\n");
		printf("******************************************\n");
		printf("请输入您的选择:");
		scanf(" %c", &option);
		switch (option)
		{
		case '1':
			system("cls");
			GradeOneMenu();//一年级函数调用
			break;
		case '2':
			system("cls");
			 GradeTwoMenu();//二年级函数调用
			break;
		case '3':
			system("cls");
			GradeTwoMenu();//三年级函数调用
			break;
		case '4':
			printf("\n谢谢您的参与!\n");
			Sleep(500);
			exit(0);
		default:
			printf("您输入不对,只能输入1,2,3,4,请重输!\n");
			Sleep(500);
		}
	} while (!(option >= '1' && option <= '4'));
}
  • 一年级操作系统
void GradeOneMenu()//一年级
{

	while (1)
	{
		system("cls");//清屏
		printf("*********************一年级小朋友好!********************************\n");
		printf("系统将随机生成一个口算式,如果您会做,则输入y,输入结果。\n");
		printf("**如果您不想做,输入n退回主菜单。\n");
		printf("***************************************************************\n");

		/*1.生成操作数函数*/
		int num1, num2;
		srand(time(0));
		num1 = GatValue1();
		num2 = GatValue1();
	
		/*2.生成随机运算符函数*/
		char op;
		op = GetSymbol();
		/*3.根据年级判断生成的表达式是否合理的函数(选做)*/
		int temp;
		if (op == '-' && num1 < num2)
		{
			temp = num1;
			num1 = num2;
			num2 = temp;
		}
		/*4.生成表达式函数,并输出展示*/

		Expression(num1, op, num2);
		printf("是否继续答题\n");
		char ch = 0;
		scanf("\n%c", &ch);
		if (ch == 'y')//选择答题
		{
			/*答题模块*/
			int yourNumber, result;
			int right = 0, wrong = 0;
			int count = 0;
			switch (op)
			{
			case'+':result = num1 + num2;
				break;
			case'-':result = num1 - num2;
				break;
			}
			printf("请你输出你滴回答哟:");
			scanf("%d", &yourNumber);
			if (yourNumber == result)
			{
				Rewards();
				right++;
			}
			else
			{
				Encouragements();
				printf("正确答案是:\n");
				printf("%d", result);
				wrong++;
			}
			count++;
			printf("是否继续答题\n");
			scanf("\n%c", &ch);
			if (ch == 'n')
			{
				printf("小朋友你的成绩为:答对题数:%d 答错题数:%d 共答题数:%d ", right, wrong, count);
				right = 0;
				wrong = 0;
				count = 0;
			}

		}
		else
			OperateMenu();//返回主菜单
	}
	return;
}
  • 二年级操作系统
void GradeTwoMenu()//二年级
{
	
	while (2)
	{
		char op=0;
		system("cls");//清屏
		printf("*********************二年级小朋友好!********************************\n");
		printf("系统将随机生成一个口算式,如果您会做,则输入y,输入结果。\n");
		printf("**如果您不想做,输入n退回主菜单。\n");
		printf("***************************************************************\n");


		/*生成随机操作数*/
		int num1, num2;
		srand(time(0));
		num1 = GatValue2();
		num2 = GatValue2();
		
        op= GetSymbol();//生成二则运算符
		

		/*3.根据年级判断生成的表达式是否合理的函数(选做)*/
		int temp;
		
		if (op == '-' && num1 < num2)
		{
			temp = num1;
			num1 = num2;
			num2 = temp;
		}
		/*4.生成表达式函数,并输出展示*/
		Expression(num1, op, num2);
		printf("是否继续答题\n");
		char ch = 0;
		scanf("\n%c", &ch);
		if (ch == 'y')//选择答题
		{
			/*答题模块*/
			int yourNumber, result;
			int right = 0, wrong = 0;
			int count = 0;
			switch (op)
			{
			case'+':result = num1 + num2;
				break;
			case'-':result = num1 - num2;
				break;
			}
			printf("请你输出你滴回答哟:");
			scanf("%d", &yourNumber);
			if (yourNumber == result)
			{
				Rewards();
				right++;
			}
			else
			{
				Encouragements();
				printf("正确答案是:\n");
				printf("%d", result);
				wrong++;
			}
			count++;
			printf("是否继续答题\n");
			scanf("\n%c", &ch);
			if (ch == 'n')
			{
				printf("小朋友你的成绩为:答对题数:%d 答错题数:%d 共答题数:%d ", right, wrong, count);
				right = 0;
				wrong = 0;
				count = 0;
				Sleep(800);

			}

		}
		else
			OperateMenu();//返回主菜单
	}
	return;
}
  • 三年级操作系统
void GradeThreeMenu()//三年级
{
	char op;
	int num1;
	int num2;
	int N;
	int temp;
	while (3)
	{
		system("cls");//清屏
		printf("*********************三年级小朋友好!********************************\n");
		printf("系统将随机生成一个口算式,如果您会做,则输入y,输入结果。\n");
		printf("**如果您不想做,输入n退回主菜单。\n");
		printf("***************************************************************\n");


		/*2.生成随机运算符函数*/
		op = GetSymbo2();
		/*1.生成操作数函数*/
		if (op == '*' || op == '/')//三年级小朋友需要1位数乘2位数,2位数除以1位数
		{
			num1 = GatValue2();
			num2 = GatValue1();
			N = num1 * num2;
		}
		else
		{
			num1 = GatValue2();
			num2 = GatValue2();
		}

		/*3.根据年级判断生成的表达式是否合理的函数(选做)*/
		if (op == '-' && num1 < num2)
		{
			temp = num1;
			num1 = num2;
			num2 = temp;
		}

		/*4.生成表达式函数,并输出展示*/
		Expression(num1, op, num2);
		printf("是否继续答题\n");
		char ch = 0;
		scanf("\n%c", &ch);
		if (ch == 'y')//选择答题
		{
			/*答题模块*/
			int yourNumber, result;
			int right = 0, wrong = 0;
			int count = 0;
			switch (op)
			{
			case'+':result = num1 + num2;
				break;
			case'-':result = num1 - num2;
				break;
			case'*':result = num1 * num2;
				break;
			case'/':result = num1 / num2;
				break;
			}
			printf("请你输出你滴回答哟:");
			scanf("%d", &yourNumber);
			if (yourNumber == result)
			{
				Rewards();
				right++;
			}
			else
			{
				Encouragements();
				printf("正确答案是:\n");
				printf("%d", result);
				wrong++;
			}
			count++;
			printf("是否继续答题\n");
			scanf("\n%c", &ch);
			if (ch == 'n')
			{
				printf("小朋友你的成绩为:答对题数:%d 答错题数:%d 共答题数:%d ", right, wrong, count);
				right = 0;
				wrong = 0;
				count = 0;
				Sleep(800);

			}

		}
		else
			OperateMenu();//返回主菜单
	}
	return;
}

2.2.2 出题相关函数

int GatValue1()//随机生成一个操作数
{
	int num;
	num = 1 + rand() % 9;//一年级1到10

	return num;
}
int GatValue2()//随机生成2个操作数
{
	int num;
	num = 1 + rand() % 100;//一年级1到100
	return num;
}


char GetSymbol()//生成二则运算符
{
	char op;
	int num;
	srand(time(0));
	num = rand() % 2;
	switch (num)
	{
	case 0:op = '+';
		break;
	case 1:op = '-';
		break;
	}
	return op;
}
char GetSymbo2()//生成四则运算符
{
	char op=0;
	int num;
	switch (num)
	{
	case 0:op = '+';
		break;
	case 1:op = '-';
		break;
	case 2:op = '*';
		break;
	case 3:op = '/';
		break;
	}
	return op;
}


void Expression(int num1, char op, int num2)//生成随机表达式
{
	printf("%d %c %d =\n", num1, op, num2);
}
void Rewards()//奖励小朋友的话
{
	int a;
	srand(time(0));//随机种子
	a = 1 + rand() % 3;
	switch (a)
	{
	case 1:printf("对啦!太棒了小朋友!\n");
		break;
	case 2:printf("哇哦!又对了!\n");
		break;
	case 3:printf("对了对了又对了!\n");
		break;
	case 4:printf("厉害了小朋友!\n");
		break;
	}
	printf("\n");
}
void Encouragements()//鼓励小朋友的话
{
	int a;
	srand(time(0));//随机种子
	a = 1 + rand() % 3;
	switch (a)
	{
	case 1:printf("没关系的\n");
		break;
	case 2:printf("哎呀又错啦!没关系我们再来一次!\n");
		break;
	case 3:printf("失败是成功之母,再来!\n");
		break;
	case 4:printf("没事没事继续加油哦!\n");
		break;
	}
	printf("\n");
}

2.3.运行结果截图,测试用例。

  • 以一年级为例

一年级界面

回答正确

回答错误

统计答题情况

2.4.大作业中编程技巧总结

2.4.1 随机数生成

2.4.2 延迟界面

知道了可以用Sleep(数字)来延迟界面,括号内数字为延迟的时间

例:

这样待会儿统计答题情况的时候就能延缓,让小朋友有充分的时间看清并记录自己的答题情况

2.4.3 感悟思考

  • 首先,大作业本身是一道综合性很强的题目,看似简单的小学生运算系统设计,其中却掺杂着大量的程序设计知识以及现实生活知识。就程序设计而言,哪里需要设计函数,需要设计几个函数,如何正确设计函数,函数内又需要设计什么内容,如何定义变量,如何通过变量正确表达各种值和话语,种种问题都需要我们进行冷静地思考,深入的分析,理性地探究,大胆地实践,方能找到解决问题的方法;就现实生活而言,一年级的小学生学习范围是哪里,二年级三年级又分别覆盖了什么知识,是否还像我们小时候那样,哪些知识点有出现较大增删减改,题目难度又如何把控,究竟是“一视同仁”,难度确定,做完即止,还是“因人而异”,可以主动提升难度,体现区分度,这些问题其实都需要考虑进去,因为这道题目是一道现实应用题,与现实生活有密切联系,我们必须基于生活实际进行程序设计,这样设计出的程序才能更好地与现实接轨,应用于现实生活。

  • 其次,在编程过程中,我发现了很多问题,先说程序设计,比如对于随机数部分的设计,我发现我对于随机数的理解还很浅,并没有真正掌握它的用法,或许只是懂得有这么一个东西叫做随机数,但是到底是什么、怎么用就模糊不清;再比如对于操作系统设计的不理解,一开始特别蒙,完全不知道从哪里下手,还记得实验课的时候,老师提醒了两次,我依然一头雾水,真是丈二和尚摸不着头脑,好在最后终于敲下了熟悉的#include<stdio.h>,也算是从0到1的第一步正式迈出,这门课就是这样,一定要大胆实践,空想没有用,想不出来就先试试看,试试看说不定就出来了;再说现实生活,我一开始压根就没考虑到这一层面,根本没有这个意识,所以在课堂上老师提出的时候我一下子还没反应过来:what?还要考虑这个?转念一想,对啊,这是个现实问题啊,当然需要!今后考虑问题也会更多地从实际出发,从现实出发,充分考虑到各种现实因素对程序的影响,再进行程序设计。

  • 再者,对于C语言这门学科,我又有了新的理解。感觉它跟数学挺像的,逻辑性很强,前面是什么、后面是什么都很有条理,并且非常注重细节,别说一行代码、一个单词,哪怕是一个符号也不能错,我这次又出现了许多次的编译错误、格式错误,真是非常头疼,却也无可奈何,只能细心检查、耐心纠错,除此之外别无他法;它也和英语很像,注重语法,强调定义,不说种类繁多的命名法,单论各种变量的定义格式、各种函数的使用法则,都需要熟记于心,做到胸有成竹。死记硬背肯定不行,需要自己多实践多动手敲代码,自然能记熟、记牢。现在回过头再看老师常说的那句“代码量不够”,似乎不再是那么平淡,很多问题的根本原因就真的是代码量不够,因为代码量不够,所以会出现各种低级错误;因为代码量不够,所以遇到新的问题不懂如何设计程序;因为代码量不够,所以对C语言不熟,看不到问题本质,换个面就以为它是新的头,再费大量功夫死研究,到头来也没研究出个所以来。

  • 最后,再接再厉吧,现在已经感受到在这门学科上自己存在的诸多不足了, 但也逐渐摸清了C语言的学习正确学习方法,继续努力即可。它比想象中更难,也比想象中更简单。

posted @ 2020-11-30 22:22  走去干饭  阅读(158)  评论(0编辑  收藏  举报