一、PTA实验作业
题目1:7-3 出生年
1. 本题PTA提交列表(要提交列表,不是结果)
2. 设计思路
- 1.定义year代表出生的年份,repeat代表循环操作,max代表某个数最多重复次数
- 2.定义 i, k, j, m; //代表数值下标和循环次数
- 3.输入year和repeat
- 4.定义数值a[4]b[4]来分别存放year中的数字和对应数字在year中的出现次数
- 5.遍历数组a[4]来统计数字的出现次数并把对应值存放在b[4]
- 6.遍历数组b[4]来寻找最大值
- 7.发现n个数字不同可以转化成 max+repeat=5 的条件
- 8.若max == (5 - repeat) 输出对应岁数和年份,若不是,则继续下一轮循环
3.代码截图
4.本题调试过程碰到问题及PTA提交列表情况说明。
- 1.第一次提交发现了三个错误
根据第0个测试点进行第一个输入测试: 发现正确,于是输入第2次数据尝试发现结果不对
于是进行调试,通过监测变量发现b的值会累加
明白了问题出在:一次循环后应该把b的值重新清空
- 2.修改后得到了第二次的提交列表
根据第二个测试点提示的最大边界发现输入3000 4 输出0 3000,通过调试发现发现当year=3001时无法进入循环体,发现了循环条件出错,不应该用for(i=year;i<=3000;i++)否则如果输入3000 4.结果应该是3012,而我的代码的i是不会循环到3012。于是把i<=3000去掉
- 3.修改后等到了最后一个提交列表
于是进行需要补零情况的测试
发现结果是正确的,多次调试无果后,后遂无问津者。
题目2:7-6 阅览室
1. 本题PTA提交列表(要提交列表,不是结果)
2. 设计思路
-
1.定义book[i][0]用来保存第i本书的'S'或者'E',book[i][1]用来保存'S'时候的时间,count表示借书次数
-
2.定义book[1001][2], i, j, n, num, hour, minute, count, average, sum;
-
3.定义字符ch来存放输入的S或者E
-
4.输入n的值
-
5.for (i = 0; i < n; i++) {
count = 0; //清空记录
sum = 0; -
6.for (j = 0; j < 1001; j++) {
book[j][0] = 0; //清除一下第i天的S和E
} -
7.读取整行数据,num表示第几本书,ch表示'S'或'E',hour和minute表示时间,当num!=0的时候继续循环
-
8.if (ch == 'E') { 如果碰到整行数据有'E',表示还书来了
-
9.if (book[num][0] == 'S') { //book[num][0] == 'S'表示第num本书保存有借书记录
sum += 60 * hour + minute - book[num][1];//sum进行累加,还书时的时间减去借书时保存的时间就是借阅时间
count++;
book[num][0] = 0;//为避免出现'S''E''E'的异常,把S换为0
}
}
//如果碰到整行数据有'S',表示借书,此时记录好S和借书时间
else {
book[num][0] = 'S';
book[num][1] = hour * 60 + minute;
}
} -
10.若一天没人借书还书或出错,输出0 0
else { 计算平均时间,因为平均数是整数,所以加0.5,成浮点数,赋值给average自动取整数,并输出 }
3.代码截图
4.本题调试过程碰到问题及PTA提交列表情况说明。
- 1.一开始拿到这题的时候是无从下手的,因为数据比较多,又有整数又有字符,思路受阻
解决方法:在重新整理思路并联系现在所学的数组去考虑和分析后发现可以用二维数组下标i表示书号,book[i][0]表示借还,book[i][1]表示时间eg.book[5][0]存第五本书的s,book[5][1]存借书的时间。再碰到一串数据的时候,判断book[i][0]是否为's',再用现在的时间减book[i][1]的时间,得到借阅时间
总之就是就是碰到S的情况就把时间记录下来,碰到E的情况就看以前的book[i][0]里有没有保存S,保存了S就是有效的借阅,这时用读取的时间减去原来保存的时间。 - 2.忘记考虑到SEE的情况
解决方法:应该在count++后面加一句book[num][0]=0,把第一个S换掉
题目3:7-9 判断上三角矩阵
1. 本题PTA提交列表(要提交列表,不是结果)
2. 设计思路
- 1.定义整数型变量repeat存放重复操作次数,定义flag来存放情况,i代表行,j代表列,定义整数型数组a[10][10]
- 2.输入repeat的值
- 3.进行repeat次以下操作
- 4.flag=1
- 5.输入n的值
- 6.利用两个循环输入给数组a[10][10]赋值
- 7.遍历下三角的数,判断是否有为0的数
若有,输出NO,并使flag=0; - 8.if (flag == 1) 输出YES
3.代码截图
4.本题调试过程碰到问题及PTA提交列表情况说明。
- 1.按照样例输入后发现得到了正确的结果,发现并没有错误,但是提交后发现答案错误,分析后发现a[i][j]不为0后要跳出整个嵌套的for循环,否则循环还会继续,导致不停的输出No
也就是下三角有几个数不为0,就会输出几个No. 样例没有这种情况,但不表示能通过其他数据。也就是我们要尽量输入多种数据去检测。 - 2.记得YES和NO的输出要换行,原因:有多组数据要输出结果
- 3.检测每组数据后都要把flag重置为1. 小体会:像这种进行多次循环操作的记得要清空上一轮循环的数据
二、截图本周题目集的PTA最后排名。
三、同学代码结对互评
1.我的代码(刘艳钦同学左) 互评同学(林晓露同学右)代码截图
2.我和同学代码不同在哪里?有哪些各自优势?你更喜欢哪种代码风格?如果同学代码有错的也请帮忙指出来哪里出问题。
我跟林晓露同学的代码思路还是有所差异的.
- 我的思路是:在输入的时候就直接改变数组的下标来改变它存储的位置。
- 而林晓露同学的思路是按顺序输入数据存储,再利用循环来改变所在数据所在的位置。
- 我的思路优势在于:代码的执行效率会更高一些,也更简洁一点点。
- 林晓露同学优势是:更好理解一些,而且比较不容出错,更容易检查出错误。
但是可以看得出的是:林晓露同学这段代码并没有完全正确,特别是对m>=n这种情况的考虑,应该是对这种情况产生了一定的误解,m>=n,并不是就按原来的顺序输出,而是当m=kn(其中k为整数)的时候才是原顺序输出,所以可以参照我的做法使m=m-xn且m>0来使m重新变成小于n的数,再归结到m<n的做法里。 - 我更喜欢我自己的代码风格,因为我会更偏向于自己的这种直接一点点的思路会更简洁一点点,但是林晓露同学的代码是非常容易让人理解也是相当优秀的。
四、本周学习总结(3分)
1.你学会了什么?
1.1 C中如何存储字符串?
c语言将字符串作为一个特殊的一维字符数组来处理。
1.字符串的存储一数组初始化
字符串可以存放在一维字符数组中。例如:
staticchar s [6]= I'H','a','p','p','y',' ' ;
数组s 中就存放了字符串"Happy"。
字符数组的初始化还可以使用字符串常量,上述初始化等价于:
static char s [6]= {"Happy" };
或
static char s[6]=''Happy'' ;
补充:有效字符和字符串的有效长度
字符数组表示字符串可以有两种方式:
(1)char str1[ ]="aaaaa";
此种方法声明的字符串本质上是字符数组,在赋值前数组大小还没有确定。在赋值后编译器会自动在“aaaaa”后加上’ ‘以表示字符串的结尾,此时str1中存储的数是“aaaaa ”,数组的大小为6。而此时该字符串的有效字符个数为5,所以字符串的有效长度: 有效字符的个数+1 (' ')
(2)char str2[ 5]=“bbbbb”;
此种方法声明的字符串本质上是字符数组,在声明部分已经定义了数组的大小为5,在赋值“bbbb”后str2已没有空间来存储‘ ‘,str2存储的数据是“bbbbb”,数组的大小为5;而字符串的有效字符个数也为5,此时字符串有效长度=有效字符个数
- 但是若使用strlen()函数来测量字符串的长度,它返回的的是从基地址开始到’ ‘结束包含的字符的个数(不包括’ ‘),所以字符串有效长度=有效字符个数
1.2 字符串的结束标志是什么,为什么要结束标志?
字符串的结束标志: 字符" '
注意:空字符: 转义字符,不是空格字符
将字符申存人一维字符数组后,对字符串的操作就是对该字符数组的操作。但是,它和普通字符数组的操作又有所不同。以遍历数组或字符串为例,由于普通数
组中数组元素的个数是确定的,一般用下标控制循环; 而字符串并没有显式地给出有效字符的个数,只规定在字符串结束符' 之前的字符都是字符串的有效字符,一般通过比较数组元素的值是否等于 ’ ' 来决定是否结束循环,即用结束符’0来控制循环。
1.3 字符串输入有哪几种方法? 重要~
(1)scanf("%s",str)
输入参数:字符数组名,不加地址符
遇回车或空格输入结束
并自动将输入的一串字符和"0' 送入数组中
2 )gets(str)
遇回车输入结束,自动将输入的一串字符和"10^ 送入数组中
补充:字符串的输出
char str[80];
for (i = O; str[i] !=*O'; i++)
putchar (str[i]);
输出参数可以是字符数组名或字符串常量
(3 )printf ("%s",str)
printf ("%s","hello");
组名或字符串常量,输出遇"O' 结束
(4) puts (str)
puts ("hello");
输出字符串后自动换行(注意)
1.4 数字字符怎么转整数?
char number[i] //定义数字字符数组
int i,j=0,k=1,n; //定义i为循环次数,j来存放转换后的整数,n用来统计该数组中有几个数字字符
for(i=0;number[i];i++) //遍历数字字符数组
number[i]-='0'; //把数字字符转换成整数后一一对应放在num[i]数组中
for(i=n;i>=0;i--)
{
j+=number[i]*k; //将num[i]中的数一个个提出来后乘以k使对应成为个位十位百位组成新的整数
k*=10;
}
printf("%d",j); //输出整数
1.5 16进制、二进制字符串如何转10进制?
int count=1;
for (int i=length-1;i>=0;i--) //遍历数组
{
if ((revstr[i]>='0') && (revstr[i]<='9'))
num[i]=revstr[i]-48; //字符0的ASCII值为48
else if ((revstr[i]>='a') && (revstr[i]<='f'))
num[i]=revstr[i]-'a'+10;
else if ((revstr[i]>='A') && (revstr[i]<='F'))
num[i]=revstr[i]-'A'+10;
else
num[i]=0;
result=result+num[i]*count;
count=count*16;//十六进制 (如果是二进制就在这里乘以2)
}
2.本周的内容,你还不会什么?
- 1.从这周的数组开始,代码难度和复杂程度明显上升了一个阶梯,虽然已经快要结束数组的学习,但是对二维数组的灵活运用和存储位置等理解还是不够,特别是很重要的几种排序方法,我还只是看得懂会理解,如果要自己亲手写肯定会出现一些错误,所以我要找时间把这几个排序的方法独立地写一遍
- 2.课堂派的错题:
3.期中考试小结
3.1 你认为为什么没考好?
- 1.对题型不熟悉导致没把握好时间,没有合理分配时间,在选择题上花费了较多的时间,而且得分率不好,可以看出我对很多基础概念eg(static,auto,extern具体的作用范围啥的)都很模棱两可而平时却没有去复习去完全地掌握这些概念,对课堂派预习作业错题也没有全部掌握,这是我值得认真反思的地方
- 2.在程序分析题中,因为太着急和平时代码阅读量不够多,导致考试的时候对代码的理解是一知半解的,导致答案总是有一点点小出入造成失分严重
- 3.程序编写中,因为卡在第一题的产生随机数而花费了很多没必要的时间,这是值得反思的考试习惯,对这种不熟练不会的东西我们要学会适当地舍弃而不是白白浪费太多的时间,最重要的是整体编程题的思路正确,对这种小节实在没有思路要学会灵活跳过,然后在代码旁边加上一定的注释,保证最小程度的失分,还有就是要提高代码的整齐度,字要适当大小,不要像上次一样字太大导致到处找空位造成卷面分丢失,先简单地打一份草稿而不是全部写好抄写过去的浪费时间的做法!!!
3.2 罗列错题。
填空题
1.在计算机中的数值数据表示的是(二,八,十,十六)进制数
拓展:在计算机中数据是以(二进制)形式存储
2.下列关于字节和数的运算的叙述中,正确的一项是(C)
A 字节通常用英文单词“bit”来表示,有时也可以写做“b”(x)解析:Byte代表字节,可以写成B 注意:大写B表示Byte,小写b表示bit
B 目前广泛使用的Pentium 机其字长为16 个字节(x) 解析:Pentum机字长通常为 32位
C 计算机中不是所有数的运算均为补码计算
D 计算机的字长并不一定是Byte的整数倍(x) 解析:一定是整数倍,因为Byte是计算机中最小存储单位
3.x=y==5(正确)
理解:==是个逻辑运算符,用来判断其左右两边是否相等,若相等返回1,不等返0
所以当y=5时,x=1
y!=5,x=0
4.第九题选择中的反思:注意:非与或的先后顺序
5.static
static变量是指静态的变量,不管是在全局还是局部声明的static变量都存放于程序的全局变量区域,所以它的生命周期是从程序开始到程序结束。但是static变量的作用域并不等同于它的生存周期,它的作用域决定于它被定义的位置。可以认为static变量的作用域<=生存周期。
中兴通讯2012校招笔试题的一道问答题:
**1. static全局变量与普通的全局变量有什么区别 ? **
全局变量(外部变量)的说明之前再冠以static 就构成了静态的全局变量。
全局变量本身就是静态存储方式, 静态全局变量当然也是静态存储方式。 这两者在存储方式上并无不同。
这两者的区别在于非静态全局变量的作用域是整个源程序, 当一个源程序由多个源文件组成时,非静态的全局变量在各个源文件中都是有效的。 而静态全局变量则限制了其作用>域, 即只在定义该变量的源文件内有效, 在同一源程序的其它源文件中不能使用它。由于静态全局变量的作用域局限于一个源文件内,只能为该源文件内的函数公用,因此可以避免>在其它源文件中引起错误。
static全局变量只初使化一次,防止在其他文件单元中被引用;
**2. static局部变量和普通局部变量有什么区别 ? **
把局部变量改变为静态变量后是改变了它的存储方式即改变了它的生存期。把全局变量改变为静态变量后是改变了它的作用域,限制了它的使用范围。
static局部变量只被初始化一次,下一次依据上一次结果值;
**3. static函数与普通函数有什么区别? **
static函数与普通函数作用域不同,仅在本文件。只在当前源文件中使用的函数应该说明为内部函数(static修饰的函数),内部函数应该在当前源文件中说明和定义。对于可在当前源>文件以外使用的函数,应该在一个头文件中说明,要使用这些函数的源文件要包含这个头文件.
static函数在内存中只有一份,普通函数在每个被调用中维持一份拷贝>>
exten###
extern是计算机语言中的一个关键字,可置于变量或者函数前,以表示变量或者函数的定义在别的文件中。提示编译器遇到此变量或函数时,在其它模块中寻找其定义,另外extern也>可用来进行链接指定。
extern用于变量的用法:
extern int a;//声明一个全局变量a
int a; //定义一个全局变量a
extern int a =0 ;//定义一个全局变量a 并给初值。一旦给予赋值,一定是定义,定义才会分配存储空间。
int a =0;//定义一个全局变量a,并给初值,
声明之后你不能直接使用这个变量,需要定义之后才能使用。
第四个等于第三个,都是定义一个可以被外部使用的全局变量,并给初值。
糊涂了吧,他们看上去可真像。但是定义只能出现在一处。也就是说,不管是int a;还是int a=0;都只能出现一次,而那个extern int a可以出现很多次。
当你要引用一个全局变量的时候,你就要声明extern int a;这时候extern不能省略,因为省略了,就变成int a;这是一个定义,不是声明。>
register###
当声明对象有自动生存周期时,可以使用register修饰符。因此,register也只能用在函数内的声明中。
此关键字告诉编译器:此对象的存取应该尽量快,最好存储在CPU的寄存器中。然而,编译器不见得会这么做。
另外要注意的是,当一个对象声明为register,就不可使用地址运算符&了,因为它有可能被放到寄存器中。>
auto###
这个关键字用于声明变量的生存期为自动,即将不在任何类、结构、枚举、联合和函数中定义的变量视为全局变量,而在函数中定义的变量视为局部变量。这个关键字不怎么多写,因为所有的变量默认就是auto
总结##
C语言中提供了存储说明符auto,register,extern,static说明的四种存储类别。四种存储类别说明符有两种存储期:自动存储期和静态存储期。其中auto和register对应自动存储期。具有自动存储期的变量在进入声明该变量的程序块是被建立,它在该程序块活动时存在,退出该程序块时撤销。
在函数内部定义的变量成为局部变量。在某些C语言教材中,局部变量称为自动变量,这就与使用可选关键字a u t o定义局部变量这一作法保持一致。局部变量仅由其被定义的模块内部的语句所访问。换言之,局部变量在自己的代码模块之外是不可知的。切记:模块以左花
括号开始,以右花括号结束。
对于局部变量,要了解的最重要的东西是:它们仅存在于被定义的当前执行代码块中,即局部变量在进入模块时生成,在退出模块时消亡。
4.
- 在函数中可以使用多条return语可来这回一个结果
- 若形参与实参类型不一致时,以形参类型为准
- 当函数值的类型与返回值的类型不一致时,以函数值的类型为准
- 定义数时,形参的类型说明不可放在函数体内
- x=-1 while(!x) 则不执行,因为c语言中非0即真
分析程序的运行结果:
#include<stdio.h>
int main(void)
int i;
if((i= n/10) != 0)
convert(i);
putchar(n%10 +'0' );
int main () {
int number;
scanf ("%d",&number)
if (number<0)
putchar('-');
number=-number ;
}
convert(number);
}
从键盘输入:
5647
输出结果:
我的答案是:‘7465’
正确答案是:7465
对putchar(n%10+'0') 的理解:
由于0-9是一个整数值来的,想在屏幕上输出的话要转换为ascii码。
'0'为0的ascii码,加上0-9就是为'0'-'9'的ascii码。
这个句子的结果是把n%10的结果用ascii码输出在屏幕上
错误分析:这题的确是输出字符数字7465,但是字符数字和数字我们是看不出来的,平时课本上加‘’是为了便于我们区别而已,实际上输出看上去是无差别的。
阅读程序填空
- 1/pow(i,2) -> 1.0/pow(i,2) 又错误在整数/整数=整数的易错点中了
- ‘a'<=ch&&ch<='z'||‘A'<=ch&&ch<='z' ->(‘a'<=ch&&ch<='z')||(‘A'<=ch&&ch<='z')
改错题
while(r==0)->while(r!=0)
分析:没找出来的原因还是因为对该题程序的逻辑不够清晰,要先代具体数据进去先理清楚思路
技巧:先编译错误+逻辑错误
编程题
编程题主要是在第一题考虑如何产生随机数上花费了过多的时间导致了后面的程序没来的及更好完成
产生随机数的方法:
include <stdio.h>
srand (time(NULL));
x=ran()%9000+1000; //[1000,9999]
注意:取余的特点: x%m<[0,m]
3.3 下半学期要怎么调整C的学习?
- 1.从下学期开始,对上课老师所讲的概念和易错点要及时地用笔记写下来,因为我的记忆力比想象中要差一些,于是慢慢从理解变成一知半解的情况,我要杜绝度对概念模棱两可的情况
- 2.提高对c语言学习的效率,还有侧重点也要有一小些改变,比如我在上学期花费了大部分的c语言学习时间都是在打pta的题目,而对一些概念只是课前预习来完成课堂派的预习作业,而上课后并没有进行概念的复习,直奔打代码,而且会在一提代码上纠结一整天的时间,其实代码可以纠结一会儿时间印象会更深刻,但是如果花费太多在一题自己根本就看不出来的错误就得不偿失了,应该在实在不会的情况下及时向他人询问,然后及时总结,这种方法效率会更高而且印象也不会不深刻。
- 3.整理错题!整理错题!整理错题! 因为考试的题目其实大部分我们平时有涉及到,但是往往考试中出错的是我们平时做题出错的,所以对于本来我就做错的题来说它就是我的易错点,至少要反复看上几次才会有印象才会避免继续掉进那个大坑