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语言的学习正确学习方法,继续努力即可。它比想象中更难,也比想象中更简单。