C语言博客作业——函数
一、PTA实验作业
题目1:6-6 使用函数输出水仙花数
1.本题PTA提交列表


2. 设计思路
int narcissistic( int number ) //函数定义
- 1.定义整数型变量a.i分别来存放number分离的出来的数和进行digit次幂运算的循环次数
- 2.定义x=number,b=1,c=number,sum=0,定义整数型变量digit来存放位数
- 3.利用循环求出数的位数 for(digit=1;;digit++){ x=x/10;if(x==0){break;}}
- 4.a=c%10 把c即number的数一个个分离出来存放在a
- 5.利用for循环,把分离出来的数a进行digit次幂运算后存放在b
- 6.sum=sum+b;求每个位上的数字的digit次幂之和
- 7.c=c/10 把分离出来的数去掉
- 8.b=1 清空b的值继续进入下一次循环求a的digit次幂运算结果
- 9.重复步骤4,直到c=0
- 10.判断sum与number的关系:相等返回1,不相等返回0
void PrintN( int m, int n ) //函数定义
- 1.定义整数型变量i来存放循环次数
- 2.for(i=m+1;i<=n-1;i++){ //列出开区间(m,n)里所有数
 if(narcissistic(i)){ //调用上一个函数,如果满足水仙花数
 printf("%d\n",i); //输出水仙花数i
 }
 }
3.本题调试过程碰到问题及PTA提交列表情况说明。
- 
1.一开始就遇到 ![]() 
 原来题目所给的代码并没有调用#include ''math.h''
 于是利用for循环进行重复累积,并且提出疑问:是否可以 在函数定义中再调用#include''math.h'' 答案是:不可以
- 
2.进行调试后发现没有进入循环,后监视变量发现忘记给c赋初值了....(可怕的老毛病) 
 ![]() 
- 
3.为了提高运行效率而有意减少未知数的定义导致number的值被改变而影响后续的比较 
 ![]() 
 ![]() 
- 
解决方法:定义一个数c附上number的值然后对c进行分离而不去改变number的值,避免对后续工作造成影响 
- 
4.发现多输出一个本身的数 
 ![]() 
- 
解决方法:回过头来审题发现是 开区间 于是 ![]() 
- 
5.终于运行出与样例一样的答案,但是....果然pta不是吃素的... 
 ![]() 
- 
解决方法:根据pta的提示 
- 
(1)增加一个条件 ![]() 
 ,但是输出![]() 
 即: 在不返回的函数里不可以return 任何东西
- 
(2)最大区间答案错误:在输入较大数后发现只输出3位数字的数字,但是误以为四位数并没有水仙花数,一筹莫展之下去询问了同学后发现 
 自己审题上的错误,并不是所有数都是各个位数的三次方而是 digit次幂之和
- 
6.遇到下面这句陌生的话不要着急,解决的方法非常简单:关闭黑框框即可 
 ![]() 
题目2:6-7 使用函数输出指定范围内的完数
1.本题PTA提交列表



2. 设计思路
int factorsum(int number) //函数定义
- 1.定义整数型变量i和sum分别来存放循环次数和所有因子和
- 2.利用for (i = 2; i<number; i++) {      //寻找number的因子
 if (number%i == 0) {
 sum += i; //所有因子相加
 }
 }
- 3.返回sum的值
函数定义 void PrintPN(int m, int n)
- 1.定义整数型变量i,j分别来存放循环次数和所有可能的因子,定义flag=0存放没有完数的情况,flag=1存放有完数的情况,并给flag赋初值=0
- 2.利用for (i = m; i <= n; i++) 列出(m,n)内所有数
- 3.调用函数判断i是否为完数: if (factorsum(i) == i) //若因子相加等于本身,即符合完数
- 4.若是,则flag=1,并输出表达式的前一小部分表达式 : printf("%d = 1", i);
- 5.利用for (j = 2; j<i; j++) {       //寻找number的因子
 if (i%j == 0) {
 printf(" + %d", j); //输出表达式后部分因子相加的式子
 }
- 6.完成一个完数的表达式后换行
- 7.判断flag是否为0,如是,则输出 No perfect number
3.本题调试过程碰到问题及PTA提交列表情况说明。
- 1.定义两个函数时,可以先确定一个函数无误后注释掉再去调试另一个函数
- 2.根据自己的思路写好代码后输出发现严重错误:![]() 
 啥呀这是.....滚去调试
 ![]() 
 ![]() 
 发现i=6,j=5 然后result竟然=1进入循环.... 难道是整数/整数=整数的问题?然而并不是,吃了那么多次亏当然已经变成i*1.0/j了.....
 可是result凭啥等于1啊...重新观察result,发现我竟然给result定义成整数型...得出小经验:如果结果应该为小数但是却输出整数有两种情况:
 (1)整数/整数=整数 (2)一开始就给结果定义成整数呀
- 解决方法:显然把int改成double啦
- 3.部分答案正确![]() 
- 解决方法:根据pta的提示,针对特殊点如只输入一个1等通过添加if语句来对代码进行完善
- 4.最大范围内运行超时:代码效率问题
 因为刚刚学习了通过int(x)可以强制把x变成整数型,所以利用x=int(x)的方法来判断整除![]() 
 但是如果是在本题这种大范围内执行需要多一次操作的代码无疑是大大降低了代码的执行效率的,而且从学长那了解到这种方法还可能带来浮点误差(加红)
- 解决方法:创新无果于是利用最经典传统的方式取余是否等于0来判断是否整除
题目3:7-1 求组合数
1.本题PTA提交列表


2. 设计思路
- 1.函数声明 double fact(int x)
- 2.定义两个整数型变量m,n 定义浮点型变量result来存放结果
- 3.输入两个整数m,n
- 4.判断m与n是否相等,若是,则result=1
- 5.若不是,则调用函数进行计算result = fact(n)/(fact(m)*fact(n-m))
- 6.输出结果
 定义函数 double fact(int n) 来求n!
- 1.定义整数型变量i,浮点型变量result
- 2.赋初值:result=1 i=1
- 3.result=result*i
- 4.i++,重复步骤3直到i>n
- 5.返回result的值
3.本题调试过程碰到问题及PTA提交列表情况说明。
- 1.浮点错误
- 解决方法:像这种求n!结果的数都应该定义结果为double型而不是int型
- 2.答案错误
- 解决方法:答案应该整数输出
 ![]() 
 ![]() 
二、同学代码结对互评
1.同学互评照片。

2.我的代码、互评同学代码截图
刘艳钦同学的代码
int reverse( int number )
{
  int i=1,x,sum=0; 	       //定义整数型变量i,x,sum分别存放符号,分离出来的数字,逆序后的数
  while(number){        
    x = number%10; 	       //从个位开始分离输入的数存放在x
    sum = sum * 10 +x; 	   //把上一次分离出来的数*10然后在加上新分离出来的数组成新数
    number=number/10;            //把分离出的数从number中去掉
    } 
    sum=sum*i; 	             //把符号加到number上(此处针对负数)
    return sum;               //返回sum的值
}
林晓露同学的代码
int reverse( int number )
{  
  int i,j,k,down,sum;
  k=number;
  i=1;
  sum=0;
  while(number/10!=0){
    number=number/10;
    i++;}//计算number的位数
  for(j=i;j>0;j--){//根据number的位数循环输出逆序数
    down=k%10;
    sum=sum+down*pow(10,j);
    k=k/10;
  }
  if(sum%10==0)//当最后是0时舍去
    sum=sum/10;
  return sum;
}
3.我和同学代码不同在哪里?有哪些各自优势?你更喜欢哪种代码风格?如果同学代码有错的也请帮忙指出来哪里出问题。
- 不同点:设计思路不同:我——利用取余的方式把number从后面一个个取出数字后再依次10, 先分离出来的数10的次数便多,也就是位于新数的前面实现了逆序
 林晓露同学——利用一个数的每个数字在正序和逆序中10的总和不变来实现逆序,eg(512中5在正序中10两次,而后在逆序中10零次,2在正序中10零次而后两次)
- 在这一题上,我更喜欢我的代码风格,因为我的代码的运行效率相对会高一些而且整洁一些,但是晓露同学的代码设计思路更容易让人理解而且更有数学思想
 虽然我一开始的想法也是偏向晓露同学的设计思路,但是题目所给的主函数并没有为我们提供#include<math.h> ,于是我放弃利用这种设计思路......这也是我觉得pta很神奇的地方
三、截图本周题目集的PTA最后排名

四、本周学习总结
1.你学会了什么?
1.1 C语言哪些数据类型?

1.2 字符型数据需要注意地方?
- 1.字符常量:用单引号扩起来的一个字符,eg 'A'   
 转义字符:特殊的字符常量,都是以 ‘ \ ’开头 (代表一个字符)
 注意:所有字符都可以用转义字符表示
- 2.字符变量:用来存放字符,且只能存放一个字符
 定义的方式是char c
 赋值的方式是c='A' 或者是 c=65
 输入输出的方式是 %c
 但是字符型数据和整数型数据可以相互赋值,即字符型数据可以以字符形式输出,也可以以整数形式输出
1.3 自增自减运算符?
- 
++是自增运算符,是单目运算符,其作用是使单个变量的值增1。它有两种使用情况: 
- 
1)前置:++i,先执行i=i+1,再使用i值; 
- 
2)后置:i++,先使用i值,再执行i=i+1。 
 例如:
 j=3; k=++j;执行后, k=4,j=4。上述语句等效为:j=3; j=j+1; k=j;
 j=3; k=j++;执行后, k=3,j=4。上述语句等效为:j=3; k=j; j=j+1;
- 
--是自减运算符,是单目运算符,其作用是使单个变量的值减1。它有两种使用情况: 
- 
1)前置:--i,先执行i=i-1,再使用i值; 
- 
2)后置:i--,先使用i值,再执行i=i-1。 
 例如:
 j=3; k=--j;执行后,k=2,j=2。 上述语句等效为:j=3; j=j-1; k=j;
 j=3; k=j--;执行后,k=3,j=2。上述语句等效为:j=3; k=j ; j=j-1;
- 
注意: 
 1)自增和自减运算符,只能用于变量,不能用于常量和表达式。例如5++,--(a+b)等都是非法的。
 2)自增、自减运算符及负号运算符的结合方向是从右向左。
1.4 运算符优先级?
运算符共分为15级,1级优先级最高,15级优先级最低。
同一优先级的运算符,运算次序由结合方向所决定。(结合性:单目运算符,三目运算符和各种赋值运算符是从右至左 其他都是 从左至右)
 简单记就是:! > 算术运算符 > 关系运算符 > && > || > 赋值运算符
再详细一点,附带一个口诀。(网上找的)
括号成员第一;                //括号运算符 成员运算符. ->
全体单目第二;              //所有的单目运算符比如++、 --、 +(正)、 -(负) 、指针运算*、&
乘除余三,加减四;         //这个"余"是指取余运算即%
移位五,关系六;          //移位运算符:<< >> ,关系:> < >= <= 等
等于(与)不等排第七;      //即== 和!=
位与异或和位或;   "三分天下"八九十;     //这几个都是位运算: 位与(&)异或(^)位或(|) 
逻辑或跟与;              //逻辑运算符:|| 和 &&
十二和十一;           //注意顺序:优先级(||) 底于 优先级(&&) 
条件高于赋值,                //三目运算符优先级排到13 位只比赋值运算符和","高
逗号运算级最低!        //逗号运算符优先级最低
1.5 C语言哪些表达式?
表达式:
- 1 算数表达式:
 单目:+, -, ++, --。
 双目:+,-,*,/,%。
- 2 赋值表达式:
 简单赋值:=
 复合赋值:+=,-=,*=,,/=%=,!=。
- 3 关系表达式:>,>=,<,<=,!=。
- 4 逻辑表达式:!,&&,||
- 5 条件表达式:
 exp1? exp2:exp3
 例:
if(x>0)
y=x+2;      =====    y=(x>0)?x+2:x*x
else
y=x*x;
- 
6.逗号表达式:, 
 表达式1,表达式2,表达式3........表达式N
 先计算表达式1,然后计算表达式2.。。。。并将表达式n的值作为逗号表达式的值。
 Int a,b,c;
 (a=2),(b=3),(c=a+b);
 逗号运算符的优先权最低,左结合
- 
注意:(1)可以看到一个表达式也可以没有操作符,例如“4”这种形式就是最简单的表达式形式,即最简单的表达式只有一个常量或一个变量名称而没有操作符。 
 (2)函数调用也是表达式
- 
课堂派 
 ![]() 
 由y=012可知y是个八进制,换成十进制=10
 由后置先使用x值可知,表达式就等于10
1.6 其他内容?
- 1.数字字符和数字转换
 number=ch-'0'
 ch=number+'0'
- 2.大小写转换
 小写转大写:ch-'a'+'A'
 大写转小写:ch+‘A'-'a'
- 3.强制类型转换
 double n=3.14
 x=int(x)=3
- 4.自动类型转换
 非赋值运算:水平方向,垂直方向,类型小的转类型大的
 赋值运算:变量= 表达式
 将赋值运算符右侧表达式的类型,自动转换成赋值号左侧变量的类型
- 注意:逻辑运算符注意P138
 在逻辑表达式的求解中,并不是所有的逻辑运算符都执行,只有在必须执行下个逻辑运算符才能求出表达式的值时,才执行下一个运算符则执行语句:
 eg:
 t均为int型变量,
 设x、y
 x=y=3;t=++xll ++y;
 y的值为一3
- 
位运算应用 
 2的整数次方的数特点: 转成2进制后?
 只有一个尾部1其他都是0.即1000
 只有1个1的二进制数-1后,怎样形式? 0111
 再和自己本身进行&运算,结果?可判断该数为2的整数次方
 int pow_2(int n){
 if((n1)&n)==0) return 1;
 else return 0;
2.本周的内容,你还不会什么?
- 1.对位运算还很不熟悉,如位逻辑运算,移位运算,复合位赋值运算都还不太熟悉,也不会它具体的灵活运用,除了了解到老师上课举例的找2的整数次方的数
- 2.对异或还有二进制,八进制,十六进制的转换的都不熟练
- 3.对自动类型转换也不熟悉
3.循环结构考试总结
- 1.哪题做错了,怎么改?
 最后一题的设计思路过于复杂导致部分正确和运行超时
 ![]() 
 ![]() 
 但是现在还是没有完全正确还在调试和修改的阶段.....
- 2.考试结果满意么,怎么改进?
- 1.不满意
- 2.设计思路还是不够清晰和明确,特别是在时间有限的情况下,经过调试还是会发现总是出现一些常见的小错误还是一直在犯
- 改进:
 1)在今后的代码中更要有时间观念,就是要在平时就训练自己写代码的效率而不是只追求完成
 2)常见的错误在博客上总结后要经常阅读来提醒自己
 3)老话:practice makes perfect~~ 依然是继续不停敲代码!敲代码!敲代码!
 4)对于最后一题这种比较灵活复杂的题也要多看多思考多练习
- 3.其他总结。
 1)我觉得我预习效率太低了,做预习作业的情况不太理想
 2)作业效率也很低,虽然现在都已经开学半学期也打了挺多代码,但是总是会被几题代码困住好久动弹不得,导致每天都被作业追着跑
 3)这周的学习内容太多了,有点不好消化,八进制十六进制和对位运算还不够理解
 
                    
                




















 
                
            
         浙公网安备 33010602011771号
浙公网安备 33010602011771号